//*********************************************************************** // Probabilistic prime test based on Solovay-Strassen (Euler Criterion) // // p is probably prime if for any a < p (a is not multiple of p), // a^((p-1)/2) mod p = J(a, p) // // where J is the Jacobi symbol. // // Otherwise, p is composite. // // Returns // ------- // True if "this" is a Euler pseudoprime to randomly chosen // bases. The number of chosen bases is given by the "confidence" // parameter. // // False if "this" is definitely NOT prime. // //*********************************************************************** public bool SolovayStrassenTest(int confidence) { BigInteger thisVal; if((this.data[maxLength-1] & 0x80000000) != 0) // negative thisVal = -this; else thisVal = this; if(thisVal.dataLength == 1) { // test small numbers 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) // even numbers return false; int bits = thisVal.bitCount(); BigInteger a = new BigInteger(); BigInteger p_sub1 = thisVal - 1; BigInteger p_sub1_shift = p_sub1 >> 1; Random rand = new Random(); for(int round = 0; round < confidence; round++) { bool done = false; while(!done) // generate a < n { int testBits = 0; // make sure "a" has at least 2 bits while(testBits < 2) testBits = (int)(rand.NextDouble() * bits); a.genRandomBits(testBits, rand); int byteLen = a.dataLength; // make sure "a" is not 0 if(byteLen > 1 || (byteLen == 1 && a.data[0] != 1)) done = true; } // check whether a factor exists (fix for version 1.03) BigInteger gcdTest = a.gcd(thisVal); if(gcdTest.dataLength == 1 && gcdTest.data[0] != 1) return false; // calculate a^((p-1)/2) mod p BigInteger expResult = a.modPow(p_sub1_shift, thisVal); if(expResult == p_sub1) expResult = -1; // calculate Jacobi symbol BigInteger jacob = Jacobi(a, thisVal); //Console.WriteLine("a = " + a.ToString(10) + " b = " + thisVal.ToString(10)); //Console.WriteLine("expResult = " + expResult.ToString(10) + " Jacob = " + jacob.ToString(10)); // if they are different then it is not prime if(expResult != jacob) return false; } return true; }
//*********************************************************************** // Probabilistic prime test based on Rabin-Miller's // // for any p > 0 with p - 1 = 2^s * t // // p is probably prime (strong pseudoprime) if for any a < p, // 1) a^t mod p = 1 or // 2) a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1 // // Otherwise, p is composite. // // Returns // ------- // True if "this" is a strong pseudoprime to randomly chosen // bases. The number of chosen bases is given by the "confidence" // parameter. // // False if "this" is definitely NOT prime. // //*********************************************************************** public bool RabinMillerTest(int confidence) { BigInteger thisVal; if((this.data[maxLength-1] & 0x80000000) != 0) // negative thisVal = -this; else thisVal = this; if(thisVal.dataLength == 1) { // test small numbers 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) // even numbers return false; // calculate values of s and t BigInteger p_sub1 = thisVal - (new BigInteger(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; // to break the outer loop break; } mask <<= 1; s++; } } BigInteger t = p_sub1 >> s; int bits = thisVal.bitCount(); BigInteger a = new BigInteger(); Random rand = new Random(); for(int round = 0; round < confidence; round++) { bool done = false; while(!done) // generate a < n { int testBits = 0; // make sure "a" has at least 2 bits while(testBits < 2) testBits = (int)(rand.NextDouble() * bits); a.genRandomBits(testBits, rand); int byteLen = a.dataLength; // make sure "a" is not 0 if(byteLen > 1 || (byteLen == 1 && a.data[0] != 1)) done = true; } // check whether a factor exists (fix for version 1.03) BigInteger gcdTest = a.gcd(thisVal); if(gcdTest.dataLength == 1 && gcdTest.data[0] != 1) return false; BigInteger b = a.modPow(t, thisVal); /* Console.WriteLine("a = " + a.ToString(10)); Console.WriteLine("b = " + b.ToString(10)); Console.WriteLine("t = " + t.ToString(10)); Console.WriteLine("s = " + s); */ 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 for some 0 <= j <= s-1 { result = true; break; } b = (b * b) % thisVal; } if(result == false) return false; } return true; }
/** * <summary> * verarbeite die eingehende Nachricht * </summary> * <param name="in"> eingehende Nachricht als array.</param> * <param name="inOff"> der Zeiger auf das erste Inhaltsemelent.</param> * <param name="inLen> die Anzahl der Zeichen welche verarbeitet werden sollen.</param> * <returns> gibt die ver- bzw. entschlüsselte Nachricht zurück.</returns> * <exception cref="sl.crypto.elgamal.exceptions.DataLengthException"> die eingehende Nachricht ist zu lang.</exception> */ public byte[] processBlock(byte[] input, int inOff, int inLen) { if (inLen > (getInputBlockSize() + 1)) { throw new DataLengthException("Nachricht zu groß für diesen ElGamal Schlüssel.\n"); } else if (inLen == (getInputBlockSize() + 1) && (input[inOff] & 0x80) != 0) { throw new DataLengthException("Nachricht zu groß für diesen ElGamal Schlüssel.\n"); } byte[] block; if (inOff != 0 || inLen != input.Length) { block = new byte[inLen]; Array.Copy(input, inOff, block, 0, inLen); } else { block = input; } BigInteger g = key.Parameter.G; BigInteger p = key.Parameter.P; if (key is PrivateKey) { byte[] in1 = new byte[block.Length / 2]; byte[] in2 = new byte[block.Length / 2]; System.Array.Copy(block, 0, in1, 0, in1.Length); System.Array.Copy(block, in1.Length, in2, 0, in2.Length); BigInteger a = new BigInteger(in1); BigInteger b = new BigInteger(in2); PrivateKey priv = (PrivateKey) key; BigInteger m = a.modPow(p - ONE - priv.X,p) * b % p; byte[] output = m.getBytes(); if (output[0] != 0) { return output; } else { byte[] newoutput = new byte[output.Length - 1]; Array.Copy(output, 1, newoutput, 0, newoutput.Length); return newoutput; } } else { PublicKey pub = (PublicKey) key; BigInteger newinput = new BigInteger(block); int pBitLength = p.bitCount(); BigInteger k = new BigInteger(); k.genRandomBits(pBitLength, random); while (k.Equals(ZERO) || (k > (p - TWO))) { k = new BigInteger(); k.genRandomBits(pBitLength, random); } BigInteger a = g.modPow(k, p); BigInteger b = newinput * (pub.Y.modPow(k, p)) % (p); byte[] out1 = a.getBytes(); byte[] out2 = b.getBytes(); byte[] output = new byte[this.getOutputBlockSize()]; if (out1.Length > output.Length / 2) { Array.Copy(out1, 1, output, output.Length / 2 - (out1.Length - 1), out1.Length - 1); } else { Array.Copy(out1, 0, output, output.Length / 2 - out1.Length, out1.Length); } if (out2.Length > output.Length / 2) { Array.Copy(out2, 1, output, output.Length - (out2.Length - 1), out2.Length - 1); } else { Array.Copy(out2, 0, output, output.Length - out2.Length, out2.Length); } return output; } }
//*********************************************************************** // Probabilistic prime test based on Fermat's little theorem // // for any a < p (p does not divide a) if // a^(p-1) mod p != 1 then p is not prime. // // Otherwise, p is probably prime (pseudoprime to the chosen base). // // Returns // ------- // True if "this" is a pseudoprime to randomly chosen // bases. The number of chosen bases is given by the "confidence" // parameter. // // False if "this" is definitely NOT prime. // // Note - this method is fast but fails for Carmichael numbers except // when the randomly chosen base is a factor of the number. // //*********************************************************************** public bool FermatLittleTest(int confidence) { BigInteger thisVal; if((this.data[maxLength-1] & 0x80000000) != 0) // negative thisVal = -this; else thisVal = this; if(thisVal.dataLength == 1) { // test small numbers 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) // even numbers return false; int bits = thisVal.bitCount(); BigInteger a = new BigInteger(); BigInteger p_sub1 = thisVal - (new BigInteger(1)); Random rand = new Random(); for(int round = 0; round < confidence; round++) { bool done = false; while(!done) // generate a < n { int testBits = 0; // make sure "a" has at least 2 bits while(testBits < 2) testBits = (int)(rand.NextDouble() * bits); a.genRandomBits(testBits, rand); int byteLen = a.dataLength; // make sure "a" is not 0 if(byteLen > 1 || (byteLen == 1 && a.data[0] != 1)) done = true; } // check whether a factor exists (fix for version 1.03) BigInteger gcdTest = a.gcd(thisVal); if(gcdTest.dataLength == 1 && gcdTest.data[0] != 1) return false; // calculate a^(p-1) mod p BigInteger expResult = a.modPow(p_sub1, thisVal); int resultLen = expResult.dataLength; // is NOT prime is a^(p-1) mod p != 1 if(resultLen > 1 || (resultLen == 1 && expResult.data[0] != 1)) { //Console.WriteLine("a = " + a.ToString()); return false; } } return true; }
/** * <summary> * finde eine sichere große Primzahl p und eine primitive Wurzel g mit den * angegebenen Parametern * </summary> */ private void generateParameters() { BigInteger g, p, q; int qLength = size - 1; // finde eine sichere große Primzahl p durch 2*q + 1, q ist ebenfalls eine Primzahl while(true) { q = new BigInteger(); q.genRandomBits(qLength,random); if (q.bitCount() != qLength) { continue; } if (!q.isProbablePrime(certainty)) { continue; } p = q*(TWO)+(ONE); if (p.isProbablePrime(certainty)) { break; } } this.p=p; // berechne g durch 2q+1while(true) while(true) { g = new BigInteger(); g.genRandomBits(qLength, random); if (g.modPow(TWO, p).Equals(ONE)) { continue; } if (g.modPow(q, p).Equals(ONE)) { continue; } break; } this.g=g; }