internal RSAParameters ParseRSAPrivateKey() { RSAParameters parameters = new RSAParameters(); // Current value byte[] value = null; // Checkpoint int position = parser.CurrentPosition(); // Sanity Check int length = 0; // Ignore Sequence - PrivateKeyInfo length = parser.NextSequence(); if (length != parser.RemainingBytes()) { StringBuilder sb = new StringBuilder("Incorrect Sequence Size. "); sb.AppendFormat("Specified: {0}, Remaining: {1}", length.ToString(CultureInfo.InvariantCulture), parser.RemainingBytes().ToString(CultureInfo.InvariantCulture)); throw new BerDecodeException(sb.ToString(), position); } // Checkpoint position = parser.CurrentPosition(); // Version value = parser.NextInteger(); if (0x00 != value[0]) { StringBuilder sb = new StringBuilder("Incorrect PrivateKeyInfo Version. "); BigInteger v = new BigInteger(value); sb.AppendFormat("Expected: 0, Specified: {0}", v.ToString(10)); throw new BerDecodeException(sb.ToString(), position); } // Checkpoint position = parser.CurrentPosition(); // Ignore Sequence - AlgorithmIdentifier length = parser.NextSequence(); if (length > parser.RemainingBytes()) { StringBuilder sb = new StringBuilder("Incorrect AlgorithmIdentifier Size. "); sb.AppendFormat("Specified: {0}, Remaining: {1}", length.ToString(CultureInfo.InvariantCulture), parser.RemainingBytes().ToString(CultureInfo.InvariantCulture)); throw new BerDecodeException(sb.ToString(), position); } // Checkpoint position = parser.CurrentPosition(); // Grab the OID value = parser.NextOID(); byte[] oid = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 }; if (!EqualOid(value, oid)) { throw new BerDecodeException("Expected OID 1.2.840.113549.1.1.1", position); } // Optional Parameters if (parser.IsNextNull()) { parser.NextNull(); // Also OK: value = parser.Next(); } else { // Gracefully skip the optional data value = parser.Next(); } // Checkpoint position = parser.CurrentPosition(); // Ignore OctetString - PrivateKey length = parser.NextOctetString(); if (length > parser.RemainingBytes()) { StringBuilder sb = new StringBuilder("Incorrect PrivateKey Size. "); sb.AppendFormat("Specified: {0}, Remaining: {1}", length.ToString(CultureInfo.InvariantCulture), parser.RemainingBytes().ToString(CultureInfo.InvariantCulture)); throw new BerDecodeException(sb.ToString(), position); } // Checkpoint position = parser.CurrentPosition(); // Ignore Sequence - RSAPrivateKey length = parser.NextSequence(); if (length < parser.RemainingBytes()) { StringBuilder sb = new StringBuilder("Incorrect RSAPrivateKey Size. "); sb.AppendFormat("Specified: {0}, Remaining: {1}", length.ToString(CultureInfo.InvariantCulture), parser.RemainingBytes().ToString(CultureInfo.InvariantCulture)); throw new BerDecodeException(sb.ToString(), position); } // Checkpoint position = parser.CurrentPosition(); // Version value = parser.NextInteger(); if (0x00 != value[0]) { StringBuilder sb = new StringBuilder("Incorrect RSAPrivateKey Version. "); BigInteger v = new BigInteger(value); sb.AppendFormat("Expected: 0, Specified: {0}", v.ToString(10)); throw new BerDecodeException(sb.ToString(), position); } parameters.Modulus = TrimLeadingZero(parser.NextInteger()); parameters.Exponent = TrimLeadingZero(parser.NextInteger()); parameters.D = TrimLeadingZero(parser.NextInteger()); parameters.P = TrimLeadingZero(parser.NextInteger()); parameters.Q = TrimLeadingZero(parser.NextInteger()); parameters.DP = TrimLeadingZero(parser.NextInteger()); parameters.DQ = TrimLeadingZero(parser.NextInteger()); parameters.InverseQ = TrimLeadingZero(parser.NextInteger()); Debug.Assert(0 == parser.RemainingBytes()); return parameters; }
//*********************************************************************** // Tests the correct implementation of the modulo exponential function // using RSA encryption and decryption (using pre-computed encryption and // decryption keys). //*********************************************************************** public static void RSATest(int rounds) { Random rand = new Random(1); byte[] val = new byte[64]; // private and public key BigInteger bi_e = new BigInteger("a932b948feed4fb2b692609bd22164fc9edb59fae7880cc1eaff7b3c9626b7e5b241c27a974833b2622ebe09beb451917663d47232488f23a117fc97720f1e7", 16); BigInteger bi_d = new BigInteger("4adf2f7a89da93248509347d2ae506d683dd3a16357e859a980c4f77a4e2f7a01fae289f13a851df6e9db5adaa60bfd2b162bbbe31f7c8f828261a6839311929d2cef4f864dde65e556ce43c89bbbf9f1ac5511315847ce9cc8dc92470a747b8792d6a83b0092d2e5ebaf852c85cacf34278efa99160f2f8aa7ee7214de07b7", 16); BigInteger bi_n = new BigInteger("e8e77781f36a7b3188d711c2190b560f205a52391b3479cdb99fa010745cbeba5f2adc08e1de6bf38398a0487c4a73610d94ec36f17f3f46ad75e17bc1adfec99839589f45f95ccc94cb2a5c500b477eb3323d8cfab0c8458c96f0147a45d27e45a4d11d54d77684f65d48f15fafcc1ba208e71e921b9bd9017c16a5231af7f", 16); Console.WriteLine("e =\n" + bi_e.ToString(10)); Console.WriteLine("\nd =\n" + bi_d.ToString(10)); Console.WriteLine("\nn =\n" + bi_n.ToString(10) + "\n"); for (int count = 0; count < rounds; count++) { // generate data of random length int t1 = 0; while (t1 == 0) t1 = (int)(rand.NextDouble() * 65); bool done = false; while (!done) { for (int i = 0; i < 64; i++) { if (i < t1) val[i] = (byte)(rand.NextDouble() * 256); else val[i] = 0; if (val[i] != 0) done = true; } } while (val[0] == 0) val[0] = (byte)(rand.NextDouble() * 256); Console.Write("Round = " + count); // encrypt and decrypt data BigInteger bi_data = new BigInteger(val, t1); BigInteger bi_encrypted = bi_data.modPow(bi_e, bi_n); BigInteger bi_decrypted = bi_encrypted.modPow(bi_d, bi_n); // compare if (bi_decrypted != bi_data) { Console.WriteLine("\nError at round " + count); Console.WriteLine(bi_data + "\n"); return; } Console.WriteLine(" <PASSED>."); } }