RSAKeyPairGenerator.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.crypto.generators;
2
3import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
4import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
5import org.bouncycastle.crypto.KeyGenerationParameters;
6import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
7import org.bouncycastle.crypto.params.RSAKeyParameters;
8import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
9
10import java.math.BigInteger;
11
12/**
13 * an RSA key pair generator.
14 */
15public 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