"crypto/elliptic"
"crypto/internal/randutil"
"crypto/sha512"
- "encoding/asn1"
"errors"
"io"
"math/big"
+
+ "golang.org/x/crypto/cryptobyte"
+ "golang.org/x/crypto/cryptobyte/asn1"
)
// A invertible implements fast inverse mod Curve.Params().N
D *big.Int
}
-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
}
testSignAndVerify(t, elliptic.P521(), "p521")
}
+func testSignAndVerifyASN1(t *testing.T, c elliptic.Curve, tag string) {
+ priv, _ := GenerateKey(c, rand.Reader)
+
+ hashed := []byte("testing")
+ sig, err := SignASN1(rand.Reader, priv, hashed)
+ if err != nil {
+ t.Errorf("%s: error signing: %s", tag, err)
+ return
+ }
+
+ if !VerifyASN1(&priv.PublicKey, hashed, sig) {
+ t.Errorf("%s: VerifyASN1 failed", tag)
+ }
+
+ hashed[0] ^= 0xff
+ if VerifyASN1(&priv.PublicKey, hashed, sig) {
+ t.Errorf("%s: VerifyASN1 always works!", tag)
+ }
+}
+
+func TestSignAndVerifyASN1(t *testing.T) {
+ testSignAndVerifyASN1(t, elliptic.P224(), "p224")
+ if testing.Short() {
+ return
+ }
+ testSignAndVerifyASN1(t, elliptic.P256(), "p256")
+ testSignAndVerifyASN1(t, elliptic.P384(), "p384")
+ testSignAndVerifyASN1(t, elliptic.P521(), "p521")
+}
+
func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
priv, _ := GenerateKey(c, rand.Reader)
msg := "hello, world"
hash := sha256.Sum256([]byte(msg))
- r, s, err := ecdsa.Sign(rand.Reader, privateKey, hash[:])
+ sig, err := ecdsa.SignASN1(rand.Reader, privateKey, hash[:])
if err != nil {
panic(err)
}
- fmt.Printf("signature: (0x%x, 0x%x)\n", r, s)
+ fmt.Printf("signature: %x\n", sig)
- valid := ecdsa.Verify(&privateKey.PublicKey, hash[:], r, s)
+ valid := ecdsa.VerifyASN1(&privateKey.PublicKey, hash[:], sig)
fmt.Println("signature verified:", valid)
}
// Mathematical crypto: dependencies on fmt (L4) and math/big.
// We could avoid some of the fmt, but math/big imports fmt anyway.
- "crypto/dsa": {"L4", "CRYPTO", "math/big"},
- "crypto/ecdsa": {"L4", "CRYPTO", "crypto/elliptic", "math/big", "encoding/asn1"},
+ "crypto/dsa": {"L4", "CRYPTO", "math/big"},
+ "crypto/ecdsa": {
+ "L4", "CRYPTO", "crypto/elliptic", "math/big",
+ "golang.org/x/crypto/cryptobyte", "golang.org/x/crypto/cryptobyte/asn1",
+ },
"crypto/elliptic": {"L4", "CRYPTO", "math/big"},
"crypto/rsa": {"L4", "CRYPTO", "crypto/rand", "math/big"},