Skip to content

Commit 298cf42

Browse files
FiloSottilexujianhai666
authored andcommitted
crypto/rsa,crypto/ecdsa,crypto/ed25519: implement PrivateKey.Equal
Fixes golang#38190 Change-Id: I10766068ee18974e81b3bd78ee0b4d83cc9d1a8c Reviewed-on: https://go-review.googlesource.com/c/go/+/231417 Run-TryBot: Filippo Valsorda <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Katie Hockman <[email protected]>
1 parent dbe3390 commit 298cf42

File tree

6 files changed

+85
-11
lines changed

6 files changed

+85
-11
lines changed

src/crypto/ecdsa/ecdsa.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ type PublicKey struct {
6262
X, Y *big.Int
6363
}
6464

65+
// Any methods implemented on PublicKey might need to also be implemented on
66+
// PrivateKey, as the latter embeds the former and will expose its methods.
67+
6568
// Equal reports whether pub and x have the same value.
6669
//
6770
// 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 {
9194
return &priv.PublicKey
9295
}
9396

97+
// Equal reports whether priv and x have the same value.
98+
//
99+
// See PublicKey.Equal for details on how Curve is compared.
100+
func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
101+
xx, ok := x.(*PrivateKey)
102+
if !ok {
103+
return false
104+
}
105+
return priv.PublicKey.Equal(&xx.PublicKey) && priv.D.Cmp(xx.D) == 0
106+
}
107+
94108
// Sign signs digest with priv, reading randomness from rand. The opts argument
95109
// is not currently used but, in keeping with the crypto.Signer interface,
96110
// should be the hash function used to digest the message.

