Skip to content

Commit bf8571c

Browse files
FiloSottilegopherbot
authored andcommitted
crypto/ed25519,crypto/rsa: make Equal methods constant time
Fixes #53849 Updates #57752 Change-Id: I055564f31a47c79565b82bf9844fcf626989b295 Reviewed-on: https://go-review.googlesource.com/c/go/+/492955 Auto-Submit: Russ Cox <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]> Reviewed-by: Russ Cox <[email protected]> Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent b7e767b commit bf8571c

File tree

2 files changed

+12
-5
lines changed

2 files changed

+12
-5
lines changed

src/crypto/ed25519/ed25519.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"crypto/internal/edwards25519"
1919
cryptorand "crypto/rand"
2020
"crypto/sha512"
21+
"crypto/subtle"
2122
"errors"
2223
"io"
2324
"strconv"
@@ -46,7 +47,7 @@ func (pub PublicKey) Equal(x crypto.PublicKey) bool {
4647
if !ok {
4748
return false
4849
}
49-
return bytes.Equal(pub, xx)
50+
return subtle.ConstantTimeCompare(pub, xx) == 1
5051
}
5152

5253
// PrivateKey is the type of Ed25519 private keys. It implements [crypto.Signer].
@@ -65,7 +66,7 @@ func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
6566
if !ok {
6667
return false
6768
}
68-
return bytes.Equal(priv, xx)
69+
return subtle.ConstantTimeCompare(priv, xx) == 1
6970
}
7071

7172
// Seed returns the private key seed corresponding to priv. It is provided for

src/crypto/rsa/rsa.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
6464
if !ok {
6565
return false
6666
}
67-
return pub.N.Cmp(xx.N) == 0 && pub.E == xx.E
67+
return bigIntEqual(pub.N, xx.N) && pub.E == xx.E
6868
}
6969

7070
// OAEPOptions is an interface for passing options to OAEP decryption using the
@@ -130,20 +130,26 @@ func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
130130
if !ok {
131131
return false
132132
}
133-
if !priv.PublicKey.Equal(&xx.PublicKey) || priv.D.Cmp(xx.D) != 0 {
133+
if !priv.PublicKey.Equal(&xx.PublicKey) || !bigIntEqual(priv.D, xx.D) {
134134
return false
135135
}
136136
if len(priv.Primes) != len(xx.Primes) {
137137
return false
138138
}
139139
for i := range priv.Primes {
140-
if priv.Primes[i].Cmp(xx.Primes[i]) != 0 {
140+
if !bigIntEqual(priv.Primes[i], xx.Primes[i]) {
141141
return false
142142
}
143143
}
144144
return true
145145
}
146146

147+
// bigIntEqual reports whether a and b are equal leaking only their bit length
148+
// through timing side-channels.
149+
func bigIntEqual(a, b *big.Int) bool {
150+
return subtle.ConstantTimeCompare(a.Bytes(), b.Bytes()) == 1
151+
}
152+
147153
// Sign signs digest with priv, reading randomness from rand. If opts is a
148154
// *PSSOptions then the PSS algorithm will be used, otherwise PKCS #1 v1.5 will
149155
// be used. digest must be the result of hashing the input message using

0 commit comments

Comments
 (0)