public void AppliedCryptographySanityChecks() { // Sanity checks from Applied Cryptography, 2nd Edition p467 - 468 var p = new BigInteger(47); var q = new BigInteger(71); var n = p * q; var e = new BigInteger(79); var d = e.ModInverse((p - 1) * (q - 1)); Func<int, string> encryptor = m => (new BigInteger(m).ModPow(e, n)).ToString(); Assert.AreEqual("1570", encryptor(688)); Assert.AreEqual("2756", encryptor(232)); Assert.AreEqual("2091", encryptor(687)); Assert.AreEqual("2276", encryptor(966)); Assert.AreEqual("2423", encryptor(668)); Assert.AreEqual("158", encryptor(3)); }
public override bool VerifySignature (byte[] rgbHash, byte[] rgbSignature) { if (m_disposed) throw new ObjectDisposedException (Locale.GetText ("Keypair was disposed")); if (rgbHash == null) throw new ArgumentNullException ("rgbHash"); if (rgbSignature == null) throw new ArgumentNullException ("rgbSignature"); if (rgbHash.Length != 20) throw new CryptographicException ("invalid hash length"); // signature is always 40 bytes (no matter the size of the // public key). In fact it is 2 times the size of the private // key (which is 20 bytes for 512 to 1024 bits DSA keypairs) if (rgbSignature.Length != 40) throw new CryptographicException ("invalid signature length"); // it would be stupid to verify a signature with a newly // generated keypair - so we return false if (!keypairGenerated) return false; try { BigInteger m = new BigInteger (rgbHash); byte[] half = new byte [20]; Array.Copy (rgbSignature, 0, half, 0, 20); BigInteger r = new BigInteger (half); Array.Copy (rgbSignature, 20, half, 0, 20); BigInteger s = new BigInteger (half); if ((r < 0) || (q <= r)) return false; if ((s < 0) || (q <= s)) return false; BigInteger w = s.ModInverse(q); BigInteger u1 = m * w % q; BigInteger u2 = r * w % q; u1 = g.ModPow(u1, p); u2 = y.ModPow(u2, p); BigInteger v = ((u1 * u2 % p) % q); return (v == r); } catch { throw new CryptographicException ("couldn't compute signature verification"); } }
private void GenerateKeyPair () { // p and q values should have a length of half the strength in bits int pbitlength = ((KeySize + 1) >> 1); int qbitlength = (KeySize - pbitlength); const uint uint_e = 17; e = uint_e; // fixed // generate p, prime and (p-1) relatively prime to e for (;;) { p = BigInteger.GeneratePseudoPrime (pbitlength); if (p % uint_e != 1) break; } // generate a modulus of the required length for (;;) { // generate q, prime and (q-1) relatively prime to e, // and not equal to p for (;;) { q = BigInteger.GeneratePseudoPrime (qbitlength); if ((q % uint_e != 1) && (p != q)) break; } // calculate the modulus n = p * q; if (n.BitCount () == KeySize) break; // if we get here our primes aren't big enough, make the largest // of the two p and try again if (p < q) p = q; } BigInteger pSub1 = (p - 1); BigInteger qSub1 = (q - 1); BigInteger phi = pSub1 * qSub1; // calculate the private exponent d = e.ModInverse (phi); // calculate the CRT factors dp = d % pSub1; dq = d % qSub1; qInv = q.ModInverse (p); keypairGenerated = true; isCRTpossible = true; if (KeyGenerated != null) KeyGenerated (this, null); }
public override void ImportParameters (RSAParameters parameters) { if (m_disposed) throw new ObjectDisposedException (Locale.GetText ("Keypair was disposed")); // if missing "mandatory" parameters if (parameters.Exponent == null) throw new CryptographicException (Locale.GetText ("Missing Exponent")); if (parameters.Modulus == null) throw new CryptographicException (Locale.GetText ("Missing Modulus")); e = new BigInteger (parameters.Exponent); n = new BigInteger (parameters.Modulus); // only if the private key is present if (parameters.D != null) d = new BigInteger (parameters.D); if (parameters.DP != null) dp = new BigInteger (parameters.DP); if (parameters.DQ != null) dq = new BigInteger (parameters.DQ); if (parameters.InverseQ != null) qInv = new BigInteger (parameters.InverseQ); if (parameters.P != null) p = new BigInteger (parameters.P); if (parameters.Q != null) q = new BigInteger (parameters.Q); // we now have a keypair keypairGenerated = true; bool privateKey = ((p != null) && (q != null) && (dp != null)); isCRTpossible = (privateKey && (dq != null) && (qInv != null)); // check if the public/private keys match // the way the check is made allows a bad D to work if CRT is available (like MS does, see unit tests) if (!privateKey) return; // always check n == p * q bool ok = (n == (p * q)); if (ok) { // we now know that p and q are correct, so (p - 1), (q - 1) and phi will be ok too BigInteger pSub1 = (p - 1); BigInteger qSub1 = (q - 1); BigInteger phi = pSub1 * qSub1; // e is fairly static but anyway we can ensure it makes sense by recomputing d BigInteger dcheck = e.ModInverse (phi); // now if our new d(check) is different than the d we're provided then we cannot // be sure if 'd' or 'e' is invalid... (note that, from experience, 'd' is more // likely to be invalid since it's twice as large as DP (or DQ) and sits at the // end of the structure (e.g. truncation). ok = (d == dcheck); // ... unless we have the pre-computed CRT parameters if (!ok && isCRTpossible) { // we can override the previous decision since Mono always prefer, for // performance reasons, using the CRT algorithm ok = (dp == (dcheck % pSub1)) && (dq == (dcheck % qSub1)) && (qInv == q.ModInverse (p)); } } if (!ok) throw new CryptographicException (Locale.GetText ("Private/public key mismatch")); }