ECDsaSigner.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Multiplier;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  10. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  11. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Signers
  12. {
  13. /**
  14. * EC-DSA as described in X9.62
  15. */
  16. public class ECDsaSigner
  17. : IDsaExt
  18. {
  19. private static readonly BigInteger Eight = BigInteger.ValueOf(8);
  20. protected readonly IDsaKCalculator kCalculator;
  21. protected ECKeyParameters key = null;
  22. protected SecureRandom random = null;
  23. /**
  24. * Default configuration, random K values.
  25. */
  26. public ECDsaSigner()
  27. {
  28. this.kCalculator = new RandomDsaKCalculator();
  29. }
  30. /**
  31. * Configuration with an alternate, possibly deterministic calculator of K.
  32. *
  33. * @param kCalculator a K value calculator.
  34. */
  35. public ECDsaSigner(IDsaKCalculator kCalculator)
  36. {
  37. this.kCalculator = kCalculator;
  38. }
  39. public virtual string AlgorithmName
  40. {
  41. get { return "ECDSA"; }
  42. }
  43. public virtual void Init(bool forSigning, ICipherParameters parameters)
  44. {
  45. SecureRandom providedRandom = null;
  46. if (forSigning)
  47. {
  48. if (parameters is ParametersWithRandom)
  49. {
  50. ParametersWithRandom rParam = (ParametersWithRandom)parameters;
  51. providedRandom = rParam.Random;
  52. parameters = rParam.Parameters;
  53. }
  54. if (!(parameters is ECPrivateKeyParameters))
  55. throw new InvalidKeyException("EC private key required for signing");
  56. this.key = (ECPrivateKeyParameters)parameters;
  57. }
  58. else
  59. {
  60. if (!(parameters is ECPublicKeyParameters))
  61. throw new InvalidKeyException("EC public key required for verification");
  62. this.key = (ECPublicKeyParameters)parameters;
  63. }
  64. this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
  65. }
  66. public virtual BigInteger Order
  67. {
  68. get { return key.Parameters.N; }
  69. }
  70. // 5.3 pg 28
  71. /**
  72. * Generate a signature for the given message using the key we were
  73. * initialised with. For conventional DSA the message should be a SHA-1
  74. * hash of the message of interest.
  75. *
  76. * @param message the message that will be verified later.
  77. */
  78. public virtual BigInteger[] GenerateSignature(byte[] message)
  79. {
  80. ECDomainParameters ec = key.Parameters;
  81. BigInteger n = ec.N;
  82. BigInteger e = CalculateE(n, message);
  83. BigInteger d = ((ECPrivateKeyParameters)key).D;
  84. if (kCalculator.IsDeterministic)
  85. {
  86. kCalculator.Init(n, d, message);
  87. }
  88. else
  89. {
  90. kCalculator.Init(n, random);
  91. }
  92. BigInteger r, s;
  93. ECMultiplier basePointMultiplier = CreateBasePointMultiplier();
  94. // 5.3.2
  95. do // Generate s
  96. {
  97. BigInteger k;
  98. do // Generate r
  99. {
  100. k = kCalculator.NextK();
  101. ECPoint p = basePointMultiplier.Multiply(ec.G, k).Normalize();
  102. // 5.3.3
  103. r = p.AffineXCoord.ToBigInteger().Mod(n);
  104. }
  105. while (r.SignValue == 0);
  106. s = BigIntegers.ModOddInverse(n, k).Multiply(e.Add(d.Multiply(r))).Mod(n);
  107. }
  108. while (s.SignValue == 0);
  109. return new BigInteger[]{ r, s };
  110. }
  111. // 5.4 pg 29
  112. /**
  113. * return true if the value r and s represent a DSA signature for
  114. * the passed in message (for standard DSA the message should be
  115. * a SHA-1 hash of the real message to be verified).
  116. */
  117. public virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
  118. {
  119. BigInteger n = key.Parameters.N;
  120. // r and s should both in the range [1,n-1]
  121. if (r.SignValue < 1 || s.SignValue < 1
  122. || r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0)
  123. {
  124. return false;
  125. }
  126. BigInteger e = CalculateE(n, message);
  127. BigInteger c = BigIntegers.ModOddInverseVar(n, s);
  128. BigInteger u1 = e.Multiply(c).Mod(n);
  129. BigInteger u2 = r.Multiply(c).Mod(n);
  130. ECPoint G = key.Parameters.G;
  131. ECPoint Q = ((ECPublicKeyParameters) key).Q;
  132. ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2);
  133. if (point.IsInfinity)
  134. return false;
  135. /*
  136. * If possible, avoid normalizing the point (to save a modular inversion in the curve field).
  137. *
  138. * There are ~cofactor elements of the curve field that reduce (modulo the group order) to 'r'.
  139. * If the cofactor is known and small, we generate those possible field values and project each
  140. * of them to the same "denominator" (depending on the particular projective coordinates in use)
  141. * as the calculated point.X. If any of the projected values matches point.X, then we have:
  142. * (point.X / Denominator mod p) mod n == r
  143. * as required, and verification succeeds.
  144. *
  145. * Based on an original idea by Gregory Maxwell (https://github.com/gmaxwell), as implemented in
  146. * the libsecp256k1 project (https://github.com/bitcoin/secp256k1).
  147. */
  148. ECCurve curve = point.Curve;
  149. if (curve != null)
  150. {
  151. BigInteger cofactor = curve.Cofactor;
  152. if (cofactor != null && cofactor.CompareTo(Eight) <= 0)
  153. {
  154. ECFieldElement D = GetDenominator(curve.CoordinateSystem, point);
  155. if (D != null && !D.IsZero)
  156. {
  157. ECFieldElement X = point.XCoord;
  158. while (curve.IsValidFieldElement(r))
  159. {
  160. ECFieldElement R = curve.FromBigInteger(r).Multiply(D);
  161. if (R.Equals(X))
  162. {
  163. return true;
  164. }
  165. r = r.Add(n);
  166. }
  167. return false;
  168. }
  169. }
  170. }
  171. BigInteger v = point.Normalize().AffineXCoord.ToBigInteger().Mod(n);
  172. return v.Equals(r);
  173. }
  174. protected virtual BigInteger CalculateE(BigInteger n, byte[] message)
  175. {
  176. int messageBitLength = message.Length * 8;
  177. BigInteger trunc = new BigInteger(1, message);
  178. if (n.BitLength < messageBitLength)
  179. {
  180. trunc = trunc.ShiftRight(messageBitLength - n.BitLength);
  181. }
  182. return trunc;
  183. }
  184. protected virtual ECMultiplier CreateBasePointMultiplier()
  185. {
  186. return new FixedPointCombMultiplier();
  187. }
  188. protected virtual ECFieldElement GetDenominator(int coordinateSystem, ECPoint p)
  189. {
  190. switch (coordinateSystem)
  191. {
  192. case ECCurve.COORD_HOMOGENEOUS:
  193. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  194. case ECCurve.COORD_SKEWED:
  195. return p.GetZCoord(0);
  196. case ECCurve.COORD_JACOBIAN:
  197. case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
  198. case ECCurve.COORD_JACOBIAN_MODIFIED:
  199. return p.GetZCoord(0).Square();
  200. default:
  201. return null;
  202. }
  203. }
  204. protected virtual SecureRandom InitSecureRandom(bool needed, SecureRandom provided)
  205. {
  206. return !needed ? null : (provided != null) ? provided : new SecureRandom();
  207. }
  208. }
  209. }
  210. #pragma warning restore
  211. #endif