//*************************************************************************************** //*************************************************************************************** /// <summary> /// Генерирует положительный BigInt32. С большой вероятностью простое.+ /// </summary> public static BigInt32 GetPseudoPrime(int bits, int confidence, Random rand) { BigInt32 result = new BigInt32(); bool done = false; while (!done) { result.GetRandomBits(bits, rand); result.data[0] = 0x01; // делает сгенерированное число нечетным done = result.RabinMillerTest(confidence); //проверяем на простоту } return(result); }
/// <summary> /// Конструктор. Генерирует и проверяет ключи. /// </summary> public RSA() { Random uy = new Random(); const int KeyOFLenght = 128; // Длина p и q BigInt32 p = BigInt32.GetPseudoPrime(KeyOFLenght, 10, uy); BigInt32 q = BigInt32.GetPseudoPrime(KeyOFLenght - 1, 10, uy); //Console.WriteLine("q = {0}, p = {1}", q, p); n = p * q; //Console.WriteLine("n= {0}", n); p--; q--; BigInt32 w = p * q; // функция Эйлера e = new BigInt32(); // открытый ключ do { e.GetRandomBits(KeyOFLenght * 2, uy); }while (BigInt32.NOD(e, w) != 1 && (e > n)); d = BigInt32.Inverse(e, w); // d - закрытый ключ (обратный к е по модулю w) } // d - существует <=> НОД(e,w) = 1
/// <summary> /// Вероятностный тест на простоту основанный на алгоритме Милера-Рабина /// Для любого p > 0, при p - 1 = 2^s * t /// p вероятно простое для любого a < p, /// 1) a^t mod p = 1 или /// 2) a^((2^j)*t) mod p = p-1 для некоторого 0 <= j <= s-1 /// </summary> public bool RabinMillerTest(int confidence) { BigInt32 thisVal = this; if (thisVal.dataLength == 1) { // для малых значений if (thisVal.data[0] == 0 || thisVal.data[0] == 1) { return(false); } else if (thisVal.data[0] == 2 || thisVal.data[0] == 3) { return(true); } } if ((thisVal.data[0] & 0x1) == 0) // четное число { return(false); } // Вычислим значение s и t BigInt32 p_sub1 = thisVal - (new BigInt32(1)); // р-1 int s = 0; for (int index = 0; index < p_sub1.dataLength; index++) { uint mask = 0x01; for (int i = 0; i < 32; i++) { if ((p_sub1.data[index] & mask) != 0) { index = p_sub1.dataLength; // разбить внутренний цикл break; } mask <<= 1; s++; } } BigInt32 t = p_sub1 >> s; int bits = thisVal.bitCount(); BigInt32 a = new BigInt32(); Random rand = new Random(); for (int round = 0; round < confidence; round++) { bool done = false; while (!done) // генерирует a < n { int testBits = 0; while (testBits < 2) { testBits = (int)(rand.NextDouble() * bits); } a.GetRandomBits(testBits, rand); int byteLen = a.dataLength; if (byteLen > 1 || (byteLen == 1 && a.data[0] != 1)) // убедиться, что а != 0 { done = true; } } // проверка является ли а свидетелем простоты BigInt32 gcdTest = a.gcd(thisVal); if (gcdTest.dataLength == 1 && gcdTest.data[0] != 1) { return(false); } BigInt32 b = a.modPow(t, thisVal); bool result = false; if (b.dataLength == 1 && b.data[0] == 1) // a^t mod p = 1 { result = true; } for (int j = 0; result == false && j < s; j++) { if (b == p_sub1) // a^((2^j)*t) mod p = p-1 для 0 <= j <= s-1 { result = true; break; } b = (b * b) % thisVal; } if (result == false) { return(false); } } return(true); }