Home | History | Annotate | Download | only in generators
      1 package org.bouncycastle.crypto.generators;
      2 
      3 import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
      4 import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
      5 import org.bouncycastle.crypto.KeyGenerationParameters;
      6 import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
      7 import org.bouncycastle.crypto.params.RSAKeyParameters;
      8 import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
      9 
     10 import java.math.BigInteger;
     11 
     12 /**
     13  * an RSA key pair generator.
     14  */
     15 public class RSAKeyPairGenerator
     16     implements AsymmetricCipherKeyPairGenerator
     17 {
     18     private static final BigInteger ONE = BigInteger.valueOf(1);
     19 
     20     private RSAKeyGenerationParameters param;
     21 
     22     public void init(
     23         KeyGenerationParameters param)
     24     {
     25         this.param = (RSAKeyGenerationParameters)param;
     26     }
     27 
     28     public AsymmetricCipherKeyPair generateKeyPair()
     29     {
     30         BigInteger    p, q, n, d, e, pSub1, qSub1, phi;
     31 
     32         //
     33         // p and q values should have a length of half the strength in bits
     34         //
     35         int strength = param.getStrength();
     36         int pbitlength = (strength + 1) / 2;
     37         int qbitlength = strength - pbitlength;
     38         int mindiffbits = strength / 3;
     39 
     40         e = param.getPublicExponent();
     41 
     42         // TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes)
     43         // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
     44 
     45         //
     46         // generate p, prime and (p-1) relatively prime to e
     47         //
     48         for (;;)
     49         {
     50             p = new BigInteger(pbitlength, 1, param.getRandom());
     51 
     52             if (p.mod(e).equals(ONE))
     53             {
     54                 continue;
     55             }
     56 
     57             if (!p.isProbablePrime(param.getCertainty()))
     58             {
     59                 continue;
     60             }
     61 
     62             if (e.gcd(p.subtract(ONE)).equals(ONE))
     63             {
     64                 break;
     65             }
     66         }
     67 
     68         //
     69         // generate a modulus of the required length
     70         //
     71         for (;;)
     72         {
     73             // generate q, prime and (q-1) relatively prime to e,
     74             // and not equal to p
     75             //
     76             for (;;)
     77             {
     78                 q = new BigInteger(qbitlength, 1, param.getRandom());
     79 
     80                 if (q.subtract(p).abs().bitLength() < mindiffbits)
     81                 {
     82                     continue;
     83                 }
     84 
     85                 if (q.mod(e).equals(ONE))
     86                 {
     87                     continue;
     88                 }
     89 
     90                 if (!q.isProbablePrime(param.getCertainty()))
     91                 {
     92                     continue;
     93                 }
     94 
     95                 if (e.gcd(q.subtract(ONE)).equals(ONE))
     96                 {
     97                     break;
     98                 }
     99             }
    100 
    101             //
    102             // calculate the modulus
    103             //
    104             n = p.multiply(q);
    105 
    106             if (n.bitLength() == param.getStrength())
    107             {
    108                 break;
    109             }
    110 
    111             //
    112             // if we get here our primes aren't big enough, make the largest
    113             // of the two p and try again
    114             //
    115             p = p.max(q);
    116         }
    117 
    118         if (p.compareTo(q) < 0)
    119         {
    120             phi = p;
    121             p = q;
    122             q = phi;
    123         }
    124 
    125         pSub1 = p.subtract(ONE);
    126         qSub1 = q.subtract(ONE);
    127         phi = pSub1.multiply(qSub1);
    128 
    129         //
    130         // calculate the private exponent
    131         //
    132         d = e.modInverse(phi);
    133 
    134         //
    135         // calculate the CRT factors
    136         //
    137         BigInteger    dP, dQ, qInv;
    138 
    139         dP = d.remainder(pSub1);
    140         dQ = d.remainder(qSub1);
    141         qInv = q.modInverse(p);
    142 
    143         return new AsymmetricCipherKeyPair(
    144                 new RSAKeyParameters(false, n, e),
    145                 new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
    146     }
    147 }
    148