Skip to content

Commit

Permalink
crypto/rsa,crypto/ecdsa,crypto/ed25519: implement PrivateKey.Equal
Browse files Browse the repository at this point in the history
Fixes golang#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>
  • Loading branch information
FiloSottile authored and xujianhai666 committed May 21, 2020
1 parent dbe3390 commit 298cf42
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 11 deletions.
14 changes: 14 additions & 0 deletions src/crypto/ecdsa/ecdsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
17 changes: 13 additions & 4 deletions src/crypto/ecdsa/equal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 12 additions & 0 deletions src/crypto/ed25519/ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.
Expand Down
12 changes: 9 additions & 3 deletions src/crypto/ed25519/ed25519_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
17 changes: 13 additions & 4 deletions src/crypto/rsa/equal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}
24 changes: 24 additions & 0 deletions src/crypto/rsa/rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 298cf42

Please sign in to comment.