// 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; } }