aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2020-04-30 23:52:48 -0400
committerFilippo Valsorda <filippo@golang.org>2020-05-05 18:05:10 +0000
commita8e83d51a0cc709c836fe8836b10155342aa2ac4 (patch)
tree576d47ca61f6a69a85f6a27fcb5d3ff425f0893e
parenta6c6e59655e2599bd6dabce51a3a68accff433f8 (diff)
downloadgo-a8e83d51a0cc709c836fe8836b10155342aa2ac4.tar.gz
go-a8e83d51a0cc709c836fe8836b10155342aa2ac4.zip
crypto/rsa,crypto/ecdsa,crypto/ed25519: implement PrivateKey.Equal
Fixes #38190 Change-Id: I10766068ee18974e81b3bd78ee0b4d83cc9d1a8c Reviewed-on: https://go-review.googlesource.com/c/go/+/231417 Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Katie Hockman <katie@golang.org>
-rw-r--r--src/crypto/ecdsa/ecdsa.go14
-rw-r--r--src/crypto/ecdsa/equal_test.go17
-rw-r--r--src/crypto/ed25519/ed25519.go12
-rw-r--r--src/crypto/ed25519/ed25519_test.go12
-rw-r--r--src/crypto/rsa/equal_test.go17
-rw-r--r--src/crypto/rsa/rsa.go24
6 files changed, 85 insertions, 11 deletions
diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go
index 786b8a9884..ccce873859 100644
--- a/src/crypto/ecdsa/ecdsa.go
+++ b/src/crypto/ecdsa/ecdsa.go
@@ -62,6 +62,9 @@ type PublicKey struct {
X, Y *big.Int
}
+// Any methods implemented on PublicKey might need to also be implemented on
+// PrivateKey, as the latter embeds the former and will expose its methods.
+
// 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.
@@ -91,6 +94,17 @@ func (priv *PrivateKey) Public() crypto.PublicKey {
return &priv.PublicKey
}
+// Equal reports whether priv and x have the same value.
+//
+// See PublicKey.Equal for details on how Curve is compared.
+func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
+ xx, ok := x.(*PrivateKey)
+ if !ok {
+ return false
+ }
+ return priv.PublicKey.Equal(&xx.PublicKey) && priv.D.Cmp(xx.D) == 0
+}
+
// Sign signs digest with priv, reading randomness from rand. The opts argument
// is not currently used but, in keeping with the crypto.Signer interface,
// should be the hash function used to digest the message.
diff --git a/src/crypto/ecdsa/equal_test.go b/src/crypto/ecdsa/equal_test.go
index 9b507dd4c2..53ac8504c2 100644
--- a/src/crypto/ecdsa/equal_test.go
+++ b/src/crypto/ecdsa/equal_test.go
@@ -23,23 +23,32 @@ func testEqual(t *testing.T, c elliptic.Curve) {
if !public.Equal(crypto.Signer(private).Public().(*ecdsa.PublicKey)) {
t.Errorf("private.Public() is not Equal to public: %q", public)
}
+ if !private.Equal(private) {
+ t.Errorf("private key is not equal to itself: %v", private)
+ }
- enc, err := x509.MarshalPKIXPublicKey(public)
+ enc, err := x509.MarshalPKCS8PrivateKey(private)
if err != nil {
t.Fatal(err)
}
- decoded, err := x509.ParsePKIXPublicKey(enc)
+ decoded, err := x509.ParsePKCS8PrivateKey(enc)
if err != nil {
t.Fatal(err)
}
- if !public.Equal(decoded) {
+ if !public.Equal(decoded.(crypto.Signer).Public()) {
t.Errorf("public key is not equal to itself after decoding: %v", public)
}
+ if !private.Equal(decoded) {
+ t.Errorf("private key is not equal to itself after decoding: %v", private)
+ }
other, _ := ecdsa.GenerateKey(c, rand.Reader)
- if public.Equal(other) {
+ if public.Equal(other.Public()) {
t.Errorf("different public keys are Equal")
}
+ if private.Equal(other) {
+ t.Errorf("different private keys are Equal")
+ }
// Ensure that keys with the same coordinates but on different curves
// aren't considered Equal.
diff --git a/src/crypto/ed25519/ed25519.go b/src/crypto/ed25519/ed25519.go
index 748c039dce..5766970f82 100644
--- a/src/crypto/ed25519/ed25519.go
+++ b/src/crypto/ed25519/ed25519.go
@@ -40,6 +40,9 @@ const (
// PublicKey is the type of Ed25519 public keys.
type PublicKey []byte
+// Any methods implemented on PublicKey might need to also be implemented on
+// PrivateKey, as the latter embeds the former and will expose its methods.
+
// Equal reports whether pub and x have the same value.
func (pub PublicKey) Equal(x crypto.PublicKey) bool {
xx, ok := x.(PublicKey)
@@ -59,6 +62,15 @@ func (priv PrivateKey) Public() crypto.PublicKey {
return PublicKey(publicKey)
}
+// Equal reports whether priv and x have the same value.
+func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
+ xx, ok := x.(PrivateKey)
+ if !ok {
+ return false
+ }
+ return bytes.Equal(priv, xx)
+}
+
// Seed returns the private key seed corresponding to priv. It is provided for
// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
// in this package.
diff --git a/src/crypto/ed25519/ed25519_test.go b/src/crypto/ed25519/ed25519_test.go
index 6b5cb9d201..f77d463721 100644
--- a/src/crypto/ed25519/ed25519_test.go
+++ b/src/crypto/ed25519/ed25519_test.go
@@ -113,14 +113,20 @@ func TestEqual(t *testing.T) {
if !public.Equal(public) {
t.Errorf("public key is not equal to itself: %q", public)
}
- if !public.Equal(crypto.Signer(private).Public().(PublicKey)) {
+ if !public.Equal(crypto.Signer(private).Public()) {
t.Errorf("private.Public() is not Equal to public: %q", public)
}
+ if !private.Equal(private) {
+ t.Errorf("private key is not equal to itself: %q", private)
+ }
- other, _, _ := GenerateKey(rand.Reader)
- if public.Equal(other) {
+ otherPub, otherPriv, _ := GenerateKey(rand.Reader)
+ if public.Equal(otherPub) {
t.Errorf("different public keys are Equal")
}
+ if private.Equal(otherPriv) {
+ t.Errorf("different private keys are Equal")
+ }
}
func TestGolden(t *testing.T) {
diff --git a/src/crypto/rsa/equal_test.go b/src/crypto/rsa/equal_test.go
index b00d0ea8a9..90f4bf9475 100644
--- a/src/crypto/rsa/equal_test.go
+++ b/src/crypto/rsa/equal_test.go
@@ -22,21 +22,30 @@ func TestEqual(t *testing.T) {
if !public.Equal(crypto.Signer(private).Public().(*rsa.PublicKey)) {
t.Errorf("private.Public() is not Equal to public: %q", public)
}
+ if !private.Equal(private) {
+ t.Errorf("private key is not equal to itself: %v", private)
+ }
- enc, err := x509.MarshalPKIXPublicKey(public)
+ enc, err := x509.MarshalPKCS8PrivateKey(private)
if err != nil {
t.Fatal(err)
}
- decoded, err := x509.ParsePKIXPublicKey(enc)
+ decoded, err := x509.ParsePKCS8PrivateKey(enc)
if err != nil {
t.Fatal(err)
}
- if !public.Equal(decoded) {
+ if !public.Equal(decoded.(crypto.Signer).Public()) {
t.Errorf("public key is not equal to itself after decoding: %v", public)
}
+ if !private.Equal(decoded) {
+ t.Errorf("private key is not equal to itself after decoding: %v", private)
+ }
other, _ := rsa.GenerateKey(rand.Reader, 512)
- if public.Equal(other) {
+ if public.Equal(other.Public()) {
t.Errorf("different public keys are Equal")
}
+ if private.Equal(other) {
+ t.Errorf("different private keys are Equal")
+ }
}
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go
index 28eb5926c1..b414b44148 100644
--- a/src/crypto/rsa/rsa.go
+++ b/src/crypto/rsa/rsa.go
@@ -44,6 +44,9 @@ type PublicKey struct {
E int // public exponent
}
+// Any methods implemented on PublicKey might need to also be implemented on
+// PrivateKey, as the latter embeds the former and will expose its methods.
+
// Size returns the modulus size in bytes. Raw signatures and ciphertexts
// for or by this public key will have the same size.
func (pub *PublicKey) Size() int {
@@ -109,6 +112,27 @@ func (priv *PrivateKey) Public() crypto.PublicKey {
return &priv.PublicKey
}
+// Equal reports whether priv and x have equivalent values. It ignores
+// Precomputed values.
+func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
+ xx, ok := x.(*PrivateKey)
+ if !ok {
+ return false
+ }
+ if !priv.PublicKey.Equal(&xx.PublicKey) || priv.D.Cmp(xx.D) != 0 {
+ return false
+ }
+ if len(priv.Primes) != len(xx.Primes) {
+ return false
+ }
+ for i := range priv.Primes {
+ if priv.Primes[i].Cmp(xx.Primes[i]) != 0 {
+ return false
+ }
+ }
+ return true
+}
+
// Sign signs digest with priv, reading randomness from rand. If opts is a
// *PSSOptions then the PSS algorithm will be used, otherwise PKCS#1 v1.5 will
// be used. digest must be the result of hashing the input message using