src/crypto/ecdsa/equal_test.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,32 @@ func testEqual(t *testing.T, c elliptic.Curve) {
2323
if !public.Equal(crypto.Signer(private).Public().(*ecdsa.PublicKey)) {
2424
t.Errorf("private.Public() is not Equal to public: %q", public)
2525
}
26+
if !private.Equal(private) {
27+
t.Errorf("private key is not equal to itself: %v", private)
28+
}
2629

27-
enc, err := x509.MarshalPKIXPublicKey(public)
30+
enc, err := x509.MarshalPKCS8PrivateKey(private)
2831
if err != nil {
2932
t.Fatal(err)
3033
}
31-
decoded, err := x509.ParsePKIXPublicKey(enc)
34+
decoded, err := x509.ParsePKCS8PrivateKey(enc)
3235
if err != nil {
3336
t.Fatal(err)
3437
}
35-
if !public.Equal(decoded) {
38+
if !public.Equal(decoded.(crypto.Signer).Public()) {
3639
t.Errorf("public key is not equal to itself after decoding: %v", public)
3740
}
41+
if !private.Equal(decoded) {
42+
t.Errorf("private key is not equal to itself after decoding: %v", private)
43+
}
3844

3945
other, _ := ecdsa.GenerateKey(c, rand.Reader)
40-
if public.Equal(other) {
46+
if public.Equal(other.Public()) {
4147
t.Errorf("different public keys are Equal")
4248
}
49+
if private.Equal(other) {
50+
t.Errorf("different private keys are Equal")
51+
}
4352

4453
// Ensure that keys with the same coordinates but on different curves
4554
// aren't considered Equal.

src/crypto/ed25519/ed25519.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ const (
4040
// PublicKey is the type of Ed25519 public keys.
4141
type PublicKey []byte
4242

43+
// Any methods implemented on PublicKey might need to also be implemented on
44+
// PrivateKey, as the latter embeds the former and will expose its methods.
45+
4346
// Equal reports whether pub and x have the same value.
4447
func (pub PublicKey) Equal(x crypto.PublicKey) bool {
4548
xx, ok := x.(PublicKey)
@@ -59,6 +62,15 @@ func (priv PrivateKey) Public() crypto.PublicKey {
5962
return PublicKey(publicKey)
6063
}
6164

65+
// Equal reports whether priv and x have the same value.
66+
func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
67+
xx, ok := x.(PrivateKey)
68+
if !ok {
69+
return false
70+
}
71+
return bytes.Equal(priv, xx)
72+
}
73+
6274
// Seed returns the private key seed corresponding to priv. It is provided for
6375
// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
6476
// in this package.

src/crypto/ed25519/ed25519_test.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,20 @@ func TestEqual(t *testing.T) {
113113
if !public.Equal(public) {
114114
t.Errorf("public key is not equal to itself: %q", public)
115115
}
116-
if !public.Equal(crypto.Signer(private).Public().(PublicKey)) {
116+
if !public.Equal(crypto.Signer(private).Public()) {
117117
t.Errorf("private.Public() is not Equal to public: %q", public)
118118
}
119+
if !private.Equal(private) {
120+
t.Errorf("private key is not equal to itself: %q", private)
121+
}
119122

120-
other, _, _ := GenerateKey(rand.Reader)
121-
if public.Equal(other) {
123+
otherPub, otherPriv, _ := GenerateKey(rand.Reader)
124+
if public.Equal(otherPub) {
122125
t.Errorf("different public keys are Equal")
123126
}
127+
if private.Equal(otherPriv) {
128+
t.Errorf("different private keys are Equal")
129+
}
124130
}
125131

126132
func TestGolden(t *testing.T) {

src/crypto/rsa/equal_test.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,30 @@ func TestEqual(t *testing.T) {
2222
if !public.Equal(crypto.Signer(private).Public().(*rsa.PublicKey)) {
2323
t.Errorf("private.Public() is not Equal to public: %q", public)
2424
}
25+
if !private.Equal(private) {
26+
t.Errorf("private key is not equal to itself: %v", private)
27+
}
2528

26-
enc, err := x509.MarshalPKIXPublicKey(public)
29+
enc, err := x509.MarshalPKCS8PrivateKey(private)
2730
if err != nil {
2831
t.Fatal(err)
2932
}
30-
decoded, err := x509.ParsePKIXPublicKey(enc)
33+
decoded, err := x509.ParsePKCS8PrivateKey(enc)
3134
if err != nil {
3235
t.Fatal(err)
3336
}
34-
if !public.Equal(decoded) {
37+
if !public.Equal(decoded.(crypto.Signer).Public()) {
3538
t.Errorf("public key is not equal to itself after decoding: %v", public)
3639
}
40+
if !private.Equal(decoded) {
41+
t.Errorf("private key is not equal to itself after decoding: %v", private)
42+
}
3743

3844
other, _ := rsa.GenerateKey(rand.Reader, 512)
39-
if public.Equal(other) {
45+
if public.Equal(other.Public()) {
4046
t.Errorf("different public keys are Equal")
4147
}
48+
if private.Equal(other) {
49+
t.Errorf("different private keys are Equal")
50+
}
4251
}

src/crypto/rsa/rsa.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ type PublicKey struct {
4444
E int // public exponent
4545
}
4646

47+
// Any methods implemented on PublicKey might need to also be implemented on
48+
// PrivateKey, as the latter embeds the former and will expose its methods.
49+
4750
// Size returns the modulus size in bytes. Raw signatures and ciphertexts
4851
// for or by this public key will have the same size.
4952
func (pub *PublicKey) Size() int {
@@ -109,6 +112,27 @@ func (priv *PrivateKey) Public() crypto.PublicKey {
109112
return &priv.PublicKey
110113
}
111114

115+
// Equal reports whether priv and x have equivalent values. It ignores
116+
// Precomputed values.
117+
func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
118+
xx, ok := x.(*PrivateKey)
119+
if !ok {
120+
return false
121+
}
122+
if !priv.PublicKey.Equal(&xx.PublicKey) || priv.D.Cmp(xx.D) != 0 {
123+
return false
124+
}
125+
if len(priv.Primes) != len(xx.Primes) {
126+
return false
127+
}
128+
for i := range priv.Primes {
129+
if priv.Primes[i].Cmp(xx.Primes[i]) != 0 {
130+
return false
131+
}
132+
}
133+
return true
134+
}
135+
112136
// Sign signs digest with priv, reading randomness from rand. If opts is a
113137
// *PSSOptions then the PSS algorithm will be used, otherwise PKCS#1 v1.5 will
114138
// be used. digest must be the result of hashing the input message using

0 commit comments

Comments
 (0)