/// <summary> /// Secret key operation. Decrypts biCipher with the keydata /// in the given secret key packet. /// </summary> /// <param name="biCipher">The ciphertext that is about to /// be decrypted</param> /// <param name="skpKey">The secret key packet with the key /// material for the decryption</param> /// <param name="strPassphrase">The passphrase for the /// keymaterial</param> /// <returns>The decrypted ciphertext.</returns> /// <remarks>No remarks.</remarks> public override BigInteger Decrypt(BigInteger[] biCipher, SecretKeyPacket skpKey, string strPassphrase) { RSA_Secret_Key skey = new RSA_Secret_Key(); skey = ParseSecretKey(skpKey, strPassphrase); //check if someone mangled with the key if (!CheckKey(skey)) throw(new Exception("This key does not fullfill the requirements of a valid RSA key. Please check if someone messed with your keys!")); if ((skey.d == 0) || (skey.n == 0)) throw new System.ArgumentException("This is not a valid secret key"); BigInteger biPlain = biCipher[0].modPow(skey.d, skey.n); return biPlain; }
/// <summary> /// Secret key operation. Decrypts biCipher with the keydata /// in the given secret key packet. /// </summary> /// <param name="biInput">The ciphertext that is about to /// be decrypted</param> /// <param name="skpKey">The secret key packet with the key /// material for the decryption</param> /// <param name="strPassphrase">The passphrase for the /// keymaterial</param> /// <returns>The decrypted ciphertext.</returns> /// <remarks>No remarks.</remarks> public override BigInteger Decrypt(BigInteger[] biInput, SecretKeyPacket skpKey, string strPassphrase) { BigInteger[] biKeyMaterial = skpKey.GetDecryptedKeyMaterial(strPassphrase); EG_Secret_Key eskKey = new EG_Secret_Key(); eskKey.x = biKeyMaterial[0]; eskKey.p = skpKey.PublicKey.KeyMaterial[0]; eskKey.g = skpKey.PublicKey.KeyMaterial[1]; eskKey.y = skpKey.PublicKey.KeyMaterial[2]; if (biInput.Length != 2) throw new ArgumentException("biInput is not an ElGamal encrypted Packet"); BigInteger B = biInput[0]; BigInteger c = biInput[1]; BigInteger z = B.modPow(eskKey.x, eskKey.p).modInverse(eskKey.p); BigInteger output = (z * c) % eskKey.p; return output; }
/// <summary> /// Decryption is not supported for DSA. If you call this function, /// an Exception will be thrown. /// </summary> /// <remarks> /// Decryption is not supported for DSA. If you call this function, /// an Exception will be thrown. /// </remarks> public override BigInteger Decrypt(BigInteger[] biCipher, SecretKeyPacket spkKey, string strPassphrase) { throw(new Exception("The DSA cipher cannot be used for encryption/decryption")); }
private BigInteger[] ParsePublicKey(DSA_Public_Key dpkKey) { BigInteger[] biReturn = new BigInteger[4]; biReturn[0] = dpkKey.p; biReturn[1] = dpkKey.q; biReturn[2] = dpkKey.g; biReturn[3] = dpkKey.y; return biReturn; }
// this part is quite fast private DSA_Secret_Key GenerateKeyPair(DSA_Secret_Key dskKey) { dskKey.x = new BigInteger(); do { // size of x (private key) isn't affected by the keysize (512-1024) dskKey.x = BigInteger.genRandom(160); BigInteger xx = new BigInteger(); } while ((dskKey.x == 0) || (dskKey.x >= dskKey.q)); // calculate the public key y = g^x % p dskKey.y = dskKey.g.modPow(dskKey.x, dskKey.p); return dskKey; }
/// <summary> /// Secret key operation. Signs biHash with the keydata /// in the given secret key packet. /// </summary> /// <param name="biHash">The hash value of a message that is about to /// be signed</param> /// <param name="skpKey">The secret key packet with the key /// material for the signature</param> /// <param name="strPassphrase">The passphrase for the /// keymaterial</param> /// <returns>The signed hash as array of biginteger. Only return[0] /// contains a value: the signed hash.</returns> /// <remarks>No remarks</remarks> public override BigInteger[] Sign(BigInteger biHash, SecretKeyPacket skpKey, string strPassphase) { DSA_Secret_Key dskKey = new DSA_Secret_Key(); dskKey = ParseSecretKey(skpKey, strPassphase); //check if the key has been mangled with if (!CheckKey(dskKey)) throw(new Exception("This key does not fullfill the requirements of a valid DSA key. Please check if someone messed with your keys!")); //if (biHash == null) // throw new ArgumentNullException(); // (a) Select a random secret integer k; 0 < k < q. BigInteger k = new BigInteger(); k = BigInteger.genRandom(160); while (k >= dskKey.q) k = BigInteger.genRandom(160); // (b) Compute r = ( k mod p) mod q BigInteger r = (dskKey.g.modPow (k, dskKey.p)) % dskKey.q; // (c) Compute k -1 mod q (e.g., using Algorithm 2.142). // (d) Compute s = k -1 fh(m) +arg mod q. BigInteger s = (k.modInverse (dskKey.q) * (biHash + dskKey.x * r)) % dskKey.q; BigInteger[] biReturn = new BigInteger[2]; biReturn[0] = r; biReturn[1] = s; return biReturn; }
/// <summary> /// Verifies the data given as parameter with the given public key. /// </summary> /// <remarks> /// <para>The function calculates a message digest over the given signature /// data and verifies the digest with the digest stored in the /// signature packet.</para> /// <para>The results of the verify operation are directly stored /// in the SignatureStatus property of this class.</para> /// </remarks> /// <param name="bSignedData">The data that is to be verified.</param> /// <param name="pkpKey">The key that is to verify the signature</param> public void Verify(byte[] bSignedData, PublicKeyPacket pkpKey) { System.Security.Cryptography.HashAlgorithm haVerifyer; AsymmetricCipher acVerifyer; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: haVerifyer = System.Security.Cryptography.MD5.Create(); break; case HashAlgorithms.SHA1: haVerifyer = System.Security.Cryptography.SHA1.Create(); break; default: throw(new System.Exception("Currently only MD5 and SHA1 are implemented as hash algorithms!")); } switch (this.SignatureAlgorithm) { case AsymAlgorithms.DSA: acVerifyer = new SharpPrivacy.SharpPrivacyLib.Cipher.DSA(); break; case AsymAlgorithms.RSA_Encrypt_Sign: case AsymAlgorithms.RSA_Sign_Only: acVerifyer = new SharpPrivacy.SharpPrivacyLib.Cipher.RSA(); break; default: throw(new System.Exception("Currently only DSA and RSA are implemented as signature algorithms!")); } byte[] bSignature = new byte[0]; int iCounter = 0; if (this.Version <= SignaturePacketVersionNumbers.v3) { bSignature = new byte[5]; bSignature[iCounter++] = (byte)this.SignatureType; long lTime = (dtTimeCreated.Ticks - new DateTime(1970, 1, 1).Ticks)/10000000; bSignature[iCounter++] = (byte)((lTime >> 24) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 16) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lTime & 0xFF); } else { //Hashed Subpackets Length int lHashedSubPacketLength = 0; for (int i=0; i<this.HashedSubPackets.Length; i++) { lHashedSubPacketLength += this.HashedSubPackets[i].Generate().Length; } bSignature = new byte[lHashedSubPacketLength + 12]; bSignature[iCounter++] = 4; // Version bSignature[iCounter++] = (byte)this.SignatureType; bSignature[iCounter++] = (byte)this.SignatureAlgorithm; bSignature[iCounter++] = (byte)this.HashAlgorithm; //Hashed Subpackets bSignature[iCounter++] = (byte)((lHashedSubPacketLength >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lHashedSubPacketLength & 0xFF); for (int i=0; i<this.HashedSubPackets.Length; i++) { byte[] bSubPacket = this.HashedSubPackets[i].Generate(); Array.Copy(bSubPacket, 0, bSignature, iCounter, bSubPacket.Length); iCounter += bSubPacket.Length; } //Final Trailer of 6 bytes bSignature[iCounter++] = 0x04; bSignature[iCounter++] = 0xFF; bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 24) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 16) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 8) & 0xFF); bSignature[iCounter++] = (byte)((lHashedSubPacketLength+6) & 0xFF); } byte[] bData = new byte[bSignedData.Length + bSignature.Length]; Array.Copy(bSignedData, bData, bSignedData.Length); Array.Copy(bSignature, 0, bData, bSignedData.Length, bSignature.Length); byte[] bHash = haVerifyer.ComputeHash(bData); BigInteger biHash = new BigInteger(bHash); //PKCS1 Encode the hash if (this.SignatureAlgorithm != AsymAlgorithms.DSA) { // We encode the MD in this way: // 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) // PAD consists of FF bytes. byte[] bASN = new byte[0]; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: bASN = new byte[] {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}; break; case HashAlgorithms.SHA1: bASN = new byte[] {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14}; break; } int iFrameSize = (pkpKey.KeyMaterial[0].bitCount() + 7) / 8; byte[] bFrame = new byte[iFrameSize]; int iASNCounter = 0; bFrame[iASNCounter++] = 0; bFrame[iASNCounter++] = 1; int iFFLength = iFrameSize - bHash.Length - bASN.Length - 3; for (int i=0; i<iFFLength; i++) { bFrame[iASNCounter++] = 0xFF; } bFrame[iASNCounter++] = 0; Array.Copy(bASN, 0, bFrame, iASNCounter, bASN.Length); iASNCounter += bASN.Length; Array.Copy(bHash, 0, bFrame, iASNCounter, bHash.Length); biHash = new BigInteger(bFrame); } if (acVerifyer.Verify(this.Signature, biHash, pkpKey)) { ssSignatureStatus = SignatureStatusTypes.Valid; } else { ssSignatureStatus = SignatureStatusTypes.Invalid; } }
private unsafe BigInteger OddPow (uint b, BigInteger exp) { exp.Normalize (); uint [] wkspace = new uint [mod.length << 1 + 1]; BigInteger resultNum = Montgomery.ToMont ((BigInteger)b, this.mod); resultNum = new BigInteger (resultNum, mod.length << 1 +1); uint mPrime = Montgomery.Inverse (mod.data [0]); uint pos = (uint)exp.bitCount () - 2; // // We know that the first itr will make the val b // do { // // r = r ^ 2 % m // Kernel.SquarePositive (resultNum, ref wkspace); resultNum = Montgomery.Reduce (resultNum, mod, mPrime); if (exp.testBit (pos)) { // // r = r * b % m // // TODO: Is Unsafe really speeding things up? fixed (uint* u = resultNum.data) { uint i = 0; ulong mc = 0; do { mc += (ulong)u [i] * (ulong)b; u [i] = (uint)mc; mc >>= 32; } while (++i < resultNum.length); if (resultNum.length < mod.length) { if (mc != 0) { u [i] = (uint)mc; resultNum.length++; while (resultNum >= mod) Kernel.MinusEq (resultNum, mod); } } else if (mc != 0) { // // First, we estimate the quotient by dividing // the first part of each of the numbers. Then // we correct this, if necessary, with a subtraction. // uint cc = (uint)mc; // We would rather have this estimate overshoot, // so we add one to the divisor uint divEstimate = (uint) ((((ulong)cc << 32) | (ulong) u [i -1]) / (mod.data [mod.length-1] + 1)); uint t; i = 0; mc = 0; do { mc += (ulong)mod.data [i] * (ulong)divEstimate; t = u [i]; u [i] -= (uint)mc; mc >>= 32; if (u [i] > t) mc++; i++; } while (i < resultNum.length); cc -= (uint)mc; if (cc != 0) { uint sc = 0, j = 0; uint [] s = mod.data; do { uint a = s [j]; if (((a += sc) < sc) | ((u [j] -= a) > ~a)) sc = 1; else sc = 0; j++; } while (j < resultNum.length); cc -= sc; } while (resultNum >= mod) Kernel.MinusEq (resultNum, mod); } else { while (resultNum >= mod) Kernel.MinusEq (resultNum, mod); } } } } while (pos-- > 0); resultNum = Montgomery.Reduce (resultNum, mod, mPrime); return resultNum; }
public BigInteger modPow (BigInteger exp, BigInteger n) { ModulusRing mr = new ModulusRing (n); return mr.Pow (this, exp); }
public BigInteger modInverse (BigInteger mod) { return Kernel.modInverse (this, mod); }
public BigInteger gcd (BigInteger bi) { return Kernel.gcd (this, bi); }
public string ToString (uint radix, string charSet) { if (charSet.Length < radix) throw new ArgumentException ("charSet length less than radix", "charSet"); if (radix == 1) throw new ArgumentException ("There is no such thing as radix one notation", "radix"); if (this == 0) return "0"; if (this == 1) return "1"; string result = ""; BigInteger a = new BigInteger (this); while (a != 0) { uint rem = Kernel.SingleByteDivideInPlace (a, radix); result = charSet [ (int)rem] + result; } return result; }
public Sign Compare (BigInteger bi) { return Kernel.Compare (this, bi); }
/// <summary> /// Generates a new, random BigInteger of the specified length. /// </summary> /// <param name="bits">The number of bits for the new number.</param> /// <param name="rng">A random number generator to use to obtain the bits.</param> /// <returns>A random number of the specified length.</returns> public static BigInteger genRandom (int bits, System.Security.Cryptography.RandomNumberGenerator rng) { int dwords = bits >> 5; int remBits = bits & 0x1F; if (remBits != 0) dwords++; BigInteger ret = new BigInteger (Sign.Positive, (uint)dwords + 1); byte [] random = new byte [dwords << 2]; rng.GetBytes (random); Buffer.BlockCopy (random, 0, ret.data, 0, (int)dwords << 2); if (remBits != 0) { uint mask = (uint)(0x01 << (remBits-1)); ret.data [dwords-1] |= mask; mask = (uint)(0xFFFFFFFF >> (32 - remBits)); ret.data [dwords-1] &= mask; } else ret.data [dwords-1] |= 0x80000000; ret.Normalize (); return ret; }
public static BigInteger operator * (BigInteger bi1, BigInteger bi2) { if (bi1 == 0 || bi2 == 0) return 0; // // Validate pointers // if (bi1.data.Length < bi1.length) throw new IndexOutOfRangeException ("bi1 out of range"); if (bi2.data.Length < bi2.length) throw new IndexOutOfRangeException ("bi2 out of range"); BigInteger ret = new BigInteger (Sign.Positive, bi1.length + bi2.length); Kernel.Multiply (bi1.data, 0, bi1.length, bi2.data, 0, bi2.length, ret.data, 0); ret.Normalize (); return ret; }
private BigInteger OddPow (BigInteger b, BigInteger exp) { BigInteger resultNum = new BigInteger (Montgomery.ToMont (1, mod), mod.length << 1); BigInteger tempNum = new BigInteger (Montgomery.ToMont (b, mod), mod.length << 1); // ensures (tempNum * tempNum) < b^ (2k) uint mPrime = Montgomery.Inverse (mod.data [0]); uint totalBits = (uint)exp.bitCount (); uint [] wkspace = new uint [mod.length << 1]; // perform squaring and multiply exponentiation for (uint pos = 0; pos < totalBits; pos++) { if (exp.testBit (pos)) { Array.Clear (wkspace, 0, wkspace.Length); Kernel.Multiply (resultNum.data, 0, resultNum.length, tempNum.data, 0, tempNum.length, wkspace, 0); resultNum.length += tempNum.length; uint [] t = wkspace; wkspace = resultNum.data; resultNum.data = t; Montgomery.Reduce (resultNum, mod, mPrime); } Kernel.SquarePositive (tempNum, ref wkspace); Montgomery.Reduce (tempNum, mod, mPrime); } Montgomery.Reduce (resultNum, mod, mPrime); return resultNum; }
// TODO: Make tests for this, not really needed b/c prime stuff // checks it, but still would be nice public BigInteger Pow (uint b, BigInteger exp) { if (b != 2) { if ((mod.data [0] & 1) == 1) return OddPow (b, exp); else return EvenPow (b, exp); } else { if ((mod.data [0] & 1) == 1) return OddModTwoPow (exp); else return EvenModTwoPow (exp); } }
/// <summary> /// Generates the smallest prime >= bi /// </summary> /// <param name="bi">A BigInteger</param> /// <returns>The smallest prime >= bi. More mathematically, if bi is prime: bi, else Prime [PrimePi [bi] + 1].</returns> public static BigInteger NextHightestPrime (BigInteger bi) { NextPrimeFinder npf = new NextPrimeFinder (); return npf.GenerateNewPrime (0, bi); }
/// <summary> /// Signes the data given as parameter with the given secret key. /// The given password has to fit the given key. /// </summary> /// <remarks> /// <para>The function calculates a message digest over the given signature /// data and signes the digest with the given key.</para> /// <para>The results of the signature operation are directly stored /// in the Signature property of this class.</para> /// </remarks> /// <param name="bSignedData">The data that is to be signed.</param> /// <param name="skpKey">The key that is to sign the data</param> /// <param name="strPassphrase">The passphrase that is neccessary to /// decrypt the given key.</param> public void Sign(byte[] bSignedData, SecretKeyPacket skpKey, string strPassphrase) { System.Security.Cryptography.HashAlgorithm haSigner; AsymmetricCipher acSigner; this.SignatureAlgorithm = skpKey.PublicKey.Algorithm; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: haSigner = System.Security.Cryptography.MD5.Create(); break; case HashAlgorithms.SHA1: haSigner = System.Security.Cryptography.SHA1.Create(); break; default: throw(new System.Exception("Currently only MD5 and SHA1 are implemented as hash algorithms!")); } switch (this.SignatureAlgorithm) { case AsymAlgorithms.DSA: acSigner = new SharpPrivacy.SharpPrivacyLib.Cipher.DSA(); break; case AsymAlgorithms.RSA_Encrypt_Sign: case AsymAlgorithms.RSA_Sign_Only: acSigner = new SharpPrivacy.SharpPrivacyLib.Cipher.RSA(); break; default: throw(new System.Exception("Currently only DSA and RSA are implemented as signature algorithms!")); } byte[] bSignature = new byte[0]; int iCounter = 0; if (this.Version <= SignaturePacketVersionNumbers.v3) { bSignature = new byte[5]; bSignature[iCounter++] = (byte)this.SignatureType; long lTime = (dtTimeCreated.Ticks - new DateTime(1970, 1, 1).Ticks)/10000000; bSignature[iCounter++] = (byte)((lTime >> 24) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 16) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lTime & 0xFF); } else { // Add Issuer KeyID Subpacket if it's not there. try { ulong lTestForKeyID = this.KeyID; } catch (Exception) { SignatureSubPacket sspIssuerKeyID = new SignatureSubPacket(); sspIssuerKeyID.Type = SignatureSubPacketTypes.IssuerKeyID; sspIssuerKeyID.KeyID = this.lKeyID; this.AddSubPacket(sspIssuerKeyID, true); } // Add TimeCreated Subpacket if it's not there. try { this.FindSignatureCreationTime(); } catch (Exception) { SignatureSubPacket sspCreationTime = new SignatureSubPacket(); sspCreationTime.Type = SignatureSubPacketTypes.SignatureCreationTime; sspCreationTime.TimeCreated = DateTime.Now; this.AddSubPacket(sspCreationTime, true); } //Hashed Subpackets Length int lHashedSubPacketLength = 0; for (int i=0; i<this.HashedSubPackets.Length; i++) { lHashedSubPacketLength += this.HashedSubPackets[i].Generate().Length; } bSignature = new byte[lHashedSubPacketLength + 12]; bSignature[iCounter++] = 4; // Version bSignature[iCounter++] = (byte)this.SignatureType; bSignature[iCounter++] = (byte)this.SignatureAlgorithm; bSignature[iCounter++] = (byte)this.HashAlgorithm; //Hashed bSignature[iCounter++] = (byte)((lHashedSubPacketLength >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lHashedSubPacketLength & 0xFF); for (int i=0; i<this.HashedSubPackets.Length; i++) { byte[] bSubPacket = this.HashedSubPackets[i].Generate(); Array.Copy(bSubPacket, 0, bSignature, iCounter, bSubPacket.Length); iCounter += bSubPacket.Length; } //Final Trailer of 6 bytes bSignature[iCounter++] = 0x04; bSignature[iCounter++] = 0xFF; bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 24) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 16) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 8) & 0xFF); bSignature[iCounter++] = (byte)((lHashedSubPacketLength+6) & 0xFF); } byte[] bData = new byte[bSignedData.Length + bSignature.Length]; Array.Copy(bSignedData, bData, bSignedData.Length); Array.Copy(bSignature, 0, bData, bSignedData.Length, bSignature.Length); byte[] bHash = haSigner.ComputeHash(bData); BigInteger biHash = new BigInteger(bHash); //PKCS1 Encode the hash if (this.SignatureAlgorithm != AsymAlgorithms.DSA) { // We encode the MD in this way: // 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) // PAD consists of FF bytes. byte[] bASN = new byte[0]; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: bASN = new byte[] {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}; break; case HashAlgorithms.SHA1: bASN = new byte[] {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14}; break; } int iFrameSize = (skpKey.PublicKey.KeyMaterial[0].bitCount() + 7) / 8; byte[] bFrame = new byte[iFrameSize]; int iASNCounter = 0; bFrame[iASNCounter++] = 0; bFrame[iASNCounter++] = 1; int iFFLength = iFrameSize - bHash.Length - bASN.Length - 3; for (int i=0; i<iFFLength; i++) bFrame[iASNCounter++] = 0xFF; bFrame[iASNCounter++] = 0; Array.Copy(bASN, 0, bFrame, iASNCounter, bASN.Length); iASNCounter += bASN.Length; Array.Copy(bHash, 0, bFrame, iASNCounter, bHash.Length); biHash = new BigInteger(bFrame); } sSignedHash16Bit = (ushort)((bHash[0] << 8) + bHash[1]); biSignature = acSigner.Sign(biHash, skpKey, strPassphrase); this.bIsUpdated = true; }
public ModulusRing (BigInteger mod) { this.mod = mod; // calculate constant = b^ (2k) / m uint i = mod.length << 1; constant = new BigInteger (Sign.Positive, i + 1); constant.data [i] = 0x00000001; constant = constant / mod; }
/// <summary> /// Creates a new DES secret key and returns it as a /// 2 dimensional array of biginteger. return[0] holds /// the public values of the key and return[1] all the /// secret values. /// </summary> /// <remarks> /// Creates a new DSA secret key and returns it as a /// 2 dimensional array of biginteger. return[0] holds /// the public values of the key and return[1] all the /// secret values.<br></br> /// The order of the public components is p, q, g, y /// The order of the secret components is x. /// </remarks> /// <param name="nbits">The size of the key in bits.</param> /// <returns> a new DSA secret key and returns it as a /// 2 dimensional array of biginteger. return[0] holds /// the public values of the key and return[1] all the /// secret values.<br></br> /// The order of the public components is p, q, g, y /// The order of the secret components is x.</returns> public override BigInteger[][] Generate(int keyLength) { DSA_Secret_Key dskKey = new DSA_Secret_Key(); dskKey = GenerateParams(keyLength); dskKey = GenerateKeyPair(dskKey); biGeneratedKey = new BigInteger[2][]; biGeneratedKey[0] = new BigInteger[4]; biGeneratedKey[0][0] = dskKey.p; biGeneratedKey[0][1] = dskKey.q; biGeneratedKey[0][2] = dskKey.g; biGeneratedKey[0][3] = dskKey.y; biGeneratedKey[1] = new BigInteger[1]; biGeneratedKey[1][0] = dskKey.x; return biGeneratedKey; }
public void BarrettReduction (BigInteger x) { BigInteger n = mod; uint k = n.length, kPlusOne = k+1, kMinusOne = k-1; // x < mod, so nothing to do. if (x.length < k) return; BigInteger q3; // // Validate pointers // if (x.data.Length < x.length) throw new IndexOutOfRangeException ("x out of range"); // q1 = x / b^ (k-1) // q2 = q1 * constant // q3 = q2 / b^ (k+1), Needs to be accessed with an offset of kPlusOne // TODO: We should the method in HAC p 604 to do this (14.45) q3 = new BigInteger (Sign.Positive, x.length - kMinusOne + constant.length); Kernel.Multiply (x.data, kMinusOne, x.length - kMinusOne, constant.data, 0, constant.length, q3.data, 0); // r1 = x mod b^ (k+1) // i.e. keep the lowest (k+1) words uint lengthToCopy = (x.length > kPlusOne) ? kPlusOne : x.length; x.length = lengthToCopy; x.Normalize (); // r2 = (q3 * n) mod b^ (k+1) // partial multiplication of q3 and n BigInteger r2 = new BigInteger (Sign.Positive, kPlusOne); Kernel.MultiplyMod2p32pmod (q3.data, (int)kPlusOne, (int)q3.length - (int)kPlusOne, n.data, 0, (int)n.length, r2.data, 0, (int)kPlusOne); r2.Normalize (); if (r2 < x) { Kernel.MinusEq (x, r2); } else { BigInteger val = new BigInteger (Sign.Positive, kPlusOne + 1); val.data [kPlusOne] = 0x00000001; Kernel.MinusEq (val, r2); Kernel.PlusEq (x, val); } while (x >= n) Kernel.MinusEq (x, n); }
/// <summary> /// Public key operation. Verifies biSignature with the keydata /// in the given public key packet and returns true if the signature /// is valid. /// </summary> /// <param name="biSignature">The signature that is about to /// be verified</param> /// <param name="biHash">The hash value of the signed message.</param> /// <param name="pkpKey">The public key packet with the key /// material for the verification.</param> /// <returns>True if the signature is valid, otherwise /// false</returns> /// <remarks>No remarks</remarks> public override bool Verify(BigInteger[] biSignature, BigInteger biHash, PublicKeyPacket pkpKey) { if (biSignature == null) throw new ArgumentNullException("rgbSignature"); DSA_Public_Key dpkKey = new DSA_Public_Key(); dpkKey = ParsePublicKey(pkpKey); try { BigInteger m = biHash; BigInteger r = biSignature[0]; BigInteger s = biSignature[1]; if ((r < 0) || (dpkKey.q <= r)) return false; if ((s < 0) || (dpkKey.q <= s)) return false; BigInteger w = s.modInverse(dpkKey.q); BigInteger u1 = m * w % dpkKey.q; BigInteger u2 = r * w % dpkKey.q; u1 = dpkKey.g.modPow(u1, dpkKey.p); u2 = dpkKey.y.modPow(u2, dpkKey.p); BigInteger v = ((u1 * u2 % dpkKey.p) % dpkKey.q); return (v == r); } catch { throw new CryptographicException(); } }
public BigInteger Multiply (BigInteger a, BigInteger b) { if (a == 0 || b == 0) return 0; if (a.length >= mod.length << 1) a %= mod; if (b.length >= mod.length << 1) b %= mod; if (a.length >= mod.length) BarrettReduction (a); if (b.length >= mod.length) BarrettReduction (b); BigInteger ret = new BigInteger (a * b); BarrettReduction (ret); return ret; }
private DSA_Secret_Key GenerateParams(int keyLength) { byte[] seed = new byte[20]; byte[] part1 = new byte[20]; byte[] part2 = new byte[20]; byte[] u = new byte[20]; RandomNumberGenerator rng = RandomNumberGenerator.Create(); BigInteger p = new BigInteger(); // prime BigInteger q = new BigInteger(); // group order BigInteger g; // group generator DSA_Secret_Key dskKey = new DSA_Secret_Key(); SHA1 sha = SHA1.Create(); int n = (keyLength - 1) / 160; byte[] w = new byte [keyLength / 8]; bool primesFound = false; while (!primesFound) { do { rng.GetBytes(seed); part1 = sha.ComputeHash(seed); Array.Copy(seed, 0, part2, 0, seed.Length); add(part2, seed, 1); part2 = sha.ComputeHash(part2); for (int i = 0; i != u.Length; i++) u[i] = (byte)(part1[i] ^ part2[i]); // first bit must be set (to respect key length) u[0] |= (byte)0x80; // last bit must be set (prime are all odds - except 2) u[19] |= (byte)0x01; q = new BigInteger(u); } while (!q.isProbablePrime()); int counter = 0; int offset = 2; while (counter < 4096) { for (int k = 0; k < n; k++) { add(part1, seed, offset + k); part1 = sha.ComputeHash(part1); Array.Copy(part1, 0, w, w.Length - (k + 1) * part1.Length, part1.Length); } add(part1, seed, offset + n); part1 = sha.ComputeHash(part1); Array.Copy(part1, part1.Length - ((w.Length - (n) * part1.Length)), w, 0, w.Length - n * part1.Length); w[0] |= (byte)0x80; BigInteger xx = new BigInteger (w); BigInteger c = xx % (q * 2); p = xx - (c - 1); if (p.testBit((uint)(keyLength - 1))) { if (p.isProbablePrime()) { primesFound = true; break; } } counter += 1; offset += n + 1; } } // calculate the generator g BigInteger pMinusOneOverQ = (p - 1) / q; for (;;) { BigInteger h = new BigInteger(); h = BigInteger.genRandom(keyLength); if ((h <= 1) || (h >= (p - 1))) continue; g = h.modPow(pMinusOneOverQ, p); if (g <= 1) continue; break; } dskKey.p = p; dskKey.q = q; dskKey.g = g; return dskKey; }
public BigInteger Difference (BigInteger a, BigInteger b) { Sign cmp = Kernel.Compare (a, b); BigInteger diff; switch (cmp) { case Sign.Zero: return 0; case Sign.Positive: diff = a - b; break; case Sign.Negative: diff = b - a; break; default: throw new Exception (); } if (diff >= mod) { if (diff.length >= mod.length << 1) diff %= mod; else BarrettReduction (diff); } if (cmp == Sign.Negative) diff = mod - diff; return diff; }
private BigInteger[,] ParseSecretKey(DSA_Secret_Key dskKey) { BigInteger[,] biReturn = new BigInteger[2,4]; biReturn[0,0] = dskKey.p; biReturn[0,1] = dskKey.q; biReturn[0,2] = dskKey.g; biReturn[0,3] = dskKey.y; biReturn[1,0] = dskKey.x; return biReturn; }
public BigInteger Pow (BigInteger b, BigInteger exp) { if ((mod.data [0] & 1) == 1) return OddPow (b, exp); else return EvenPow (b, exp); }
/// <summary> /// Encryption is not supported for DSA. If you call this function, /// an Exception will be thrown. /// </summary> /// <remarks> /// Encryption is not supported for DSA. If you call this function, /// an Exception will be thrown. /// </remarks> public override BigInteger[] Encrypt(BigInteger biPlain, PublicKeyPacket pkpKey) { throw(new Exception("The DSA cipher cannot be used for encryption")); }
public BigInteger EvenPow (BigInteger b, BigInteger exp) { BigInteger resultNum = new BigInteger ((BigInteger)1, mod.length << 1); BigInteger tempNum = new BigInteger (b % mod, mod.length << 1); // ensures (tempNum * tempNum) < b^ (2k) uint totalBits = (uint)exp.bitCount (); uint [] wkspace = new uint [mod.length << 1]; // perform squaring and multiply exponentiation for (uint pos = 0; pos < totalBits; pos++) { if (exp.testBit (pos)) { Array.Clear (wkspace, 0, wkspace.Length); Kernel.Multiply (resultNum.data, 0, resultNum.length, tempNum.data, 0, tempNum.length, wkspace, 0); resultNum.length += tempNum.length; uint [] t = wkspace; wkspace = resultNum.data; resultNum.data = t; BarrettReduction (resultNum); } Kernel.SquarePositive (tempNum, ref wkspace); BarrettReduction (tempNum); if (tempNum == 1) { return resultNum; } } return resultNum; }