]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/ed25519,crypto/rsa: make Equal methods constant time
authorFilippo Valsorda <filippo@golang.org>
Fri, 5 May 2023 11:22:02 +0000 (13:22 +0200)
committerGopher Robot <gobot@golang.org>
Wed, 17 May 2023 14:48:13 +0000 (14:48 +0000)
Fixes #53849
Updates #57752

Change-Id: I055564f31a47c79565b82bf9844fcf626989b295
Reviewed-on: https://go-review.googlesource.com/c/go/+/492955
Auto-Submit: Russ Cox <rsc@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/crypto/ed25519/ed25519.go
src/crypto/rsa/rsa.go

index a043eaf80770e86238223e9363922b0876a2e6d5..32a8d9e86c866f729dd6d3744d7588693b249982 100644 (file)
@@ -18,6 +18,7 @@ import (
        "crypto/internal/edwards25519"
        cryptorand "crypto/rand"
        "crypto/sha512"
+       "crypto/subtle"
        "errors"
        "io"
        "strconv"
@@ -46,7 +47,7 @@ func (pub PublicKey) Equal(x crypto.PublicKey) bool {
        if !ok {
                return false
        }
-       return bytes.Equal(pub, xx)
+       return subtle.ConstantTimeCompare(pub, xx) == 1
 }
 
 // PrivateKey is the type of Ed25519 private keys. It implements [crypto.Signer].
@@ -65,7 +66,7 @@ func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
        if !ok {
                return false
        }
-       return bytes.Equal(priv, xx)
+       return subtle.ConstantTimeCompare(priv, xx) == 1
 }
 
 // Seed returns the private key seed corresponding to priv. It is provided for
index 64a27660dcadaeefff6821cb0c87db37788ebb71..6f0221d74b8645082b2b1c5dc6073d067b9d4b87 100644 (file)
@@ -64,7 +64,7 @@ func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
        if !ok {
                return false
        }
-       return pub.N.Cmp(xx.N) == 0 && pub.E == xx.E
+       return bigIntEqual(pub.N, xx.N) && pub.E == xx.E
 }
 
 // OAEPOptions is an interface for passing options to OAEP decryption using the
@@ -130,20 +130,26 @@ func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
        if !ok {
                return false
        }
-       if !priv.PublicKey.Equal(&xx.PublicKey) || priv.D.Cmp(xx.D) != 0 {
+       if !priv.PublicKey.Equal(&xx.PublicKey) || !bigIntEqual(priv.D, xx.D) {
                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 {
+               if !bigIntEqual(priv.Primes[i], xx.Primes[i]) {
                        return false
                }
        }
        return true
 }
 
+// bigIntEqual reports whether a and b are equal leaking only their bit length
+// through timing side-channels.
+func bigIntEqual(a, b *big.Int) bool {
+       return subtle.ConstantTimeCompare(a.Bytes(), b.Bytes()) == 1
+}
+
 // 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