summary refs log tree commit diff
path: root/Crypto/src/crypto/signers/ECDsaSigner.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/crypto/signers/ECDsaSigner.cs')
-rw-r--r--Crypto/src/crypto/signers/ECDsaSigner.cs156
1 files changed, 156 insertions, 0 deletions
diff --git a/Crypto/src/crypto/signers/ECDsaSigner.cs b/Crypto/src/crypto/signers/ECDsaSigner.cs
new file mode 100644

index 000000000..4254e5590 --- /dev/null +++ b/Crypto/src/crypto/signers/ECDsaSigner.cs
@@ -0,0 +1,156 @@ +using System; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Signers +{ + /** + * EC-DSA as described in X9.62 + */ + public class ECDsaSigner + : IDsa + { + private ECKeyParameters key; + private SecureRandom random; + + public string AlgorithmName + { + get { return "ECDSA"; } + } + + public void Init( + bool forSigning, + ICipherParameters parameters) + { + if (forSigning) + { + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom) parameters; + + this.random = rParam.Random; + parameters = rParam.Parameters; + } + else + { + this.random = new SecureRandom(); + } + + if (!(parameters is ECPrivateKeyParameters)) + throw new InvalidKeyException("EC private key required for signing"); + + this.key = (ECPrivateKeyParameters) parameters; + } + else + { + if (!(parameters is ECPublicKeyParameters)) + throw new InvalidKeyException("EC public key required for verification"); + + this.key = (ECPublicKeyParameters) parameters; + } + } + + // 5.3 pg 28 + /** + * Generate a signature for the given message using the key we were + * initialised with. For conventional DSA the message should be a SHA-1 + * hash of the message of interest. + * + * @param message the message that will be verified later. + */ + public BigInteger[] GenerateSignature( + byte[] message) + { + BigInteger n = key.Parameters.N; + BigInteger e = calculateE(n, message); + + BigInteger r = null; + BigInteger s = null; + + // 5.3.2 + do // Generate s + { + BigInteger k = null; + + do // Generate r + { + do + { + k = new BigInteger(n.BitLength, random); + } + while (k.SignValue == 0 || k.CompareTo(n) >= 0); + + ECPoint p = key.Parameters.G.Multiply(k); + + // 5.3.3 + BigInteger x = p.X.ToBigInteger(); + + r = x.Mod(n); + } + while (r.SignValue == 0); + + BigInteger d = ((ECPrivateKeyParameters)key).D; + + s = k.ModInverse(n).Multiply(e.Add(d.Multiply(r).Mod(n))).Mod(n); + } + while (s.SignValue == 0); + + return new BigInteger[]{ r, s }; + } + + // 5.4 pg 29 + /** + * return true if the value r and s represent a DSA signature for + * the passed in message (for standard DSA the message should be + * a SHA-1 hash of the real message to be verified). + */ + public bool VerifySignature( + byte[] message, + BigInteger r, + BigInteger s) + { + BigInteger n = key.Parameters.N; + + // r and s should both in the range [1,n-1] + if (r.SignValue < 1 || s.SignValue < 1 + || r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0) + { + return false; + } + + BigInteger e = calculateE(n, message); + BigInteger c = s.ModInverse(n); + + BigInteger u1 = e.Multiply(c).Mod(n); + BigInteger u2 = r.Multiply(c).Mod(n); + + ECPoint G = key.Parameters.G; + ECPoint Q = ((ECPublicKeyParameters) key).Q; + + ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2); + + BigInteger v = point.X.ToBigInteger().Mod(n); + + return v.Equals(r); + } + + private BigInteger calculateE( + BigInteger n, + byte[] message) + { + int messageBitLength = message.Length * 8; + BigInteger trunc = new BigInteger(1, message); + + if (n.BitLength < messageBitLength) + { + trunc = trunc.ShiftRight(messageBitLength - n.BitLength); + } + + return trunc; + } + } +}