001: package org.bouncycastle.crypto.generators;
002:
003: import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
004: import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
005: import org.bouncycastle.crypto.KeyGenerationParameters;
006: import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
007: import org.bouncycastle.crypto.params.RSAKeyParameters;
008: import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
009:
010: import java.math.BigInteger;
011:
012: /**
013: * an RSA key pair generator.
014: */
015: public class RSAKeyPairGenerator implements
016: AsymmetricCipherKeyPairGenerator {
017: private static final BigInteger ONE = BigInteger.valueOf(1);
018:
019: private RSAKeyGenerationParameters param;
020:
021: public void init(KeyGenerationParameters param) {
022: this .param = (RSAKeyGenerationParameters) param;
023: }
024:
025: public AsymmetricCipherKeyPair generateKeyPair() {
026: BigInteger p, q, n, d, e, pSub1, qSub1, phi;
027:
028: //
029: // p and q values should have a length of half the strength in bits
030: //
031: int strength = param.getStrength();
032: int pbitlength = (strength + 1) / 2;
033: int qbitlength = strength - pbitlength;
034: int mindiffbits = strength / 3;
035:
036: e = param.getPublicExponent();
037:
038: //
039: // generate p, prime and (p-1) relatively prime to e
040: //
041: for (;;) {
042: p = new BigInteger(pbitlength, 1, param.getRandom());
043:
044: if (p.mod(e).equals(ONE)) {
045: continue;
046: }
047:
048: if (!p.isProbablePrime(param.getCertainty())) {
049: continue;
050: }
051:
052: if (e.gcd(p.subtract(ONE)).equals(ONE)) {
053: break;
054: }
055: }
056:
057: //
058: // generate a modulus of the required length
059: //
060: for (;;) {
061: // generate q, prime and (q-1) relatively prime to e,
062: // and not equal to p
063: //
064: for (;;) {
065: q = new BigInteger(qbitlength, 1, param.getRandom());
066:
067: if (q.subtract(p).abs().bitLength() < mindiffbits) {
068: continue;
069: }
070:
071: if (q.mod(e).equals(ONE)) {
072: continue;
073: }
074:
075: if (!q.isProbablePrime(param.getCertainty())) {
076: continue;
077: }
078:
079: if (e.gcd(q.subtract(ONE)).equals(ONE)) {
080: break;
081: }
082: }
083:
084: //
085: // calculate the modulus
086: //
087: n = p.multiply(q);
088:
089: if (n.bitLength() == param.getStrength()) {
090: break;
091: }
092:
093: //
094: // if we get here our primes aren't big enough, make the largest
095: // of the two p and try again
096: //
097: p = p.max(q);
098: }
099:
100: if (p.compareTo(q) < 0) {
101: phi = p;
102: p = q;
103: q = phi;
104: }
105:
106: pSub1 = p.subtract(ONE);
107: qSub1 = q.subtract(ONE);
108: phi = pSub1.multiply(qSub1);
109:
110: //
111: // calculate the private exponent
112: //
113: d = e.modInverse(phi);
114:
115: //
116: // calculate the CRT factors
117: //
118: BigInteger dP, dQ, qInv;
119:
120: dP = d.remainder(pSub1);
121: dQ = d.remainder(qSub1);
122: qInv = q.modInverse(p);
123:
124: return new AsymmetricCipherKeyPair(new RSAKeyParameters(false,
125: n, e), new RSAPrivateCrtKeyParameters(n, e, d, p, q,
126: dP, dQ, qInv));
127: }
128: }
|