org.bouncycastle.crypto.fips.RsaKeyPairGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bc-fips Show documentation
Show all versions of bc-fips Show documentation
The FIPS 140-3 Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms certified to FIPS 140-3 level 1. This jar contains JCE provider and low-level API for the BC-FJA version 2.0.0, FIPS Certificate #4743. Please see certificate for certified platform details.
package org.bouncycastle.crypto.fips;
import java.math.BigInteger;
import org.bouncycastle.crypto.internal.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.internal.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.internal.KeyGenerationParameters;
import org.bouncycastle.crypto.internal.params.RsaKeyGenerationParameters;
import org.bouncycastle.crypto.internal.params.RsaKeyParameters;
import org.bouncycastle.crypto.internal.params.RsaPrivateCrtKeyParameters;
import org.bouncycastle.math.ec.WNafUtil;
import org.bouncycastle.math.internal.Primes;
/**
* an RSA key pair generator.
*/
class RsaKeyPairGenerator
implements AsymmetricCipherKeyPairGenerator
{
private static final BigInteger ONE = BigInteger.valueOf(1);
private RsaKeyGenerationParameters param;
public void init(
KeyGenerationParameters param)
{
this.param = (RsaKeyGenerationParameters)param;
}
public AsymmetricCipherKeyPair generateKeyPair()
{
AsymmetricCipherKeyPair result = null;
boolean done = false;
//
// 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;
int minWeight = strength >> 2;
// for approved mode operation this will never happen, but in case
// someone is doing something "different" we make sure mindiffbits is
// always sensible.
if (mindiffbits < strength / 3)
{
mindiffbits = strength / 3;
}
// 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 = BigInteger.ONE.shiftLeft(strength - 1);
// 2^(nlen/2 - 100)
BigInteger minDiff = BigInteger.ONE.shiftLeft(mindiffbits);
while (!done)
{
BigInteger p, q, n, d, e, pSub1, qSub1, gcd, lcm;
e = param.getPublicExponent();
p = chooseRandomPrime(pbitlength, e, squaredBound);
//
// generate a modulus of the required length
//
for (; ; )
{
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 || diff.compareTo(minDiff) <= 0)
{
continue;
}
//
// calculate the modulus
//
n = p.multiply(q);
if (n.bitLength() != strength)
{
//
// if we get here our primes aren't big enough, make the largest
// of the two p and try again
//
p = p.max(q);
continue;
}
/*
* 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, squaredBound);
continue;
}
break;
}
if (p.compareTo(q) < 0)
{
gcd = p;
p = q;
q = gcd;
}
pSub1 = p.subtract(ONE);
qSub1 = q.subtract(ONE);
gcd = pSub1.gcd(qSub1);
lcm = pSub1.divide(gcd).multiply(qSub1);
//
// calculate the private exponent
//
d = e.modInverse(lcm);
if (d.compareTo(dLowerBound) <= 0)
{
continue;
}
else
{
done = true;
}
//
// calculate the CRT factors
//
BigInteger dP, dQ, qInv;
dP = d.remainder(pSub1);
dQ = d.remainder(qSub1);
qInv = q.modInverse(p);
result = new AsymmetricCipherKeyPair(
new RsaKeyParameters(false, n, e),
new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
}
return result;
}
/**
* 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
*/
private BigInteger chooseRandomPrime(int bitlength, BigInteger e, BigInteger sqrdBound)
{
int iterations = getNumberOfIterations(bitlength, this.param.getCertainty());
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.multiply(p).compareTo(sqrdBound) < 0)
{
continue;
}
if (!isProbablePrime(p, iterations))
{
continue;
}
if (!e.gcd(p.subtract(ONE)).equals(ONE))
{
continue;
}
return p;
}
throw new IllegalStateException("unable to generate prime number for RSA key");
}
private boolean isProbablePrime(BigInteger x, int iterations)
{
/*
* 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;
}
}
}