blob: 7c2fe896a484b887e049f73d774f63c5c02266bc [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package security
import (
"crypto/ecdsa"
"crypto/rand"
"crypto/x509"
"math/big"
"v.io/v23/verror"
)
// NewECDSAPublicKey creates a PublicKey object that uses the ECDSA algorithm and the provided ECDSA public key.
func NewECDSAPublicKey(key *ecdsa.PublicKey) PublicKey {
return newECDSAPublicKeyImpl(key)
}
func newGoStdlibPublicKey(key *ecdsa.PublicKey) PublicKey {
return &ecdsaPublicKey{key}
}
type ecdsaPublicKey struct {
key *ecdsa.PublicKey
}
func (pk *ecdsaPublicKey) MarshalBinary() ([]byte, error) { return x509.MarshalPKIXPublicKey(pk.key) }
func (pk *ecdsaPublicKey) String() string { return publicKeyString(pk) }
func (pk *ecdsaPublicKey) verify(digest []byte, sig *Signature) bool {
var r, s big.Int
return ecdsa.Verify(pk.key, digest, r.SetBytes(sig.R), s.SetBytes(sig.S))
}
func (pk *ecdsaPublicKey) hash() Hash {
if nbits := pk.key.Curve.Params().BitSize; nbits <= 160 {
return SHA1Hash
} else if nbits <= 256 {
return SHA256Hash
} else if nbits <= 384 {
return SHA384Hash
} else {
return SHA512Hash
}
}
// NewInMemoryECDSASigner creates a Signer that uses the provided ECDSA private
// key to sign messages. This private key is kept in the clear in the memory
// of the running process.
func NewInMemoryECDSASigner(key *ecdsa.PrivateKey) Signer {
// TODO(ashankar): Change this function to return an error
// and not panic.
signer, err := newInMemoryECDSASignerImpl(key)
if err != nil {
panic(err)
}
return signer
}
func newGoStdlibSigner(key *ecdsa.PrivateKey) (Signer, error) {
sign := func(data []byte) (r, s *big.Int, err error) {
return ecdsa.Sign(rand.Reader, key, data)
}
return &ecdsaSigner{sign: sign, pubkey: newGoStdlibPublicKey(&key.PublicKey)}, nil
}
// NewECDSASigner creates a Signer that uses the provided function to sign
// messages.
func NewECDSASigner(key *ecdsa.PublicKey, sign func(data []byte) (r, s *big.Int, err error)) Signer {
return &ecdsaSigner{sign: sign, pubkey: NewECDSAPublicKey(key)}
}
type ecdsaSigner struct {
sign func(data []byte) (r, s *big.Int, err error)
pubkey PublicKey
impl interface{} // Object to hold on to for garbage collection
}
func (c *ecdsaSigner) Sign(purpose, message []byte) (Signature, error) {
hash := c.pubkey.hash()
if message = messageDigest(hash, purpose, message, c.pubkey); message == nil {
return Signature{}, verror.New(errSignCantHash, nil, hash)
}
r, s, err := c.sign(message)
if err != nil {
return Signature{}, err
}
return Signature{
Purpose: purpose,
Hash: hash,
R: r.Bytes(),
S: s.Bytes(),
}, nil
}
func (c *ecdsaSigner) PublicKey() PublicKey {
return c.pubkey
}