ClpECDsaSigner.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. { *********************************************************************************** }
  2. { * CryptoLib Library * }
  3. { * Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe * }
  4. { * Github Repository <https://github.com/Xor-el> * }
  5. { * Distributed under the MIT software license, see the accompanying file LICENSE * }
  6. { * or visit http://www.opensource.org/licenses/mit-license.php. * }
  7. { * Acknowledgements: * }
  8. { * * }
  9. { * Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring * }
  10. { * development of this library * }
  11. { * ******************************************************************************* * }
  12. (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
  13. unit ClpECDsaSigner;
  14. {$I CryptoLib.inc}
  15. interface
  16. uses
  17. SysUtils,
  18. ClpBigInteger,
  19. ClpSecureRandom,
  20. ClpECAlgorithms,
  21. ClpECC,
  22. ClpIECC,
  23. ClpIParametersWithRandom,
  24. ClpIECPublicKeyParameters,
  25. ClpIECPrivateKeyParameters,
  26. ClpMultipliers,
  27. ClpCryptoLibTypes,
  28. ClpICipherParameters,
  29. ClpIECDomainParameters,
  30. ClpISecureRandom,
  31. ClpRandomDsaKCalculator,
  32. ClpIECKeyParameters,
  33. ClpIDsaKCalculator,
  34. ClpECCurveConstants,
  35. ClpIDsaExt,
  36. ClpIECDsaSigner;
  37. resourcestring
  38. SECPublicKeyNotFound = 'EC Public Key Required for Verification';
  39. SECPrivateKeyNotFound = 'EC Private Key Required for Signing';
  40. type
  41. /// <summary>
  42. /// EC-DSA as described in X9.62
  43. /// </summary>
  44. TECDsaSigner = class(TInterfacedObject, IDsaExt, IECDsaSigner)
  45. strict private
  46. class var
  47. FEight: TBigInteger;
  48. class procedure Boot(); static;
  49. class constructor ECDsaSigner();
  50. class function GetEight: TBigInteger; static; inline;
  51. class property Eight: TBigInteger read GetEight;
  52. function GetOrder: TBigInteger; virtual;
  53. function GetAlgorithmName: String; virtual;
  54. strict protected
  55. var
  56. FkCalculator: IDsaKCalculator;
  57. Fkey: IECKeyParameters;
  58. Frandom: ISecureRandom;
  59. function CalculateE(const n: TBigInteger;
  60. const &message: TCryptoLibByteArray): TBigInteger; virtual;
  61. function CreateBasePointMultiplier(): IECMultiplier; virtual;
  62. function GetDenominator(coordinateSystem: Int32; const p: IECPoint)
  63. : IECFieldElement; virtual;
  64. function InitSecureRandom(needed: Boolean; const provided: ISecureRandom)
  65. : ISecureRandom; virtual;
  66. public
  67. /// <summary>
  68. /// Default configuration, random K values.
  69. /// </summary>
  70. constructor Create(); overload;
  71. /// <summary>
  72. /// Configuration with an alternate, possibly deterministic calculator of
  73. /// K.
  74. /// </summary>
  75. /// <param name="kCalculator">
  76. /// kCalculator a K value calculator.
  77. /// </param>
  78. constructor Create(const kCalculator: IDsaKCalculator); overload;
  79. property Order: TBigInteger read GetOrder;
  80. property AlgorithmName: String read GetAlgorithmName;
  81. procedure Init(forSigning: Boolean;
  82. const parameters: ICipherParameters); virtual;
  83. // // 5.3 pg 28
  84. // /**
  85. // * Generate a signature for the given message using the key we were
  86. // * initialised with. For conventional DSA the message should be a SHA-1
  87. // * hash of the message of interest.
  88. // *
  89. // * @param message the message that will be verified later.
  90. function GenerateSignature(const &message: TCryptoLibByteArray)
  91. : TCryptoLibGenericArray<TBigInteger>; virtual;
  92. // // 5.4 pg 29
  93. // /**
  94. // * return true if the value r and s represent a DSA signature for
  95. // * the passed in message (for standard DSA the message should be
  96. // * a SHA-1 hash of the real message to be verified).
  97. // */
  98. function VerifySignature(const &message: TCryptoLibByteArray;
  99. const r, s: TBigInteger): Boolean;
  100. end;
  101. implementation
  102. { TECDsaSigner }
  103. constructor TECDsaSigner.Create;
  104. begin
  105. inherited Create();
  106. FkCalculator := TRandomDsaKCalculator.Create();
  107. end;
  108. class procedure TECDsaSigner.Boot;
  109. begin
  110. FEight := TBigInteger.ValueOf(8);
  111. end;
  112. function TECDsaSigner.CalculateE(const n: TBigInteger;
  113. const &message: TCryptoLibByteArray): TBigInteger;
  114. var
  115. messageBitLength: Int32;
  116. trunc: TBigInteger;
  117. begin
  118. messageBitLength := System.Length(&message) * 8;
  119. trunc := TBigInteger.Create(1, &message);
  120. if (n.BitLength < messageBitLength) then
  121. begin
  122. trunc := trunc.ShiftRight(messageBitLength - n.BitLength);
  123. end;
  124. Result := trunc;
  125. end;
  126. constructor TECDsaSigner.Create(const kCalculator: IDsaKCalculator);
  127. begin
  128. inherited Create();
  129. FkCalculator := kCalculator;
  130. end;
  131. function TECDsaSigner.CreateBasePointMultiplier: IECMultiplier;
  132. begin
  133. Result := TFixedPointCombMultiplier.Create();
  134. end;
  135. class constructor TECDsaSigner.ECDsaSigner;
  136. begin
  137. TECDsaSigner.Boot;
  138. end;
  139. function TECDsaSigner.GenerateSignature(const &message: TCryptoLibByteArray)
  140. : TCryptoLibGenericArray<TBigInteger>;
  141. var
  142. ec: IECDomainParameters;
  143. basePointMultiplier: IECMultiplier;
  144. n, e, d, r, s, k: TBigInteger;
  145. p: IECPoint;
  146. begin
  147. ec := Fkey.parameters;
  148. n := ec.n;
  149. e := CalculateE(n, &message);
  150. d := (Fkey as IECPrivateKeyParameters).d;
  151. if (FkCalculator.IsDeterministic) then
  152. begin
  153. FkCalculator.Init(n, d, &message);
  154. end
  155. else
  156. begin
  157. FkCalculator.Init(n, Frandom);
  158. end;
  159. basePointMultiplier := CreateBasePointMultiplier();
  160. // 5.3.2
  161. repeat // Generate s
  162. repeat // Generate r
  163. k := FkCalculator.NextK();
  164. p := basePointMultiplier.Multiply(ec.G, k).Normalize();
  165. // 5.3.3
  166. r := p.AffineXCoord.ToBigInteger().&Mod(n);
  167. until (not(r.SignValue = 0));
  168. s := k.ModInverse(n).Multiply(e.Add(d.Multiply(r))).&Mod(n);
  169. until (not(s.SignValue = 0));
  170. Result := TCryptoLibGenericArray<TBigInteger>.Create(r, s);
  171. end;
  172. function TECDsaSigner.GetAlgorithmName: String;
  173. begin
  174. Result := 'ECDSA';
  175. end;
  176. function TECDsaSigner.GetDenominator(coordinateSystem: Int32; const p: IECPoint)
  177. : IECFieldElement;
  178. begin
  179. case (coordinateSystem) of
  180. TECCurveConstants.COORD_HOMOGENEOUS,
  181. TECCurveConstants.COORD_LAMBDA_PROJECTIVE, TECCurveConstants.COORD_SKEWED:
  182. begin
  183. Result := p.GetZCoord(0);
  184. end;
  185. TECCurveConstants.COORD_JACOBIAN,
  186. TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY,
  187. TECCurveConstants.COORD_JACOBIAN_MODIFIED:
  188. begin
  189. Result := p.GetZCoord(0).Square();
  190. end
  191. else
  192. begin
  193. Result := Nil;
  194. end;
  195. end;
  196. end;
  197. class function TECDsaSigner.GetEight: TBigInteger;
  198. begin
  199. Result := FEight;
  200. end;
  201. function TECDsaSigner.GetOrder: TBigInteger;
  202. begin
  203. Result := Fkey.parameters.n;
  204. end;
  205. procedure TECDsaSigner.Init(forSigning: Boolean;
  206. const parameters: ICipherParameters);
  207. var
  208. providedRandom: ISecureRandom;
  209. rParam: IParametersWithRandom;
  210. Lparameters: ICipherParameters;
  211. begin
  212. providedRandom := Nil;
  213. Lparameters := parameters;
  214. if (forSigning) then
  215. begin
  216. if (Supports(Lparameters, IParametersWithRandom, rParam)) then
  217. begin
  218. providedRandom := rParam.random;
  219. Lparameters := rParam.parameters;
  220. end;
  221. if (not(Supports(Lparameters, IECPrivateKeyParameters))) then
  222. begin
  223. raise EInvalidKeyCryptoLibException.CreateRes(@SECPrivateKeyNotFound);
  224. end;
  225. Fkey := Lparameters as IECPrivateKeyParameters;
  226. end
  227. else
  228. begin
  229. if (not(Supports(Lparameters, IECPublicKeyParameters))) then
  230. begin
  231. raise EInvalidKeyCryptoLibException.CreateRes(@SECPublicKeyNotFound);
  232. end;
  233. Fkey := Lparameters as IECPublicKeyParameters;
  234. end;
  235. Frandom := InitSecureRandom((forSigning) and
  236. (not FkCalculator.IsDeterministic), providedRandom);
  237. end;
  238. function TECDsaSigner.InitSecureRandom(needed: Boolean;
  239. const provided: ISecureRandom): ISecureRandom;
  240. begin
  241. if (not needed) then
  242. begin
  243. Result := Nil;
  244. end
  245. else
  246. begin
  247. if (provided <> Nil) then
  248. begin
  249. Result := provided;
  250. end
  251. else
  252. begin
  253. Result := TSecureRandom.Create();
  254. end;
  255. end;
  256. end;
  257. function TECDsaSigner.VerifySignature(const &message: TCryptoLibByteArray;
  258. const r, s: TBigInteger): Boolean;
  259. var
  260. n, e, c, u1, u2, cofactor, v, Smallr: TBigInteger;
  261. G, Q, point: IECPoint;
  262. curve: IECCurve;
  263. d, X, RLocal: IECFieldElement;
  264. begin
  265. n := Fkey.parameters.n;
  266. Smallr := r;
  267. // r and s should both in the range [1,n-1]
  268. if ((Smallr.SignValue < 1) or (s.SignValue < 1) or (Smallr.CompareTo(n) >= 0)
  269. or (s.CompareTo(n) >= 0)) then
  270. begin
  271. Result := false;
  272. Exit;
  273. end;
  274. e := CalculateE(n, &message);
  275. c := s.ModInverse(n);
  276. u1 := e.Multiply(c).&Mod(n);
  277. u2 := Smallr.Multiply(c).&Mod(n);
  278. G := Fkey.parameters.G;
  279. Q := (Fkey as IECPublicKeyParameters).Q;
  280. point := TECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2);
  281. if (point.IsInfinity) then
  282. begin
  283. Result := false;
  284. Exit;
  285. end;
  286. // /*
  287. // * If possible, avoid normalizing the point (to save a modular inversion in the curve field).
  288. // *
  289. // * There are ~cofactor elements of the curve field that reduce (modulo the group order) to 'r'.
  290. // * If the cofactor is known and small, we generate those possible field values and project each
  291. // * of them to the same "denominator" (depending on the particular projective coordinates in use)
  292. // * as the calculated point.X. If any of the projected values matches point.X, then we have:
  293. // * (point.X / Denominator mod p) mod n == r
  294. // * as required, and verification succeeds.
  295. // *
  296. // * Based on an original idea by Gregory Maxwell (https://github.com/gmaxwell), as implemented in
  297. // * the libsecp256k1 project (https://github.com/bitcoin/secp256k1).
  298. // */
  299. curve := point.curve;
  300. if (curve <> Nil) then
  301. begin
  302. cofactor := curve.cofactor;
  303. if ((cofactor.IsInitialized) and (cofactor.CompareTo(Eight) <= 0)) then
  304. begin
  305. d := GetDenominator(curve.coordinateSystem, point);
  306. if ((d <> Nil) and (not d.IsZero)) then
  307. begin
  308. X := point.XCoord;
  309. while (curve.IsValidFieldElement(Smallr)) do
  310. begin
  311. RLocal := curve.FromBigInteger(Smallr).Multiply(d);
  312. if (RLocal.Equals(X)) then
  313. begin
  314. Result := True;
  315. Exit;
  316. end;
  317. Smallr := Smallr.Add(n);
  318. end;
  319. Result := false;
  320. Exit;
  321. end;
  322. end;
  323. end;
  324. v := point.Normalize().AffineXCoord.ToBigInteger().&Mod(n);
  325. Result := v.Equals(Smallr);
  326. end;
  327. end.