internal void MakeRSAKeys() { int ShowBits = (PrimeIndex + 1) * 32; // int TestLoops = 0; Worker.ReportProgress(0, "Making RSA keys."); Worker.ReportProgress(0, "Bits size is: " + ShowBits.ToString()); // ulong Loops = 0; while (true) { if (Worker.CancellationPending) { return; } Thread.Sleep(1); // Let other things run. // Make two prime factors. // Normally you'd only make new primes when you pay the Certificate // Authority for a new certificate. if (!MakeAPrime(PrimeP, PrimeIndex, 20)) { return; } if (Worker.CancellationPending) { return; } if (!MakeAPrime(PrimeQ, PrimeIndex, 20)) { return; } if (Worker.CancellationPending) { return; } // This is extremely unlikely. Integer Gcd = new Integer(); IntMath.GreatestCommonDivisor(PrimeP, PrimeQ, Gcd); if (!Gcd.IsOne()) { Worker.ReportProgress(0, "They had a GCD: " + IntMath.ToString10(Gcd)); continue; } if (Worker.CancellationPending) { return; } IntMath.GreatestCommonDivisor(PrimeP, PubKeyExponent, Gcd); if (!Gcd.IsOne()) { Worker.ReportProgress(0, "They had a GCD with PubKeyExponent: " + IntMath.ToString10(Gcd)); continue; } if (Worker.CancellationPending) { return; } IntMath.GreatestCommonDivisor(PrimeQ, PubKeyExponent, Gcd); if (!Gcd.IsOne()) { Worker.ReportProgress(0, "2) They had a GCD with PubKeyExponent: " + IntMath.ToString10(Gcd)); continue; } // For Modular Reduction. This only has to be done // once, when P and Q are made. IntMathForP.ModReduction.SetupGeneralBaseArray(PrimeP); IntMathForQ.ModReduction.SetupGeneralBaseArray(PrimeQ); PrimePMinus1.Copy(PrimeP); IntMath.SubtractULong(PrimePMinus1, 1); PrimeQMinus1.Copy(PrimeQ); IntMath.SubtractULong(PrimeQMinus1, 1); if (Worker.CancellationPending) { return; } // These checks should be more thorough to // make sure the primes P and Q are numbers // that can be used in a secure way. Worker.ReportProgress(0, "The Index of Prime P is: " + PrimeP.GetIndex().ToString()); Worker.ReportProgress(0, "Prime P:"); Worker.ReportProgress(0, IntMath.ToString10(PrimeP)); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Prime Q:"); Worker.ReportProgress(0, IntMath.ToString10(PrimeQ)); Worker.ReportProgress(0, " "); PubKeyN.Copy(PrimeP); IntMath.Multiply(PubKeyN, PrimeQ); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "PubKeyN:"); Worker.ReportProgress(0, IntMath.ToString10(PubKeyN)); Worker.ReportProgress(0, " "); // Test Division: Integer QuotientTest = new Integer(); Integer RemainderTest = new Integer(); IntMath.Divider.Divide(PubKeyN, PrimeP, QuotientTest, RemainderTest); if (!RemainderTest.IsZero()) { throw(new Exception("RemainderTest should be zero after divide by PrimeP.")); } IntMath.Multiply(QuotientTest, PrimeP); if (!QuotientTest.IsEqual(PubKeyN)) { throw(new Exception("QuotientTest didn't come out right.")); } // Euler's Theorem: // https://en.wikipedia.org/wiki/Euler's_theorem // ========== // Work on the Least Common Multiple thing for // P - 1 and Q - 1. // ===== IntMath.GreatestCommonDivisor(PrimePMinus1, PrimeQMinus1, Gcd); Worker.ReportProgress(0, "GCD of PrimePMinus1, PrimeQMinus1 is: " + IntMath.ToString10(Gcd)); if (!Gcd.IsULong()) { Worker.ReportProgress(0, "This GCD number is too big: " + IntMath.ToString10(Gcd)); continue; } else { ulong TooBig = Gcd.GetAsULong(); // How big of a GCD is too big? // ============== if (TooBig > 1234567) { // (P - 1)(Q - 1) + (P - 1) + (Q - 1) = PQ - 1 Worker.ReportProgress(0, "This GCD number is bigger than 1234567: " + IntMath.ToString10(Gcd)); continue; } } Integer Temp1 = new Integer(); PhiN.Copy(PrimePMinus1); Temp1.Copy(PrimeQMinus1); IntMath.Multiply(PhiN, Temp1); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "PhiN:"); Worker.ReportProgress(0, IntMath.ToString10(PhiN)); Worker.ReportProgress(0, " "); if (Worker.CancellationPending) { return; } // In RFC 2437 there are commonly used letters/symbols to represent // the numbers used. So the number e is the public exponent. // The number e that is used here is called PubKeyExponentUint = 65537. // In the RFC the private key d is the multiplicative inverse of // e mod PhiN. Which is mod (P - 1)(Q - 1). It's called // PrivKInverseExponent here. if (!IntMath.FindMultiplicativeInverseSmall(PrivKInverseExponent, PubKeyExponent, PhiN, Worker)) { return; } if (PrivKInverseExponent.IsZero()) { continue; } Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "PrivKInverseExponent: " + IntMath.ToString10(PrivKInverseExponent)); if (Worker.CancellationPending) { return; } // In RFC 2437 it defines a number dP which is the multiplicative // inverse, mod (P - 1) of e. That dP is named PrivKInverseExponentDP here. Worker.ReportProgress(0, " "); if (!IntMath.FindMultiplicativeInverseSmall(PrivKInverseExponentDP, PubKeyExponent, PrimePMinus1, Worker)) { return; } Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "PrivKInverseExponentDP: " + IntMath.ToString10(PrivKInverseExponentDP)); if (PrivKInverseExponentDP.IsZero()) { continue; } // PrivKInverseExponentDP is PrivKInverseExponent mod PrimePMinus1. Integer Test1 = new Integer(); Test1.Copy(PrivKInverseExponent); IntMath.Divider.Divide(Test1, PrimePMinus1, Quotient, Remainder); Test1.Copy(Remainder); if (!Test1.IsEqual(PrivKInverseExponentDP)) { throw(new Exception("This does not match the definition of PrivKInverseExponentDP.")); } if (Worker.CancellationPending) { return; } // In RFC 2437 it defines a number dQ which is the multiplicative // inverse, mod (Q - 1) of e. That dQ is named PrivKInverseExponentDQ here. Worker.ReportProgress(0, " "); if (!IntMath.FindMultiplicativeInverseSmall(PrivKInverseExponentDQ, PubKeyExponent, PrimeQMinus1, Worker)) { return; } if (PrivKInverseExponentDQ.IsZero()) { continue; } Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "PrivKInverseExponentDQ: " + IntMath.ToString10(PrivKInverseExponentDQ)); if (Worker.CancellationPending) { return; } Test1.Copy(PrivKInverseExponent); IntMath.Divider.Divide(Test1, PrimeQMinus1, Quotient, Remainder); Test1.Copy(Remainder); if (!Test1.IsEqual(PrivKInverseExponentDQ)) { throw(new Exception("This does not match the definition of PrivKInverseExponentDQ.")); } // Make a random number to test encryption/decryption. Integer ToEncrypt = new Integer(); int HowManyBytes = PrimeIndex * 4; byte[] RandBytes = MakeRandomBytes(HowManyBytes); if (RandBytes == null) { Worker.ReportProgress(0, "Error making random bytes in MakeRSAKeys()."); return; } if (!ToEncrypt.MakeRandomOdd(PrimeIndex - 1, RandBytes)) { Worker.ReportProgress(0, "Error making random number ToEncrypt."); return; } Integer PlainTextNumber = new Integer(); PlainTextNumber.Copy(ToEncrypt); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Before encrypting number: " + IntMath.ToString10(ToEncrypt)); Worker.ReportProgress(0, " "); IntMath.ModReduction.ModularPower(ToEncrypt, PubKeyExponent, PubKeyN, false); if (Worker.CancellationPending) { return; } // Worker.ReportProgress( 0, IntMath.GetStatusString() ); Integer CipherTextNumber = new Integer(); CipherTextNumber.Copy(ToEncrypt); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Encrypted number: " + IntMath.ToString10(CipherTextNumber)); Worker.ReportProgress(0, " "); ECTime DecryptTime = new ECTime(); DecryptTime.SetToNow(); IntMath.ModReduction.ModularPower(ToEncrypt, PrivKInverseExponent, PubKeyN, false); Worker.ReportProgress(0, "Decrypted number: " + IntMath.ToString10(ToEncrypt)); if (!PlainTextNumber.IsEqual(ToEncrypt)) { throw(new Exception("PlainTextNumber not equal to unencrypted value.")); // Because P or Q wasn't really a prime? // Worker.ReportProgress( 0, "PlainTextNumber not equal to unencrypted value." ); // continue; } Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Decrypt time seconds: " + DecryptTime.GetSecondsToNow().ToString("N2")); Worker.ReportProgress(0, " "); if (Worker.CancellationPending) { return; } // Test the standard optimized way of decrypting: if (!ToEncrypt.MakeRandomOdd(PrimeIndex - 1, RandBytes)) { Worker.ReportProgress(0, "Error making random number in MakeRSAKeys()."); return; } PlainTextNumber.Copy(ToEncrypt); IntMath.ModReduction.ModularPower(ToEncrypt, PubKeyExponent, PubKeyN, false); if (Worker.CancellationPending) { return; } CipherTextNumber.Copy(ToEncrypt); // QInv is the multiplicative inverse of PrimeQ mod PrimeP. if (!IntMath.MultiplicativeInverse(PrimeQ, PrimeP, QInv, Worker)) { throw(new Exception("MultiplicativeInverse() returned false.")); } if (QInv.IsNegative) { throw(new Exception("QInv is negative.")); } Worker.ReportProgress(0, "QInv is: " + IntMath.ToString10(QInv)); DecryptWithQInverse(CipherTextNumber, ToEncrypt, // Decrypt it to this. PlainTextNumber, // Test it against this. PubKeyN, PrivKInverseExponentDP, PrivKInverseExponentDQ, PrimeP, PrimeQ, Worker); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Found the values:"); Worker.ReportProgress(0, "Seconds: " + StartTime.GetSecondsToNow().ToString("N0")); Worker.ReportProgress(0, " "); Worker.ReportProgress(1, "Prime1: " + IntMath.ToString10(PrimeP)); Worker.ReportProgress(0, " "); Worker.ReportProgress(1, "Prime2: " + IntMath.ToString10(PrimeQ)); Worker.ReportProgress(0, " "); Worker.ReportProgress(1, "PubKeyN: " + IntMath.ToString10(PubKeyN)); Worker.ReportProgress(0, " "); Worker.ReportProgress(1, "PrivKInverseExponent: " + IntMath.ToString10(PrivKInverseExponent)); // return; // Comment this out to just leave it while( true ) for testing. } }
private bool MakeAPrime(Integer Result, int SetToIndex, int HowMany) { try { int Attempts = 0; while (true) { Attempts++; if (Worker.CancellationPending) { return(false); } // Let other things run on my cheap laptop. Thread.Sleep(1); int HowManyBytes = (SetToIndex * 4) + 4; byte[] RandBytes = MakeRandomBytes(HowManyBytes); if (RandBytes == null) { Worker.ReportProgress(0, "Error making random bytes in MakeAPrime()."); return(false); } if (!Result.MakeRandomOdd(SetToIndex, RandBytes)) { Worker.ReportProgress(0, "Error making random number in MakeAPrime()."); return(false); } // Make sure that it's the size I think it is. if (Result.GetIndex() < SetToIndex) { throw(new Exception("The size of the random prime is not right.")); } uint TestPrime = IntMath.IsDivisibleBySmallPrime(Result); if (0 != TestPrime) { continue; } if (!IntMath.IsFermatPrime(Result, HowMany)) { Worker.ReportProgress(0, "Did not pass Fermat test."); continue; } // IsFermatPrime() could take a long time. if (Worker.CancellationPending) { return(false); } Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Found a probable prime."); Worker.ReportProgress(0, "Attempts: " + Attempts.ToString()); Worker.ReportProgress(0, " "); return(true); // With Result. } } catch (Exception Except) { Worker.ReportProgress(0, "Error in MakeAPrime()"); Worker.ReportProgress(0, Except.Message); return(false); } }