mirror of https://github.com/golang/go.git
crypto/(ec)dsa: use Fermat's inversion.
Now that we have a constant-time P-256 implementation, it's worth paying more attention elsewhere. The inversion of k in (EC)DSA was using Euclid's algorithm which isn't constant-time. This change switches to Fermat's algorithm, which is much better. However, it's important to note that math/big itself isn't constant time and is using a 4-bit window for exponentiation with variable memory access patterns. (Since math/big depends quite deeply on its values being in minimal (as opposed to fixed-length) represetation, perhaps crypto/elliptic should grow a constant-time implementation of exponentiation in the scalar field.) R=bradfitz Fixes #7652. LGTM=rsc R=golang-codereviews, bradfitz, rsc CC=golang-codereviews https://golang.org/cl/82740043
This commit is contained in:
parent
c5f14c55c1
commit
f23d3ea85a
|
|
@ -173,6 +173,16 @@ func GenerateKey(priv *PrivateKey, rand io.Reader) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
|
||||
// This has better constant-time properties than Euclid's method (implemented
|
||||
// in math/big.Int.ModInverse) although math/big itself isn't strictly
|
||||
// constant-time so it's not perfect.
|
||||
func fermatInverse(k, P *big.Int) *big.Int {
|
||||
two := big.NewInt(2)
|
||||
pMinus2 := new(big.Int).Sub(P, two)
|
||||
return new(big.Int).Exp(k, pMinus2, P)
|
||||
}
|
||||
|
||||
// Sign signs an arbitrary length hash (which should be the result of hashing a
|
||||
// larger message) using the private key, priv. It returns the signature as a
|
||||
// pair of integers. The security of the private key depends on the entropy of
|
||||
|
|
@ -205,7 +215,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
|
|||
}
|
||||
}
|
||||
|
||||
kInv := new(big.Int).ModInverse(k, priv.Q)
|
||||
kInv := fermatInverse(k, priv.Q)
|
||||
|
||||
r = new(big.Int).Exp(priv.G, k, priv.P)
|
||||
r.Mod(r, priv.Q)
|
||||
|
|
|
|||
|
|
@ -84,6 +84,16 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
|
|||
return ret
|
||||
}
|
||||
|
||||
// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
|
||||
// This has better constant-time properties than Euclid's method (implemented
|
||||
// in math/big.Int.ModInverse) although math/big itself isn't strictly
|
||||
// constant-time so it's not perfect.
|
||||
func fermatInverse(k, N *big.Int) *big.Int {
|
||||
two := big.NewInt(2)
|
||||
nMinus2 := new(big.Int).Sub(N, two)
|
||||
return new(big.Int).Exp(k, nMinus2, N)
|
||||
}
|
||||
|
||||
// Sign signs an arbitrary length hash (which should be the result of hashing a
|
||||
// larger message) using the private key, priv. It returns the signature as a
|
||||
// pair of integers. The security of the private key depends on the entropy of
|
||||
|
|
@ -102,7 +112,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
|
|||
return
|
||||
}
|
||||
|
||||
kInv = new(big.Int).ModInverse(k, N)
|
||||
kInv = fermatInverse(k, N)
|
||||
r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
|
||||
r.Mod(r, N)
|
||||
if r.Sign() != 0 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue