// Generate an RSA keypair
// Popular exponents are 3, 17 and 65537; the bigger it is, the slower encryption becomes
public void GenerateKeyPair(int exponent)
{
for (; ; ) {
BigInteger E = exponent;
Random rand = new Random();
int nbits = this.keylen * 8 / 2; // so that P * Q < N
// Find primes P and Q with Q < P so that:
// GCD (E, (P - 1) * (Q - 1)) == 1
BigInteger P = null;
BigInteger Q = null;
BigInteger Pmin1 = null;
BigInteger Qmin1 = null;
BigInteger H = null;
BigInteger GCD = null;
do {
P = BigInteger.genPseudoPrime(nbits, 20, rand);
Q = BigInteger.genPseudoPrime(nbits, 20, rand);
if (P == Q)
continue;
if (P < Q) {
BigInteger swap = P;
P = Q;
Q = swap;
}
Pmin1 = P - 1;
Qmin1 = Q - 1;
H = Pmin1 * Qmin1;
GCD = H.gcd(E);
}
while (GCD != 1);
// N = P * Q
// D = E^-1 mod ((P - 1) * (Q - 1))
// DP = D mod (P - 1)
// DQ = D mod (Q - 1)
// QP = Q^-1 mod P
this.N = P * Q;
this.E = E;
this.P = P;
this.Q = Q;
this.D = E.modInverse(H);
this.DP = D.modPow(1, Pmin1);
this.DQ = D.modPow(1, Qmin1);
this.QP = Q.modInverse(P);
// Check that this key actually works!
// BigInteger.genPseudoPrime (rarely) returns a non-prime
byte[] encrypt_me = new byte[this.keylen - 1];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(encrypt_me);
encrypt_me = pad_bytes(encrypt_me, this.keylen); // ensure msg < modulus
byte[] encrypted = DoPublic(encrypt_me);
byte[] decrypted = DoPrivate(encrypted);
if (compare_bytes(encrypt_me, 0, decrypted, 0, this.keylen))
return;
}
}