Commit b582ef38 authored by Rémy Oudompheng's avatar Rémy Oudompheng

crypto/rsa: fix infinite loop in GenerateMultiPrimeKey for large nprimes

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
parent 5a8b7dc6
......@@ -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
}
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment