"crypto/elliptic"
"crypto/internal/randutil"
"crypto/sha512"
- "encoding/asn1"
"errors"
"io"
"math/big"
+
+ "golang.org/x/crypto/cryptobyte"
+ "golang.org/x/crypto/cryptobyte/asn1"
)
import (
boring unsafe.Pointer
}
+// Equal reports whether pub and x have the same value.
+//
+// Two keys are only considered to have the same value if they have the same Curve value.
+// Note that for example elliptic.P256() and elliptic.P256().Params() are different
+// values, as the latter is a generic not constant time implementation.
+func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
+ xx, ok := x.(*PublicKey)
+ if !ok {
+ return false
+ }
+ return pub.X.Cmp(xx.X) == 0 && pub.Y.Cmp(xx.Y) == 0 &&
+ // Standard library Curve implementations are singletons, so this check
+ // will work for those. Other Curves might be equivalent even if not
+ // singletons, but there is no definitive way to check for that, and
+ // better to err on the side of safety.
+ pub.Curve == xx.Curve
+}
+
// PrivateKey represents an ECDSA private key.
type PrivateKey struct {
PublicKey
boring unsafe.Pointer
}
-type ecdsaSignature struct {
- R, S *big.Int
-}
-
// Public returns the public key corresponding to priv.
func (priv *PrivateKey) Public() crypto.PublicKey {
return &priv.PublicKey
return nil, err
}
- return asn1.Marshal(ecdsaSignature{r, s})
+ var b cryptobyte.Builder
+ b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
+ b.AddASN1BigInt(r)
+ b.AddASN1BigInt(s)
+ })
+ return b.Bytes()
}
var one = new(big.Int).SetInt64(1)
// Sign signs a hash (which should be the result of hashing a larger message)
// using the private key, priv. If the hash is longer than the bit-length of the
-// private key's curve order, the hash will be truncated to that length. It
+// private key's curve order, the hash will be truncated to that length. It
// returns the signature as a pair of integers. The security of the private key
// depends on the entropy of rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
return
}
+// SignASN1 signs a hash (which should be the result of hashing a larger message)
+// using the private key, priv. If the hash is longer than the bit-length of the
+// private key's curve order, the hash will be truncated to that length. It
+// returns the ASN.1 encoded signature. The security of the private key
+// depends on the entropy of rand.
+func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
+ return priv.Sign(rand, hash, nil)
+}
+
// Verify verifies the signature in r, s of hash using the public key, pub. Its
// return value records whether the signature is valid.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
return x.Cmp(r) == 0
}
+// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the
+// public key, pub. Its return value records whether the signature is valid.
+func VerifyASN1(pub *PublicKey, hash, sig []byte) bool {
+ var (
+ r, s = &big.Int{}, &big.Int{}
+ inner cryptobyte.String
+ )
+ input := cryptobyte.String(sig)
+ if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
+ !input.Empty() ||
+ !inner.ReadASN1Integer(r) ||
+ !inner.ReadASN1Integer(s) ||
+ !inner.Empty() {
+ return false
+ }
+ return Verify(pub, hash, r, s)
+}
+
type zr struct {
io.Reader
}