ClpECNRSigner.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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 ClpECNRSigner;
  14. {$I CryptoLib.inc}
  15. interface
  16. uses
  17. SysUtils,
  18. ClpIDsaExt,
  19. ClpIECC,
  20. ClpIECNRSigner,
  21. ClpBigInteger,
  22. ClpBigIntegers,
  23. ClpISecureRandom,
  24. ClpIECKeyParameters,
  25. ClpIParametersWithRandom,
  26. ClpICipherParameters,
  27. ClpIECKeyPairGenerator,
  28. ClpECKeyPairGenerator,
  29. ClpECKeyGenerationParameters,
  30. ClpIECKeyGenerationParameters,
  31. ClpIECPrivateKeyParameters,
  32. ClpIECPublicKeyParameters,
  33. ClpIAsymmetricCipherKeyPair,
  34. ClpSecureRandom,
  35. ClpECAlgorithms,
  36. ClpCryptoLibTypes;
  37. resourcestring
  38. SECPublicKeyNotFound = 'EC Public Key Required for Verification';
  39. SECPrivateKeyNotFound = 'EC Private Key Required for Signing';
  40. SNotInitializedForSigning = 'Not Initialised For Signing';
  41. SNotInitializedForVerifying = 'Not Initialised For Verifying';
  42. SNotInitializedForVerifyingRecovery =
  43. 'Not Initialised For Verifying/Recovery';
  44. SInputTooLargeForECNRKey = 'Input Too Large For ECNR Key.';
  45. type
  46. /// <summary>
  47. /// EC-NR as described in IEEE 1363-2000 - a signature algorithm for Elliptic Curve which
  48. /// also offers message recovery.
  49. /// </summary>
  50. TECNRSigner = class sealed(TInterfacedObject, IDsaExt, IECNRSigner)
  51. strict private
  52. var
  53. FForSigning: Boolean;
  54. FKey: IECKeyParameters;
  55. FRandom: ISecureRandom;
  56. function GetAlgorithmName: String;
  57. function GetOrder: TBigInteger;
  58. function ExtractT(const pubKey: IECPublicKeyParameters;
  59. const r, s: TBigInteger): TBigInteger;
  60. public
  61. property Order: TBigInteger read GetOrder;
  62. property AlgorithmName: String read GetAlgorithmName;
  63. /// <summary>
  64. /// Initialise the signer.
  65. /// </summary>
  66. /// <param name="forSigning">
  67. /// forSigning true if we are generating a signature, false for
  68. /// verification or if we want to use the signer for message recovery.
  69. /// </param>
  70. /// <param name="parameters">
  71. /// key parameters for signature generation.
  72. /// </param>
  73. procedure Init(forSigning: Boolean;
  74. const parameters: ICipherParameters); virtual;
  75. /// <summary>
  76. /// <para>
  77. /// Section 7.2.5 ECSP-NR, pg 34
  78. /// </para>
  79. /// <para>
  80. /// generate a signature for the given message using the key we were <br />
  81. /// initialised with. Generally, the order of the curve should be at <br />
  82. /// least as long as the hash of the message of interest, and with <br />
  83. /// ECNR it *must* be at least as long.
  84. /// </para>
  85. /// </summary>
  86. /// <param name="&amp;message">
  87. /// the digest to be signed.
  88. /// </param>
  89. /// <exception cref="EDataLengthCryptoLibException">
  90. /// if the digest is longer than the key allows
  91. /// </exception>
  92. function GenerateSignature(const &message: TCryptoLibByteArray)
  93. : TCryptoLibGenericArray<TBigInteger>; virtual;
  94. /// <summary>
  95. /// <para>
  96. /// Section 7.2.6 ECVP-NR, pg 35
  97. /// </para>
  98. /// <para>
  99. /// return true if the value r and s represent a signature for the <br />
  100. /// message passed in. Generally, the order of the curve should be at
  101. /// <br />least as long as the hash of the message of interest, and
  102. /// with <br />ECNR, it *must* be at least as long. But just in case
  103. /// the signer <br />applied mod(n) to the longer digest, this
  104. /// implementation will <br />apply mod(n) during verification.
  105. /// </para>
  106. /// </summary>
  107. /// <param name="&amp;message">
  108. /// the digest to be verified.
  109. /// </param>
  110. /// <param name="r">
  111. /// the r value of the signature.
  112. /// </param>
  113. /// <param name="s">
  114. /// the s value of the signature.
  115. /// </param>
  116. /// <exception cref="EDataLengthCryptoLibException">
  117. /// if the digest is longer than the key allows
  118. /// </exception>
  119. function VerifySignature(const &message: TCryptoLibByteArray;
  120. const r, s: TBigInteger): Boolean;
  121. /// <summary>
  122. /// Returns the data used for the signature generation, assuming the
  123. /// public key passed to Init() is correct.
  124. /// </summary>
  125. /// <returns>
  126. /// null if r and s are not valid.
  127. /// </returns>
  128. function GetRecoveredMessage(const r, s: TBigInteger): TCryptoLibByteArray;
  129. end;
  130. implementation
  131. { TECNRSigner }
  132. function TECNRSigner.ExtractT(const pubKey: IECPublicKeyParameters;
  133. const r, s: TBigInteger): TBigInteger;
  134. var
  135. n, x: TBigInteger;
  136. G, W, P: IECPoint;
  137. begin
  138. n := pubKey.parameters.n;
  139. // r in the range [1,n-1]
  140. if ((r.CompareTo(TBigInteger.ONE) < 0) or (r.CompareTo(n) >= 0)) then
  141. begin
  142. result := Default (TBigInteger);
  143. Exit;
  144. end;
  145. // s in the range [0,n-1] NB: ECNR spec says 0
  146. if ((s.CompareTo(TBigInteger.ZERO) < 0) or (s.CompareTo(n) >= 0)) then
  147. begin
  148. result := Default (TBigInteger);
  149. Exit;
  150. end;
  151. // compute P = sG + rW
  152. G := pubKey.parameters.G;
  153. W := pubKey.Q;
  154. // calculate P using Bouncy math
  155. P := TECAlgorithms.SumOfTwoMultiplies(G, s, W, r).Normalize();
  156. // components must be bogus.
  157. if (P.IsInfinity) then
  158. begin
  159. result := Default (TBigInteger);
  160. Exit;
  161. end;
  162. x := P.AffineXCoord.ToBigInteger();
  163. result := r.Subtract(x).&Mod(n);
  164. end;
  165. function TECNRSigner.GenerateSignature(const &message: TCryptoLibByteArray)
  166. : TCryptoLibGenericArray<TBigInteger>;
  167. var
  168. n, e, r, s, Vx, x, u: TBigInteger;
  169. privKey: IECPrivateKeyParameters;
  170. tempPair: IAsymmetricCipherKeyPair;
  171. keyGen: IECKeyPairGenerator;
  172. V: IECPublicKeyParameters;
  173. begin
  174. if (not FForSigning) then
  175. begin
  176. // not properly initialized... deal with it
  177. raise EInvalidOperationCryptoLibException.CreateRes
  178. (@SNotInitializedForSigning);
  179. end;
  180. n := Order;
  181. e := TBigInteger.Create(1, &message);
  182. privKey := FKey as IECPrivateKeyParameters;
  183. if (e.CompareTo(n) >= 0) then
  184. begin
  185. raise EDataLengthCryptoLibException.CreateRes(@SInputTooLargeForECNRKey);
  186. end;
  187. repeat // generate r
  188. // generate another, but very temporary, key pair using
  189. // the same EC parameters
  190. keyGen := TECKeyPairGenerator.Create();
  191. keyGen.Init(TECKeyGenerationParameters.Create(privKey.parameters, FRandom)
  192. as IECKeyGenerationParameters);
  193. tempPair := keyGen.GenerateKeyPair();
  194. V := tempPair.Public as IECPublicKeyParameters; // get temp's public key
  195. Vx := V.Q.AffineXCoord.ToBigInteger(); // get the point's x coordinate
  196. r := Vx.Add(e).&Mod(n);
  197. until (not(r.SignValue = 0));
  198. // generate s
  199. x := privKey.D; // private key value
  200. u := (tempPair.Private as IECPrivateKeyParameters).D;
  201. // temp's private key value
  202. s := u.Subtract(r.Multiply(x)).&Mod(n);
  203. result := TCryptoLibGenericArray<TBigInteger>.Create(r, s);
  204. end;
  205. function TECNRSigner.GetAlgorithmName: String;
  206. begin
  207. result := 'ECNR';
  208. end;
  209. function TECNRSigner.GetOrder: TBigInteger;
  210. begin
  211. result := FKey.parameters.n;
  212. end;
  213. procedure TECNRSigner.Init(forSigning: Boolean;
  214. const parameters: ICipherParameters);
  215. var
  216. rParam: IParametersWithRandom;
  217. Lparameters: ICipherParameters;
  218. begin
  219. FForSigning := forSigning;
  220. Lparameters := parameters;
  221. if (forSigning) then
  222. begin
  223. if (Supports(Lparameters, IParametersWithRandom, rParam)) then
  224. begin
  225. FRandom := rParam.random;
  226. Lparameters := rParam.parameters;
  227. end
  228. else
  229. begin
  230. FRandom := TSecureRandom.Create();
  231. end;
  232. if (not(Supports(Lparameters, IECPrivateKeyParameters))) then
  233. begin
  234. raise EInvalidKeyCryptoLibException.CreateRes(@SECPrivateKeyNotFound);
  235. end;
  236. FKey := Lparameters as IECPrivateKeyParameters;
  237. end
  238. else
  239. begin
  240. if (not(Supports(Lparameters, IECPublicKeyParameters))) then
  241. begin
  242. raise EInvalidKeyCryptoLibException.CreateRes(@SECPublicKeyNotFound);
  243. end;
  244. FKey := Lparameters as IECPublicKeyParameters;
  245. end;
  246. end;
  247. function TECNRSigner.VerifySignature(const &message: TCryptoLibByteArray;
  248. const r, s: TBigInteger): Boolean;
  249. var
  250. pubKey: IECPublicKeyParameters;
  251. n, e, t: TBigInteger;
  252. nBitLength, eBitLength: Int32;
  253. begin
  254. if (FForSigning) then
  255. begin
  256. // not properly initialized... deal with it
  257. raise EInvalidOperationCryptoLibException.CreateRes
  258. (@SNotInitializedForVerifying);
  259. end;
  260. pubKey := FKey as IECPublicKeyParameters;
  261. n := pubKey.parameters.n;
  262. nBitLength := n.BitLength;
  263. e := TBigInteger.Create(1, &message);
  264. eBitLength := e.BitLength;
  265. if (eBitLength > nBitLength) then
  266. begin
  267. raise EDataLengthCryptoLibException.CreateRes(@SInputTooLargeForECNRKey);
  268. end;
  269. t := ExtractT(pubKey, r, s);
  270. result := (t.IsInitialized) and (t.Equals(e.&Mod(n)));
  271. end;
  272. function TECNRSigner.GetRecoveredMessage(const r, s: TBigInteger)
  273. : TCryptoLibByteArray;
  274. var
  275. t: TBigInteger;
  276. begin
  277. if (FForSigning) then
  278. begin
  279. raise EInvalidOperationCryptoLibException.CreateRes
  280. (@SNotInitializedForVerifyingRecovery);
  281. end;
  282. t := ExtractT(FKey as IECPublicKeyParameters, r, s);
  283. if (t.IsInitialized) then
  284. begin
  285. result := TBigIntegers.AsUnsignedByteArray(t);
  286. Exit;
  287. end;
  288. result := Nil;
  289. end;
  290. end.