From 22690e662197836806e5d30a1bd49013ea16a50a Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Wed, 4 Apr 2012 12:53:59 -0400 Subject: [PATCH] =?UTF-8?q?crypto/rsa:=20only=20enforce=20that=20de=20?= =?UTF-8?q?=E2=89=A1=201=20mod=20|(=E2=84=A4/n=E2=84=A4)*|=20in=20order=20?= =?UTF-8?q?to=20load=20private=20keys=20generated=20by=20GnuTLS.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we checked that de ≡ 1 mod φ(n). Since φ(n) is a multiple of |(ℤ/nℤ)*|, this encompassed the new check, but it was too strict as keys generated by GnuTLS would be rejected when gcd(p-1,q-1)≠1. (Also updated the error strings in crypto/rsa to contain the package name, which some were missing.) R=golang-dev, r CC=golang-dev https://golang.org/cl/5867043 --- src/pkg/crypto/rsa/pkcs1v15.go | 4 ++-- src/pkg/crypto/rsa/rsa.go | 22 +++++++++++++++------- src/pkg/crypto/rsa/rsa_test.go | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go index 254f4a3da0..8981074b63 100644 --- a/src/pkg/crypto/rsa/pkcs1v15.go +++ b/src/pkg/crypto/rsa/pkcs1v15.go @@ -232,11 +232,11 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) { hashLen = hash.Size() if inLen != hashLen { - return 0, nil, errors.New("input must be hashed message") + return 0, nil, errors.New("crypto/rsa: input must be hashed message") } prefix, ok := hashPrefixes[hash] if !ok { - return 0, nil, errors.New("unsupported hash function") + return 0, nil, errors.New("crypto/rsa: unsupported hash function") } return } diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go index ec77e68696..6ff89a902f 100644 --- a/src/pkg/crypto/rsa/rsa.go +++ b/src/pkg/crypto/rsa/rsa.go @@ -63,7 +63,7 @@ func (priv *PrivateKey) Validate() error { // easy for an attack to generate composites that pass this test. for _, prime := range priv.Primes { if !prime.ProbablyPrime(20) { - return errors.New("prime factor is composite") + return errors.New("crypto/rsa: prime factor is composite") } } @@ -73,13 +73,20 @@ func (priv *PrivateKey) Validate() error { modulus.Mul(modulus, prime) } if modulus.Cmp(priv.N) != 0 { - return errors.New("invalid modulus") + return errors.New("crypto/rsa: invalid modulus") } // Check that e and totient(Πprimes) are coprime. totient := new(big.Int).Set(bigOne) + var gcdTotients *big.Int for _, prime := range priv.Primes { pminus1 := new(big.Int).Sub(prime, bigOne) totient.Mul(totient, pminus1) + + if gcdTotients == nil { + gcdTotients = pminus1 + } else { + gcdTotients.GCD(nil, nil, gcdTotients, pminus1) + } } e := big.NewInt(int64(priv.E)) gcd := new(big.Int) @@ -87,13 +94,14 @@ func (priv *PrivateKey) Validate() error { y := new(big.Int) gcd.GCD(x, y, totient, e) if gcd.Cmp(bigOne) != 0 { - return errors.New("invalid public exponent E") + return errors.New("crypto/rsa: invalid public exponent E") } - // Check that de ≡ 1 (mod totient(Πprimes)) + // Check that de ≡ 1 mod |ℤ/nℤ| where |ℤ/nℤ| = totient/gcdTotients de := new(big.Int).Mul(priv.D, e) - de.Mod(de, totient) + order := new(big.Int).Div(totient, gcdTotients) + de.Mod(de, order) if de.Cmp(bigOne) != 0 { - return errors.New("invalid private exponent D") + return errors.New("crypto/rsa: invalid private exponent D") } return nil } @@ -118,7 +126,7 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *Priva priv.E = 65537 if nprimes < 2 { - return nil, errors.New("rsa.GenerateMultiPrimeKey: nprimes must be >= 2") + return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2") } primes := make([]*big.Int, nprimes) diff --git a/src/pkg/crypto/rsa/rsa_test.go b/src/pkg/crypto/rsa/rsa_test.go index 0fb9875d04..62bbdc4aec 100644 --- a/src/pkg/crypto/rsa/rsa_test.go +++ b/src/pkg/crypto/rsa/rsa_test.go @@ -50,6 +50,24 @@ func Test4PrimeKeyGeneration(t *testing.T) { testKeyBasics(t, priv) } +func TestGnuTLSKey(t *testing.T) { + // This is a key generated by `certtool --generate-privkey --bits 128`. + // It's such that de ≢ 1 mod φ(n), but is congruent mod the order of + // the group. + priv := &PrivateKey{ + PublicKey: PublicKey{ + N: fromBase10("290684273230919398108010081414538931343"), + E: 65537, + }, + D: fromBase10("31877380284581499213530787347443987241"), + Primes: []*big.Int{ + fromBase10("16775196964030542637"), + fromBase10("17328218193455850539"), + }, + } + testKeyBasics(t, priv) +} + func testKeyBasics(t *testing.T, priv *PrivateKey) { if err := priv.Validate(); err != nil { t.Errorf("Validate() failed: %s", err)