]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/rsa: fix infinite loop in GenerateMultiPrimeKey for large nprimes
authorRémy Oudompheng <oudomphe@phare.normalesup.org>
Sun, 24 Feb 2013 16:19:09 +0000 (17:19 +0100)
committerRémy Oudompheng <oudomphe@phare.normalesup.org>
Sun, 24 Feb 2013 16:19:09 +0000 (17:19 +0100)
The heuristics for BitLen of a product of randomly generated primes
are wrong, and the generated candidates never match the required
size for nprimes > 10. This corner case is not expected to be used in
practice.

R=agl
CC=golang-dev
https://golang.org/cl/7397052

src/pkg/crypto/rsa/rsa.go
src/pkg/crypto/rsa/rsa_test.go

index 543070f90fbe4d412bf2e431617fa37cf5e78ef9..35a5f7c3c6a107504d919564a3f745ed421049fc 100644 (file)
@@ -150,6 +150,20 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *Priva
 NextSetOfPrimes:
        for {
                todo := bits
+               // crypto/rand should set the top two bits in each prime.
+               // Thus each prime has the form
+               //   p_i = 2^bitlen(p_i) × 0.11... (in base 2).
+               // And the product is:
+               //   P = 2^todo × α
+               // where α is the product of nprimes numbers of the form 0.11...
+               //
+               // If α < 1/2 (which can happen for nprimes > 2), we need to
+               // shift todo to compensate for lost bits: the mean value of 0.11...
+               // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
+               // will give good results.
+               if nprimes >= 7 {
+                       todo += (nprimes - 2) / 5
+               }
                for i := 0; i < nprimes; i++ {
                        primes[i], err = rand.Prime(random, todo/(nprimes-i))
                        if err != nil {
@@ -176,8 +190,9 @@ NextSetOfPrimes:
                        totient.Mul(totient, pminus1)
                }
                if n.BitLen() != bits {
-                       // This should never happen because crypto/rand should
-                       // set the top two bits in each prime.
+                       // This should never happen for nprimes == 2 because
+                       // crypto/rand should set the top two bits in each prime.
+                       // For nprimes > 2 we hope it does not happen often.
                        continue NextSetOfPrimes
                }
 
index 9be22a8f0bfb395c8429472bd3aebb65441bdbb2..f08cfe73c4ca99ad7a526d8cd49fbce7aec06a77 100644 (file)
@@ -28,11 +28,11 @@ func TestKeyGeneration(t *testing.T) {
 }
 
 func Test3PrimeKeyGeneration(t *testing.T) {
+       size := 768
        if testing.Short() {
-               return
+               size = 256
        }
 
-       size := 768
        priv, err := GenerateMultiPrimeKey(rand.Reader, 3, size)
        if err != nil {
                t.Errorf("failed to generate key")
@@ -41,11 +41,11 @@ func Test3PrimeKeyGeneration(t *testing.T) {
 }
 
 func Test4PrimeKeyGeneration(t *testing.T) {
+       size := 768
        if testing.Short() {
-               return
+               size = 256
        }
 
-       size := 768
        priv, err := GenerateMultiPrimeKey(rand.Reader, 4, size)
        if err != nil {
                t.Errorf("failed to generate key")
@@ -53,6 +53,24 @@ func Test4PrimeKeyGeneration(t *testing.T) {
        testKeyBasics(t, priv)
 }
 
+func TestNPrimeKeyGeneration(t *testing.T) {
+       primeSize := 64
+       maxN := 24
+       if testing.Short() {
+               primeSize = 16
+               maxN = 16
+       }
+       // Test that generation of N-prime keys works for N > 4.
+       for n := 5; n < maxN; n++ {
+               priv, err := GenerateMultiPrimeKey(rand.Reader, n, 64+n*primeSize)
+               if err == nil {
+                       testKeyBasics(t, priv)
+               } else {
+                       t.Errorf("failed to generate %d-prime key", n)
+               }
+       }
+}
+
 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