Home | History | Annotate | Download | only in generators
      1 package org.bouncycastle.crypto.generators;
      2 
      3 import java.math.BigInteger;
      4 
      5 import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
      6 import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
      7 import org.bouncycastle.crypto.KeyGenerationParameters;
      8 import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
      9 import org.bouncycastle.crypto.params.RSAKeyParameters;
     10 import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
     11 import org.bouncycastle.math.Primes;
     12 import org.bouncycastle.math.ec.WNafUtil;
     13 
     14 /**
     15  * an RSA key pair generator.
     16  */
     17 public class RSAKeyPairGenerator
     18     implements AsymmetricCipherKeyPairGenerator
     19 {
     20     private static final BigInteger ONE = BigInteger.valueOf(1);
     21 
     22     private RSAKeyGenerationParameters param;
     23     private int iterations;
     24 
     25     public void init(KeyGenerationParameters param)
     26     {
     27         this.param = (RSAKeyGenerationParameters)param;
     28         this.iterations = getNumberOfIterations(this.param.getStrength(), this.param.getCertainty());
     29     }
     30 
     31     public AsymmetricCipherKeyPair generateKeyPair()
     32     {
     33         AsymmetricCipherKeyPair result = null;
     34         boolean done = false;
     35 
     36         //
     37         // p and q values should have a length of half the strength in bits
     38         //
     39         int strength = param.getStrength();
     40         int pbitlength = (strength + 1) / 2;
     41         int qbitlength = strength - pbitlength;
     42         int mindiffbits = (strength / 2) - 100;
     43 
     44         if (mindiffbits < strength / 3)
     45         {
     46             mindiffbits = strength / 3;
     47         }
     48 
     49         int minWeight = strength >> 2;
     50 
     51         // d lower bound is 2^(strength / 2)
     52         BigInteger dLowerBound = BigInteger.valueOf(2).pow(strength / 2);
     53         // squared bound (sqrt(2)*2^(nlen/2-1))^2
     54         BigInteger squaredBound = ONE.shiftLeft(strength - 1);
     55         // 2^(nlen/2 - 100)
     56         BigInteger minDiff = ONE.shiftLeft(mindiffbits);
     57 
     58         while (!done)
     59         {
     60             BigInteger p, q, n, d, e, pSub1, qSub1, gcd, lcm;
     61 
     62             e = param.getPublicExponent();
     63 
     64             p = chooseRandomPrime(pbitlength, e, squaredBound);
     65 
     66             //
     67             // generate a modulus of the required length
     68             //
     69             for (; ; )
     70             {
     71                 q = chooseRandomPrime(qbitlength, e, squaredBound);
     72 
     73                 // p and q should not be too close together (or equal!)
     74                 BigInteger diff = q.subtract(p).abs();
     75                 if (diff.bitLength() < mindiffbits || diff.compareTo(minDiff) <= 0)
     76                 {
     77                     continue;
     78                 }
     79 
     80                 //
     81                 // calculate the modulus
     82                 //
     83                 n = p.multiply(q);
     84 
     85                 if (n.bitLength() != strength)
     86                 {
     87                     //
     88                     // if we get here our primes aren't big enough, make the largest
     89                     // of the two p and try again
     90                     //
     91                     p = p.max(q);
     92                     continue;
     93                 }
     94 
     95 	            /*
     96                  * Require a minimum weight of the NAF representation, since low-weight composites may
     97 	             * be weak against a version of the number-field-sieve for factoring.
     98 	             *
     99 	             * See "The number field sieve for integers of low weight", Oliver Schirokauer.
    100 	             */
    101                 if (WNafUtil.getNafWeight(n) < minWeight)
    102                 {
    103                     p = chooseRandomPrime(pbitlength, e, squaredBound);
    104                     continue;
    105                 }
    106 
    107                 break;
    108             }
    109 
    110             if (p.compareTo(q) < 0)
    111             {
    112                 gcd = p;
    113                 p = q;
    114                 q = gcd;
    115             }
    116 
    117             pSub1 = p.subtract(ONE);
    118             qSub1 = q.subtract(ONE);
    119             gcd = pSub1.gcd(qSub1);
    120             lcm = pSub1.divide(gcd).multiply(qSub1);
    121 
    122             //
    123             // calculate the private exponent
    124             //
    125             d = e.modInverse(lcm);
    126 
    127             if (d.compareTo(dLowerBound) <= 0)
    128             {
    129                 continue;
    130             }
    131             else
    132             {
    133                 done = true;
    134             }
    135 
    136             //
    137             // calculate the CRT factors
    138             //
    139             BigInteger dP, dQ, qInv;
    140 
    141             dP = d.remainder(pSub1);
    142             dQ = d.remainder(qSub1);
    143             qInv = q.modInverse(p);
    144 
    145             result = new AsymmetricCipherKeyPair(
    146                 new RSAKeyParameters(false, n, e),
    147                 new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
    148         }
    149 
    150         return result;
    151     }
    152 
    153     /**
    154      * Choose a random prime value for use with RSA
    155      *
    156      * @param bitlength the bit-length of the returned prime
    157      * @param e         the RSA public exponent
    158      * @return A prime p, with (p-1) relatively prime to e
    159      */
    160     protected BigInteger chooseRandomPrime(int bitlength, BigInteger e, BigInteger sqrdBound)
    161     {
    162         for (int i = 0; i != 5 * bitlength; i++)
    163         {
    164             BigInteger p = new BigInteger(bitlength, 1, param.getRandom());
    165 
    166             if (p.mod(e).equals(ONE))
    167             {
    168                 continue;
    169             }
    170 
    171             if (p.multiply(p).compareTo(sqrdBound) < 0)
    172             {
    173                 continue;
    174             }
    175 
    176             if (!isProbablePrime(p))
    177             {
    178                 continue;
    179             }
    180 
    181             if (!e.gcd(p.subtract(ONE)).equals(ONE))
    182             {
    183                 continue;
    184             }
    185 
    186             return p;
    187         }
    188 
    189         throw new IllegalStateException("unable to generate prime number for RSA key");
    190     }
    191 
    192     protected boolean isProbablePrime(BigInteger x)
    193     {
    194         /*
    195          * Primes class for FIPS 186-4 C.3 primality checking
    196          */
    197         return !Primes.hasAnySmallFactors(x) && Primes.isMRProbablePrime(x, param.getRandom(), iterations);
    198     }
    199 
    200     private static int getNumberOfIterations(int bits, int certainty)
    201     {
    202         /*
    203          * NOTE: We enforce a minimum 'certainty' of 100 for bits >= 1024 (else 80). Where the
    204          * certainty is higher than the FIPS 186-4 tables (C.2/C.3) cater to, extra iterations
    205          * are added at the "worst case rate" for the excess.
    206          */
    207         if (bits >= 1536)
    208         {
    209             return  certainty <= 100 ? 3
    210                 :   certainty <= 128 ? 4
    211                 :   4 + (certainty - 128 + 1) / 2;
    212         }
    213         else if (bits >= 1024)
    214         {
    215             return  certainty <= 100 ? 4
    216                 :   certainty <= 112 ? 5
    217                 :   5 + (certainty - 112 + 1) / 2;
    218         }
    219         else if (bits >= 512)
    220         {
    221             return  certainty <= 80  ? 5
    222                 :   certainty <= 100 ? 7
    223                 :   7 + (certainty - 100 + 1) / 2;
    224         }
    225         else
    226         {
    227             return  certainty <= 80  ? 40
    228                 :   40 + (certainty - 80 + 1) / 2;
    229         }
    230     }
    231 }
    232