summaryrefslogtreecommitdiff
path: root/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
diff options
context:
space:
mode:
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java')
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java132
1 files changed, 94 insertions, 38 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
index 7277045e..f23f654b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
@@ -8,6 +8,7 @@ import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.math.Primes;
import org.bouncycastle.math.ec.WNafUtil;
/**
@@ -19,10 +20,12 @@ public class RSAKeyPairGenerator
private static final BigInteger ONE = BigInteger.valueOf(1);
private RSAKeyGenerationParameters param;
+ private int iterations;
public void init(KeyGenerationParameters param)
{
this.param = (RSAKeyGenerationParameters)param;
+ this.iterations = getNumberOfIterations(this.param.getStrength(), this.param.getCertainty());
}
public AsymmetricCipherKeyPair generateKeyPair()
@@ -30,36 +33,46 @@ public class RSAKeyPairGenerator
AsymmetricCipherKeyPair result = null;
boolean done = false;
- while (!done)
+ //
+ // p and q values should have a length of half the strength in bits
+ //
+ int strength = param.getStrength();
+ int pbitlength = (strength + 1) / 2;
+ int qbitlength = strength - pbitlength;
+ int mindiffbits = (strength / 2) - 100;
+
+ if (mindiffbits < strength / 3)
{
- BigInteger p, q, n, d, e, pSub1, qSub1, phi, lcm, dLowerBound;
+ mindiffbits = strength / 3;
+ }
- //
- // p and q values should have a length of half the strength in bits
- //
- int strength = param.getStrength();
- int pbitlength = (strength + 1) / 2;
- int qbitlength = strength - pbitlength;
- int mindiffbits = strength / 3;
- int minWeight = strength >> 2;
+ int minWeight = strength >> 2;
- e = param.getPublicExponent();
+ // d lower bound is 2^(strength / 2)
+ BigInteger dLowerBound = BigInteger.valueOf(2).pow(strength / 2);
+ // squared bound (sqrt(2)*2^(nlen/2-1))^2
+ BigInteger squaredBound = ONE.shiftLeft(strength - 1);
+ // 2^(nlen/2 - 100)
+ BigInteger minDiff = ONE.shiftLeft(mindiffbits);
- // TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes)
- // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
+ while (!done)
+ {
+ BigInteger p, q, n, d, e, pSub1, qSub1, gcd, lcm;
- p = chooseRandomPrime(pbitlength, e);
+ e = param.getPublicExponent();
+
+ p = chooseRandomPrime(pbitlength, e, squaredBound);
//
// generate a modulus of the required length
//
- for (;;)
+ for (; ; )
{
- q = chooseRandomPrime(qbitlength, e);
+ q = chooseRandomPrime(qbitlength, e, squaredBound);
// p and q should not be too close together (or equal!)
BigInteger diff = q.subtract(p).abs();
- if (diff.bitLength() < mindiffbits)
+ if (diff.bitLength() < mindiffbits || diff.compareTo(minDiff) <= 0)
{
continue;
}
@@ -80,14 +93,14 @@ public class RSAKeyPairGenerator
}
/*
- * Require a minimum weight of the NAF representation, since low-weight composites may
+ * Require a minimum weight of the NAF representation, since low-weight composites may
* be weak against a version of the number-field-sieve for factoring.
*
* See "The number field sieve for integers of low weight", Oliver Schirokauer.
*/
if (WNafUtil.getNafWeight(n) < minWeight)
{
- p = chooseRandomPrime(pbitlength, e);
+ p = chooseRandomPrime(pbitlength, e, squaredBound);
continue;
}
@@ -96,26 +109,22 @@ public class RSAKeyPairGenerator
if (p.compareTo(q) < 0)
{
- phi = p;
+ gcd = p;
p = q;
- q = phi;
+ q = gcd;
}
pSub1 = p.subtract(ONE);
qSub1 = q.subtract(ONE);
- phi = pSub1.multiply(qSub1);
- lcm = phi.divide(pSub1.gcd(qSub1));
+ gcd = pSub1.gcd(qSub1);
+ lcm = pSub1.divide(gcd).multiply(qSub1);
//
// calculate the private exponent
//
d = e.modInverse(lcm);
- // if d is less than or equal to dLowerBound, we need to start over
- // also, for backward compatibility, if d is not the same as
- // e.modInverse(phi), we need to start over
-
- if (d.bitLength() <= qbitlength || !d.equals(e.modInverse(phi)))
+ if (d.compareTo(dLowerBound) <= 0)
{
continue;
}
@@ -143,33 +152,80 @@ public class RSAKeyPairGenerator
/**
* Choose a random prime value for use with RSA
- *
+ *
* @param bitlength the bit-length of the returned prime
- * @param e the RSA public exponent
- * @return a prime p, with (p-1) relatively prime to e
+ * @param e the RSA public exponent
+ * @return A prime p, with (p-1) relatively prime to e
*/
- protected BigInteger chooseRandomPrime(int bitlength, BigInteger e)
+ protected BigInteger chooseRandomPrime(int bitlength, BigInteger e, BigInteger sqrdBound)
{
- for (;;)
+ for (int i = 0; i != 5 * bitlength; i++)
{
BigInteger p = new BigInteger(bitlength, 1, param.getRandom());
-
+
if (p.mod(e).equals(ONE))
{
continue;
}
-
- if (!p.isProbablePrime(param.getCertainty()))
+
+ if (p.multiply(p).compareTo(sqrdBound) < 0)
+ {
+ continue;
+ }
+
+ if (!isProbablePrime(p))
{
continue;
}
- if (!e.gcd(p.subtract(ONE)).equals(ONE))
+ if (!e.gcd(p.subtract(ONE)).equals(ONE))
{
continue;
}
-
+
return p;
}
+
+ throw new IllegalStateException("unable to generate prime number for RSA key");
+ }
+
+ protected boolean isProbablePrime(BigInteger x)
+ {
+ /*
+ * Primes class for FIPS 186-4 C.3 primality checking
+ */
+ return !Primes.hasAnySmallFactors(x) && Primes.isMRProbablePrime(x, param.getRandom(), iterations);
+ }
+
+ private static int getNumberOfIterations(int bits, int certainty)
+ {
+ /*
+ * NOTE: We enforce a minimum 'certainty' of 100 for bits >= 1024 (else 80). Where the
+ * certainty is higher than the FIPS 186-4 tables (C.2/C.3) cater to, extra iterations
+ * are added at the "worst case rate" for the excess.
+ */
+ if (bits >= 1536)
+ {
+ return certainty <= 100 ? 3
+ : certainty <= 128 ? 4
+ : 4 + (certainty - 128 + 1) / 2;
+ }
+ else if (bits >= 1024)
+ {
+ return certainty <= 100 ? 4
+ : certainty <= 112 ? 5
+ : 5 + (certainty - 112 + 1) / 2;
+ }
+ else if (bits >= 512)
+ {
+ return certainty <= 80 ? 5
+ : certainty <= 100 ? 7
+ : 7 + (certainty - 100 + 1) / 2;
+ }
+ else
+ {
+ return certainty <= 80 ? 40
+ : 40 + (certainty - 80 + 1) / 2;
+ }
}
}