blob: c2fad013e59c02657eb6e886f647acb7ba761224 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.pirk.encryption;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Random;
import org.apache.pirk.utils.SystemConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to generate the primes used in the Paillier cryptosystem
* <p>
* This class will either:
* <p>
* (1) Generate the primes according to Java's BigInteger prime generation methods, which satisfy ANSI X9.80
* <p>
* or
* <p>
* (2) Bolster Java BigInteger's prime generation to meet the requirements of NIST SP 800-56B ("Recommendation for Pair-Wise Key Establishment Schemes Using
* Integer Factorization Cryptography") and FIPS 186-4 ("Digital Signature Standard (DSS)") for key generation using probable primes.
* <p>
* Relevant page: SP 800-56B: p30 http://csrc.nist.gov/publications/nistpubs/800-56B/sp800-56B.pdf#page=30 Heading: 5.4 Prime Number Generators
* <p>
* Relevant pages FIPS 186-4: p50-p53, p55, p71: Sections B.3.1, B.3.3
* <p>
* http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#page=61
* <p>
* http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#page=80
* <p>
* Headings of most interest: Table C.2 "Minimum number of rounds of M-R testing when generating primes for use in RSA Digital Signatures" and "The primes p and
* q shall be selected with the following constraints"
*
*/
public class PrimeGenerator
{
private static final Logger logger = LoggerFactory.getLogger(PrimeGenerator.class);
private static final BigDecimal SQRT_2 = BigDecimal.valueOf(Math.sqrt(2));
private static final HashMap<Integer,BigInteger> lowerBoundCache = new HashMap<>();
private static final HashMap<Integer,BigInteger> minimumDifferenceCache = new HashMap<>();
private static boolean additionalChecksEnabled = SystemConfiguration.isSetTrue("pallier.FIPSPrimeGenerationChecks");
/**
* Method to generate a single prime
* <p>
* Will optionally ensure that the prime meets the requirements in NIST SP 800-56B and FIPS 186-4
* <p>
* NOTE: bitLength corresponds to the FIPS 186-4 nlen parameter
*/
public static BigInteger getSinglePrime(int bitLength, int certainty, Random rnd)
{
BigInteger p;
logger.debug("bitLength " + bitLength + " certainty " + certainty + " random " + rnd);
// If the additional checks are disabled, don't waste time on anything else
if (!additionalChecksEnabled)
{
p = new BigInteger(bitLength / 2, certainty, rnd);
}
else
{
// Calculate the number of Miller-Rabin rounds that we need in addition to
// the number that BigInteger will do to comply with FIPS 186-4, Appendix C.2
int roundsLeft = calcNumAdditionalMillerRabinRounds(bitLength);
// Calculate the lower bound (\sqrt(2))(2^(bitLength/2) – 1)) for use in FIPS 186-4 B.3.3, step 4.4
BigInteger lowerBound;
if (!lowerBoundCache.containsKey(bitLength))
{
lowerBound = SQRT_2.multiply(BigDecimal.valueOf(2).pow((bitLength / 2) - 1)).toBigInteger();
lowerBoundCache.put(bitLength, lowerBound);
}
else
{
lowerBound = lowerBoundCache.get(bitLength);
}
// Complete FIPS 186-4 B.3.3, steps 4.2 - 4.5
while (true)
{
// FIPS 186-4 B.3.3, step 4.2 and 4.3
// 4.2: Obtain a string p of (bitLength/2) bits from an RBG that supports the security_strength.
// 4.3: If (p is not odd), then p = p + 1. -- BigInteger hands us a prime (hence odd) with the call below
p = new BigInteger(bitLength / 2, certainty, rnd);
// FIPS 186-4 B.3.3, step 4.4
// 4.4: If p < (\sqrt(2))(2^(bitLength/2) – 1)), then go to step 4.2.
if (p.compareTo(lowerBound) > -1)
{
// FIPS 186-4, step 4.5
// Run however many more rounds of Miller-Rabin are needed
if (passesMillerRabin(p, roundsLeft, rnd))
{
// We have winner
break;
}
}
}
}
return p;
}
/**
* Method to generate a second prime, q, in relation to a (p,q) RSA key pair
* <p>
* Will optionally ensure that the prime meets the requirements in NIST SP 800-56B and FIPS 186-4
* <p>
* NOTE: bitLength corresponds to the FIPS 186-4 nlen parameter
*/
public static BigInteger getSecondPrime(int bitLength, int certainty, Random rnd, BigInteger p)
{
BigInteger q;
logger.debug("bitLength " + bitLength + " certainty " + certainty + " random " + rnd);
// If the additional checks are disabled, don't waste time on anything else
if (!additionalChecksEnabled)
{
q = new BigInteger(bitLength / 2, certainty, rnd);
}
else
{
// Calculate the number of Miller-Rabin rounds that we need in addition to
// the number that BigInteger will do to comply with FIPS 186-4, Appendix C.2
int roundsLeft = calcNumAdditionalMillerRabinRounds(bitLength);
// Calculate the lower bound (\sqrt(2))(2^(bitLength/2) – 1)) for use in FIPS 186-4 B.3.3, step 5.5
BigInteger lowerBound;
if (!lowerBoundCache.containsKey(bitLength))
{
lowerBound = SQRT_2.multiply(BigDecimal.valueOf(2).pow((bitLength / 2) - 1)).toBigInteger();
lowerBoundCache.put(bitLength, lowerBound);
}
else
{
lowerBound = lowerBoundCache.get(bitLength);
}
// Compute the minimumDifference 2^((bitLength/2) – 100) for use in FIPS 186-4 B.3.3, step 5.4
BigInteger minimumDifference;
if (!minimumDifferenceCache.containsKey(bitLength))
{
minimumDifference = BigDecimal.valueOf(2).pow(bitLength / 2 - 100).toBigInteger();
minimumDifferenceCache.put(bitLength, minimumDifference);
}
else
{
minimumDifference = minimumDifferenceCache.get(bitLength);
}
// Complete FIPS 186-4 B.3.3, steps 5.2 - 5.6
while (true)
{
// FIPS 186-4 B.3.3, step 5.2 and 5.3
// 5.2: Obtain a string q of (bitLength/2) bits from an RBG that supports the security_strength.
// 5.3: If (q is not odd), then q = q + 1. -- BigInteger hands us a prime (hence odd) with the call below
q = new BigInteger(bitLength / 2, certainty, rnd);
// FIPS 186-4 B.3.3, step 5.4 & 5.5
// 5.4 If (|p – q| ≤ 2^((bitLength/2) – 100), then go to step 5.2
// 5.5: If q < (\sqrt(2))(2^(bitLength/2) – 1)), then go to step 5.2.
BigInteger absDiff = (p.subtract(q)).abs();
if ((q.compareTo(lowerBound) > -1) && (absDiff.compareTo(minimumDifference) > 0))
{
// FIPS 186-4, step 5.6
// Run however many more rounds of Miller-Rabin are needed
if (passesMillerRabin(q, roundsLeft, rnd))
{
// We have winner
break;
}
}
}
}
return q;
}
/**
* This method returns a two-long array containing a viable RSA p and q meeting FIPS 186-4 and SP 800-56B
*/
public static BigInteger[] getPrimePair(int bitLength, int certainty, Random rnd)
{
BigInteger[] toReturn = {null, null};
toReturn[0] = getSinglePrime(bitLength, certainty, rnd);
toReturn[1] = getSecondPrime(bitLength, certainty, rnd, toReturn[0]);
return toReturn;
}
/**
* Method to return the number of Miller-Rabin rounds that we need in addition to those that BigInteger will do
*/
private static int calcNumAdditionalMillerRabinRounds(int bitLength)
{
// The code in BigInteger.java:primeToCertainty(...) that selects the number of MR rounds is excerpted below:
// if (sizeInBits < 100) { rounds = 50; rounds = n < rounds ? n : rounds; return passesMillerRabin(rounds, random); }
// if (sizeInBits < 256) { rounds = 27; }
// else if (sizeInBits < 512) { rounds = 15; }
// else if (sizeInBits < 768) { rounds = 8; }
// else if (sizeInBits < 1024) { rounds = 4; }
// else { rounds = 2; } rounds = n < rounds ? n : rounds;
int roundsLeft = 0;
if (bitLength >= 1536)
{
roundsLeft = 2; // BigInteger prime generation performs 2 rounds of MR tests; 4 is FIPS 186-4 compliant
}
else if (bitLength >= 1024)
{
roundsLeft = 3; // BigInteger prime generation performs 2 rounds of MR tests; 5 is FIPS 186-4 compliant
}
return roundsLeft;
}
/**
* Returns true iff this BigInteger passes the specified number of Miller-Rabin tests.
* <p>
* This test is taken from the FIPS 186-4, C.3.1
* <p>
* The following assumptions are made:
* <p>
* This BigInteger is a positive, odd number greater than 2. iterations<=50.
*/
private static boolean passesMillerRabin(BigInteger w, int iterations, Random rnd)
{
// Find a and m:
// a is the largest int such that 2^a | (w-1)
// and m = (w-1) / 2^a
BigInteger wMinusOne = w.subtract(BigInteger.ONE);
BigInteger m = wMinusOne;
int a = m.getLowestSetBit();
m = m.shiftRight(a);
for (int i = 0; i < iterations; i++)
{
// Generate a random b, of length len(w) bits, such that 1 < b < (w-1), steps 4.1-4.2
BigInteger b = new BigInteger(w.bitLength(), rnd);
while (b.compareTo(BigInteger.ONE) <= 0 || b.compareTo(w) >= 0)
{
b = new BigInteger(w.bitLength(), rnd);
}
// Construct z = b^m mod w, step 4.3
int j = 0;
BigInteger z = ModPowAbstraction.modPow(b, m, w);
while (!((j == 0 && z.equals(BigInteger.ONE)) || z.equals(wMinusOne))) // step 4.4-4.5
{
if (j > 0 && z.equals(BigInteger.ONE) || ++j == a)
{
return false;
}
z = ModPowAbstraction.modPow(z, BigInteger.valueOf(2), w); // step 4.5.1
}
}
return true;
}
}