public override void GenerateKey(ECCurve curve) { curve.Validate(); int keySizeInByted = curve.Prime.Length; KeySize = keySizeInByted * 8; BigInteger prime = Normalize(new BigInteger(curve.Prime), s_modulus), subgroupOrder = Normalize(new BigInteger(curve.Order), s_modulus) / Normalize(new BigInteger(curve.Cofactor), s_modulus), a = Normalize(new BigInteger(curve.A), s_modulus); byte[] privateKey = new byte[keySizeInByted]; BigInteger key; do { StaticRandomNumberGenerator.GetBytes(privateKey); key = Normalize(new BigInteger(privateKey), s_modulus); } while (BigInteger.Zero >= key || key >= subgroupOrder); var basePoint = new BigIntegerPoint(curve.G, s_modulus); ECPoint publicKey = BigIntegerPoint.Multiply(basePoint, key, prime, a).ToECPoint(KeySize); EraseData(ref _privateKey); _curve = curve.Clone(); _publicKey = publicKey; _privateKey = privateKey; _parametersSet = true; }
public static BigIntegerPoint Multiply(BigIntegerPoint point, BigInteger multiplier, BigInteger prime, BigInteger a) { BigIntegerPoint result = point; multiplier--; while (multiplier > BigInteger.Zero) { if ((multiplier % s_two) != BigInteger.Zero) { if ((result.X == point.X) && (result.Y == point.Y)) { result = MultipleTwo(result, prime, a); } else { result = Add(result, point, prime); } multiplier--; } multiplier /= s_two; point = MultipleTwo(point, prime, a); } return(result); }
private static BigIntegerPoint MultipleTwo(BigIntegerPoint value, BigInteger prime, BigInteger a) { BigInteger dy = Normalize(s_three * BigInteger.Pow(value.X, 2) + a, prime), dx = Normalize(s_two * value.Y, prime), lambda = (dy * BigInteger.ModPow(dx, prime - s_two, prime)) % prime, x = Normalize((BigInteger.Pow(lambda, 2) - s_two * value.X) % prime, prime); return(new BigIntegerPoint { X = x, Y = Normalize((lambda * (value.X - x) - value.Y) % prime, prime) }); }
public static BigIntegerPoint Add(BigIntegerPoint left, BigIntegerPoint right, BigInteger prime) { BigInteger dy = Normalize(right.Y - left.Y, prime), dx = Normalize(right.X - left.X, prime), lambda = Normalize((dy * BigInteger.ModPow(dx, prime - s_two, prime)) % prime, prime), x = Normalize((BigInteger.Pow(lambda, 2) - left.X - right.X) % prime, prime); return(new BigIntegerPoint() { X = x, Y = Normalize((lambda * (left.X - x) - left.Y) % prime, prime), }); }
/// <summary> /// Verifies a digital signature against the specified hash value. /// </summary> /// <param name="hash"> /// The hash value of a block of data. /// </param> /// <param name="signature"> /// The digital signature to be verified. /// </param> /// <returns> /// <c>true</c> if the hash value equals the decrypted signature; /// otherwise, <c>false</c>. /// </returns> /// <exception cref="ArgumentNullException"> /// The <paramref name="hash"/> parameter is <c>null</c>. /// -or- /// The <paramref name="signature"/> parameter is <c>null</c>. /// </exception> public override bool VerifyHash(byte[] hash, byte[] signature) { if (hash == null) { throw new ArgumentNullException(nameof(hash)); } if (signature == null) { throw new ArgumentNullException(nameof(signature)); } ThrowIfDisposed(); if (KeySize / 8 != hash.Length) { throw new CryptographicException(string.Format(CultureInfo.CurrentCulture, CryptographicInvalidHashSize, KeySize / 8)); } if (KeySize / 4 != signature.Length) { throw new CryptographicException(string.Format(CultureInfo.CurrentCulture, CryptographicInvalidSignatureSize, KeySize / 4)); } // There is no necessity to generate new parameter, just return false if (!_parametersSet) { return(false); } int keySizeInByted = KeySize / 8; BigInteger subgroupOrder = Normalize(new BigInteger(_curve.Order), s_modulus) / Normalize(new BigInteger(_curve.Cofactor), s_modulus); byte[] array = new byte[keySizeInByted]; BlockCopy(signature, 0, array, 0, keySizeInByted); BigInteger s = Normalize(new BigInteger(array), s_modulus); if (s < BigInteger.One || s > subgroupOrder) { return(false); } BlockCopy(signature, keySizeInByted, array, 0, keySizeInByted); BigInteger r = Normalize(new BigInteger(array), s_modulus); if (r < BigInteger.One || r > subgroupOrder) { return(false); } BigInteger e = Normalize(new BigInteger(hash), s_modulus) % subgroupOrder; if (e == BigInteger.Zero) { e = BigInteger.One; } BigInteger v = BigInteger.ModPow(e, subgroupOrder - 2, subgroupOrder), z1 = (s * v) % subgroupOrder, z2 = (subgroupOrder - r) * v % subgroupOrder, prime = Normalize(new BigInteger(_curve.Prime), s_modulus), a = Normalize(new BigInteger(_curve.A), s_modulus); BigIntegerPoint c = BigIntegerPoint.Add( BigIntegerPoint.Multiply(new BigIntegerPoint(_curve.G, s_modulus), z1, prime, a), BigIntegerPoint.Multiply(new BigIntegerPoint(_publicKey, s_modulus), z2, prime, a), prime); return(c.X == r); }
/// <summary> /// Generates a digital signature for the specified hash value. /// </summary> /// <param name="hash"> /// The hash value of the data that is being signed. /// </param> /// <returns> /// A digital signature that consists of the given hash value encrypted with the private key. /// </returns> /// <exception cref="ArgumentNullException"> /// The <paramref name="hash"/> parameter is <c>null</c>. /// </exception> public override byte[] SignHash(byte[] hash) { if (hash == null) { throw new ArgumentNullException(nameof(hash)); } ThrowIfDisposed(); if (KeySize / 8 != hash.Length) { throw new CryptographicException(string.Format(CultureInfo.CurrentCulture, CryptographicInvalidHashSize, KeySize / 8)); } int keySizeInByted = KeySize / 8; if (!_parametersSet) { GenerateKey(GetDefaultCurve()); } BigInteger subgroupOrder = Normalize(new BigInteger(_curve.Order), s_modulus) / Normalize(new BigInteger(_curve.Cofactor), s_modulus); BigInteger e = Normalize(new BigInteger(hash), s_modulus) % subgroupOrder; if (e == BigInteger.Zero) { e = BigInteger.One; } BigInteger prime = Normalize(new BigInteger(_curve.Prime), s_modulus), a = Normalize(new BigInteger(_curve.A), s_modulus), d = Normalize(new BigInteger(_privateKey), s_modulus), k, r, s; var rgb = new byte[keySizeInByted]; do { do { do { StaticRandomNumberGenerator.GetBytes(rgb); k = Normalize(new BigInteger(rgb), s_modulus); } while (k <= BigInteger.Zero || k >= subgroupOrder); r = BigIntegerPoint.Multiply(new BigIntegerPoint(_curve.G, s_modulus), k, prime, a).X; } while (r == BigInteger.Zero); s = (r * d + k * e) % subgroupOrder; } while (s == BigInteger.Zero); byte[] signature = new byte[keySizeInByted * 2], array = s.ToByteArray(); BlockCopy(array, 0, signature, 0, Min(array.Length, keySizeInByted)); array = r.ToByteArray(); BlockCopy(array, 0, signature, keySizeInByted, Min(array.Length, keySizeInByted)); return(signature); }