UsageExamples.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  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 UsageExamples;
  14. {$IFDEF FPC}
  15. {$MODE DELPHI}
  16. {$HINTS OFF}
  17. {$WARNINGS OFF}
  18. {$ENDIF FPC}
  19. interface
  20. uses
  21. SysUtils,
  22. ClpIDigest,
  23. ClpIDigestMAC,
  24. ClpDigestUtilities,
  25. ClpBigInteger,
  26. ClpSecureRandom,
  27. ClpISecureRandom,
  28. ClpIX9ECParameters,
  29. ClpIECDomainParameters,
  30. ClpECDomainParameters,
  31. ClpIECKeyPairGenerator,
  32. ClpECKeyPairGenerator,
  33. ClpIECKeyGenerationParameters,
  34. ClpECKeyGenerationParameters,
  35. ClpIAsymmetricCipherKeyPair,
  36. ClpAsymmetricCipherKeyPair,
  37. ClpIECPrivateKeyParameters,
  38. ClpIECPublicKeyParameters,
  39. ClpECPublicKeyParameters,
  40. ClpECPrivateKeyParameters,
  41. ClpIAsymmetricKeyParameter,
  42. ClpECSchnorrSigner,
  43. ClpIECInterface,
  44. ClpECPoint,
  45. ClpISigner,
  46. ClpSignerUtilities,
  47. ClpParametersWithIV,
  48. ClpIParametersWithIV,
  49. ClpIBufferedCipher,
  50. ClpIBufferedBlockCipher,
  51. // ClpIIESEngine,
  52. // ClpIESEngine,
  53. ClpPascalCoinIESEngine,
  54. ClpIPascalCoinIESEngine,
  55. ClpIIESWithCipherParameters,
  56. ClpIESWithCipherParameters,
  57. ClpIAesEngine,
  58. ClpAesEngine,
  59. ClpICbcBlockCipher,
  60. ClpCbcBlockCipher,
  61. ClpIZeroBytePadding,
  62. ClpZeroBytePadding,
  63. ClpIIESCipher,
  64. ClpIESCipher,
  65. ClpIECDHBasicAgreement,
  66. ClpECDHBasicAgreement,
  67. ClpIPascalCoinECIESKdfBytesGenerator,
  68. ClpPascalCoinECIESKdfBytesGenerator,
  69. ClpPaddedBufferedBlockCipher,
  70. ClpParameterUtilities,
  71. ClpCipherUtilities,
  72. ClpGeneratorUtilities,
  73. ClpIAsymmetricCipherKeyPairGenerator,
  74. ClpArrayUtils,
  75. ClpHex,
  76. ClpSecNamedCurves;
  77. type
  78. TUsageExamples = class sealed(TObject)
  79. strict private
  80. const
  81. /// <summary>
  82. /// supported curves are secp256k1, sect283k1, secp384r1 and secp521r1
  83. /// </summary>
  84. CurveName = 'secp256k1';
  85. /// <summary>
  86. /// supported signing algorithms are NONEwithECDSA, SHA-1withECDSA, <br />
  87. /// SHA-224withECDSA, SHA-256withECDSA, SHA-384withECDSA,
  88. /// SHA-512withECDSA and RIPEMD160withECDSA
  89. /// </summary>
  90. SigningAlgorithmECDSA = 'SHA-1withECDSA';
  91. SigningAlgorithmECSCHNORR = 'SHA-256withECSCHNORRLIBSECP';
  92. PKCS5_SALT_LEN = Int32(8);
  93. SALT_MAGIC_LEN = Int32(8);
  94. SALT_SIZE = Int32(8);
  95. SALT_MAGIC: String = 'Salted__';
  96. class var
  97. FRandom: ISecureRandom;
  98. FCurve: IX9ECParameters;
  99. class function BytesToHexString(input: TBytes): String; static;
  100. class constructor UsageExamples();
  101. private
  102. class procedure DoSigningAndVerifying(const PublicKey
  103. : IECPublicKeyParameters; const PrivateKey: IECPrivateKeyParameters;
  104. const CallerMethod, TextToSign: String;
  105. const SigningAlgo: String = SigningAlgorithmECDSA); static;
  106. class function EVP_GetSalt(): TBytes; static; inline;
  107. class function EVP_GetKeyIV(PasswordBytes, SaltBytes: TBytes;
  108. out KeyBytes, IVBytes: TBytes): Boolean; static;
  109. class function AES256CBCPascalCoinEncrypt(PlainText, PasswordBytes: TBytes)
  110. : TBytes; static;
  111. class function AES256CBCPascalCoinDecrypt(CipherText, PasswordBytes: TBytes;
  112. out PlainText: TBytes): Boolean; static;
  113. class function GetECIESPascalCoinCompatibilityEngine
  114. : IPascalCoinIESEngine; static;
  115. class function GetECKeyPair: IAsymmetricCipherKeyPair; static;
  116. class function GetIESCipherParameters: IIESWithCipherParameters; static;
  117. class function ECIESPascalCoinEncrypt(const PublicKey
  118. : IAsymmetricKeyParameter; PlainText: TBytes): TBytes; static;
  119. class function ECIESPascalCoinDecrypt(const PrivateKey
  120. : IAsymmetricKeyParameter; CipherText: TBytes; out PlainText: TBytes)
  121. : Boolean; static;
  122. public
  123. class procedure GenerateKeyPairAndSignECDSA(); static;
  124. class procedure GenerateKeyPairAndSignECSchnorr(); static;
  125. class procedure GetPublicKeyFromPrivateKey(); static;
  126. class procedure RecreatePublicAndPrivateKeyPairsFromByteArray(); static;
  127. class procedure RecreatePublicKeyFromXAndYCoordByteArray; static;
  128. class procedure BinaryCompatiblePascalCoinAES256EncryptDecryptDemo
  129. (const inputmessage, password: string); static;
  130. class procedure BinaryCompatiblePascalCoinECIESEncryptDecryptDemo
  131. (const input: string); static;
  132. class procedure BinaryCompatiblePascalCoinECIESDecryptExistingPayloadDemo
  133. (const PrivateKeyInHex, EncryptedMessageInHex,
  134. ACurveName: string); static;
  135. end;
  136. implementation
  137. { TUsageExamples }
  138. class function TUsageExamples.ECIESPascalCoinDecrypt(const PrivateKey
  139. : IAsymmetricKeyParameter; CipherText: TBytes; out PlainText: TBytes)
  140. : Boolean;
  141. var
  142. CipherDecrypt: IIESCipher;
  143. begin
  144. // Decryption
  145. CipherDecrypt := TIESCipher.Create(GetECIESPascalCoinCompatibilityEngine);
  146. CipherDecrypt.Init(False, PrivateKey, GetIESCipherParameters, FRandom);
  147. PlainText := CipherDecrypt.DoFinal(CipherText);
  148. Result := True;
  149. end;
  150. class function TUsageExamples.ECIESPascalCoinEncrypt(const PublicKey
  151. : IAsymmetricKeyParameter; PlainText: TBytes): TBytes;
  152. var
  153. CipherEncrypt: IIESCipher;
  154. begin
  155. // Encryption
  156. CipherEncrypt := TIESCipher.Create(GetECIESPascalCoinCompatibilityEngine);
  157. CipherEncrypt.Init(True, PublicKey, GetIESCipherParameters, FRandom);
  158. Result := CipherEncrypt.DoFinal(PlainText);
  159. end;
  160. class function TUsageExamples.EVP_GetKeyIV(PasswordBytes, SaltBytes: TBytes;
  161. out KeyBytes, IVBytes: TBytes): Boolean;
  162. var
  163. LKey, LIV: integer;
  164. LDigest: IDigest;
  165. begin
  166. LKey := 32; // AES256 CBC Key Length
  167. LIV := 16; // AES256 CBC IV Length
  168. System.SetLength(KeyBytes, LKey);
  169. System.SetLength(IVBytes, LKey);
  170. // Max size to start then reduce it at the end
  171. LDigest := TDigestUtilities.GetDigest('SHA-256'); // SHA2_256
  172. System.Assert(LDigest.HashSize >= LKey);
  173. System.Assert(LDigest.HashSize >= LIV);
  174. // Derive Key First
  175. LDigest.TransformBytes(PasswordBytes);
  176. if SaltBytes <> Nil then
  177. begin
  178. LDigest.TransformBytes(SaltBytes);
  179. end;
  180. KeyBytes := System.Copy(LDigest.TransformFinal.GetBytes);
  181. // Derive IV Next
  182. LDigest.Initialize();
  183. LDigest.TransformBytes(KeyBytes);
  184. LDigest.TransformBytes(PasswordBytes);
  185. if SaltBytes <> Nil then
  186. begin
  187. LDigest.TransformBytes(SaltBytes);
  188. end;
  189. IVBytes := System.Copy(LDigest.TransformFinal.GetBytes);
  190. System.SetLength(IVBytes, LIV);
  191. Result := True;
  192. end;
  193. class function TUsageExamples.EVP_GetSalt: TBytes;
  194. begin
  195. System.SetLength(Result, PKCS5_SALT_LEN);
  196. FRandom.NextBytes(Result);
  197. end;
  198. class function TUsageExamples.AES256CBCPascalCoinDecrypt(CipherText,
  199. PasswordBytes: TBytes; out PlainText: TBytes): Boolean;
  200. var
  201. SaltBytes, KeyBytes, IVBytes, Buf, Chopped: TBytes;
  202. KeyParametersWithIV: IParametersWithIV;
  203. cipher: IBufferedCipher;
  204. LBufStart, LSrcStart, Count: Int32;
  205. begin
  206. Result := False;
  207. System.SetLength(SaltBytes, SALT_SIZE);
  208. // First read the magic text and the salt - if any
  209. Chopped := System.Copy(CipherText, 0, SALT_MAGIC_LEN);
  210. if (System.Length(CipherText) >= SALT_MAGIC_LEN) and
  211. (TArrayUtils.AreEqual(Chopped, TEncoding.UTF8.GetBytes(SALT_MAGIC))) then
  212. begin
  213. System.Move(CipherText[SALT_MAGIC_LEN], SaltBytes[0], SALT_SIZE);
  214. If not EVP_GetKeyIV(PasswordBytes, SaltBytes, KeyBytes, IVBytes) then
  215. begin
  216. Exit;
  217. end;
  218. LSrcStart := SALT_MAGIC_LEN + SALT_SIZE;
  219. end
  220. else
  221. begin
  222. If Not EVP_GetKeyIV(PasswordBytes, Nil, KeyBytes, IVBytes) then
  223. begin
  224. Exit;
  225. end;
  226. LSrcStart := 0;
  227. end;
  228. cipher := TCipherUtilities.GetCipher('AES/CBC/PKCS7PADDING');
  229. KeyParametersWithIV := TParametersWithIV.Create
  230. (TParameterUtilities.CreateKeyParameter('AES', KeyBytes), IVBytes);
  231. cipher.Init(False, KeyParametersWithIV); // init decryption cipher
  232. System.SetLength(Buf, System.Length(CipherText));
  233. LBufStart := 0;
  234. Count := cipher.ProcessBytes(CipherText, LSrcStart, System.Length(CipherText)
  235. - LSrcStart, Buf, LBufStart);
  236. System.Inc(LBufStart, Count);
  237. Count := cipher.DoFinal(Buf, LBufStart);
  238. System.Inc(LBufStart, Count);
  239. System.SetLength(Buf, LBufStart);
  240. PlainText := System.Copy(Buf);
  241. Result := True;
  242. end;
  243. class function TUsageExamples.AES256CBCPascalCoinEncrypt(PlainText,
  244. PasswordBytes: TBytes): TBytes;
  245. var
  246. SaltBytes, KeyBytes, IVBytes, Buf: TBytes;
  247. KeyParametersWithIV: IParametersWithIV;
  248. cipher: IBufferedCipher;
  249. LBlockSize, LBufStart, Count: Int32;
  250. begin
  251. SaltBytes := EVP_GetSalt;
  252. EVP_GetKeyIV(PasswordBytes, SaltBytes, KeyBytes, IVBytes);
  253. cipher := TCipherUtilities.GetCipher('AES/CBC/PKCS7PADDING');
  254. KeyParametersWithIV := TParametersWithIV.Create
  255. (TParameterUtilities.CreateKeyParameter('AES', KeyBytes), IVBytes);
  256. cipher.Init(True, KeyParametersWithIV); // init encryption cipher
  257. LBlockSize := cipher.GetBlockSize;
  258. System.SetLength(Buf, System.Length(PlainText) + LBlockSize + SALT_MAGIC_LEN +
  259. PKCS5_SALT_LEN);
  260. LBufStart := 0;
  261. System.Move(TEncoding.UTF8.GetBytes(SALT_MAGIC)[0], Buf[LBufStart],
  262. SALT_MAGIC_LEN * System.SizeOf(Byte));
  263. System.Inc(LBufStart, SALT_MAGIC_LEN);
  264. System.Move(SaltBytes[0], Buf[LBufStart],
  265. PKCS5_SALT_LEN * System.SizeOf(Byte));
  266. System.Inc(LBufStart, PKCS5_SALT_LEN);
  267. Count := cipher.ProcessBytes(PlainText, 0, System.Length(PlainText), Buf,
  268. LBufStart);
  269. System.Inc(LBufStart, Count);
  270. Count := cipher.DoFinal(Buf, LBufStart);
  271. System.Inc(LBufStart, Count);
  272. System.SetLength(Buf, LBufStart);
  273. Result := Buf;
  274. end;
  275. class procedure TUsageExamples.
  276. BinaryCompatiblePascalCoinAES256EncryptDecryptDemo(const inputmessage,
  277. password: string);
  278. var
  279. PlainText, PasswordBytes, CipherText, DecryptedCipherText: TBytes;
  280. begin
  281. PlainText := TEncoding.UTF8.GetBytes(inputmessage);
  282. PasswordBytes := TEncoding.UTF8.GetBytes(password);
  283. CipherText := TUsageExamples.AES256CBCPascalCoinEncrypt(PlainText,
  284. PasswordBytes);
  285. if TUsageExamples.AES256CBCPascalCoinDecrypt(CipherText, PasswordBytes,
  286. DecryptedCipherText) then
  287. begin
  288. if TArrayUtils.AreEqual(PlainText, DecryptedCipherText) then
  289. begin
  290. Writeln('AES_256_CBC PascalCoin Compatability Encrypt, Decrypt Was Successful '
  291. + sLineBreak);
  292. Exit;
  293. end;
  294. end;
  295. Writeln('AES_256_CBC PascalCoin Compatability Encrypt, Decrypt Failed ' +
  296. sLineBreak);
  297. end;
  298. class procedure TUsageExamples.
  299. BinaryCompatiblePascalCoinECIESDecryptExistingPayloadDemo
  300. (const PrivateKeyInHex, EncryptedMessageInHex, ACurveName: string);
  301. const
  302. MethodName = 'BinaryCompatiblePascalCoinECIESDecryptExistingPayloadDemo';
  303. var
  304. PrivateKeyBytes, PayloadToDecodeBytes, DecryptedCipherText: TBytes;
  305. Lcurve: IX9ECParameters;
  306. domain: IECDomainParameters;
  307. RegeneratedPublicKey: IECPublicKeyParameters;
  308. RegeneratedPrivateKey: IECPrivateKeyParameters;
  309. KeyPair: IAsymmetricCipherKeyPair;
  310. PrivD: TBigInteger;
  311. begin
  312. // Create From Existing Parameter Method
  313. System.Assert(PrivateKeyInHex <> '', 'PrivateKeyInHex Cannot be Empty');
  314. System.Assert(EncryptedMessageInHex <> '',
  315. 'EncryptedMessageInHex Cannot be Empty');
  316. System.Assert(ACurveName <> '', 'ACurveName Cannot be Empty');
  317. PrivateKeyBytes := THex.Decode(PrivateKeyInHex);
  318. System.Assert(PrivateKeyBytes <> Nil, 'PrivateKeyBytes Cannot be Nil');
  319. PayloadToDecodeBytes := THex.Decode(EncryptedMessageInHex);
  320. System.Assert(PayloadToDecodeBytes <> Nil,
  321. 'PayloadToDecodeBytes Cannot be Nil');
  322. Lcurve := TSecNamedCurves.GetByName(ACurveName);
  323. System.Assert(Lcurve <> Nil, 'Lcurve Cannot be Nil');
  324. // Set Up Asymmetric Key Pair from known private key ByteArray
  325. domain := TECDomainParameters.Create(Lcurve.Curve, Lcurve.G, Lcurve.N,
  326. Lcurve.H, Lcurve.GetSeed);
  327. PrivD := TBigInteger.Create(1, PrivateKeyBytes);
  328. RegeneratedPrivateKey := TECPrivateKeyParameters.Create('ECDSA',
  329. PrivD, domain);
  330. RegeneratedPublicKey := TECKeyPairGenerator.GetCorrespondingPublicKey
  331. (RegeneratedPrivateKey);
  332. KeyPair := TAsymmetricCipherKeyPair.Create(RegeneratedPublicKey,
  333. RegeneratedPrivateKey);
  334. // Do Signing and Verifying to Assert Proper Recreation Of Public and Private Key
  335. DoSigningAndVerifying(KeyPair.Public as IECPublicKeyParameters,
  336. KeyPair.Private as IECPrivateKeyParameters, MethodName, 'PascalECDSA');
  337. // Do Decryption Of Payload
  338. if TUsageExamples.ECIESPascalCoinDecrypt(RegeneratedPrivateKey,
  339. PayloadToDecodeBytes, DecryptedCipherText) then
  340. begin
  341. Writeln('ECIES PascalCoin Existing Payload Compatability Decrypt Was Successful '
  342. + sLineBreak);
  343. Writeln('Payload Message Is "' + TEncoding.UTF8.GetString
  344. (DecryptedCipherText) + '"');
  345. Exit;
  346. end;
  347. Writeln('ECIES PascalCoin Existing Payload Compatability Decrypt Failed ' +
  348. sLineBreak);
  349. end;
  350. class procedure TUsageExamples.BinaryCompatiblePascalCoinECIESEncryptDecryptDemo
  351. (const input: string);
  352. var
  353. PlainText, CipherText, DecryptedCipherText: TBytes;
  354. KeyPair: IAsymmetricCipherKeyPair;
  355. begin
  356. KeyPair := GetECKeyPair;
  357. PlainText := TEncoding.UTF8.GetBytes(input);
  358. CipherText := TUsageExamples.ECIESPascalCoinEncrypt(KeyPair.Public,
  359. PlainText);
  360. if TUsageExamples.ECIESPascalCoinDecrypt(KeyPair.Private, CipherText,
  361. DecryptedCipherText) then
  362. begin
  363. if TArrayUtils.AreEqual(PlainText, DecryptedCipherText) then
  364. begin
  365. Writeln('ECIES PascalCoin Compatability Encrypt, Decrypt Was Successful '
  366. + sLineBreak);
  367. Exit;
  368. end;
  369. end;
  370. Writeln('ECIES PascalCoin Compatability Encrypt, Decrypt Failed ' +
  371. sLineBreak);
  372. end;
  373. class function TUsageExamples.BytesToHexString(input: TBytes): String;
  374. var
  375. index: Int32;
  376. begin
  377. Result := '';
  378. for index := System.Low(input) to System.High(input) do
  379. begin
  380. if index = 0 then
  381. begin
  382. Result := Result + IntToHex(input[index], 2);
  383. end
  384. else
  385. begin
  386. Result := Result + ',' + IntToHex(input[index], 2);
  387. end;
  388. end;
  389. Result := '[' + Result + ']';
  390. end;
  391. class procedure TUsageExamples.DoSigningAndVerifying(const PublicKey
  392. : IECPublicKeyParameters; const PrivateKey: IECPrivateKeyParameters;
  393. const CallerMethod, TextToSign: String;
  394. const SigningAlgo: String = SigningAlgorithmECDSA);
  395. var
  396. Signer: ISigner;
  397. &message, sigBytes: TBytes;
  398. begin
  399. Writeln('Caller Method Is ' + CallerMethod + sLineBreak);
  400. Signer := TSignerUtilities.GetSigner(SigningAlgo);
  401. Writeln('Signer Name is: ' + Signer.AlgorithmName + sLineBreak);
  402. &message := TEncoding.UTF8.GetBytes(TextToSign);
  403. // Sign
  404. Signer.Init(True, PrivateKey);
  405. Signer.BlockUpdate(&message, 0, System.Length(&message));
  406. sigBytes := Signer.GenerateSignature();
  407. Writeln('Generated Signature is: ' + BytesToHexString(sigBytes) + sLineBreak);
  408. // Verify
  409. Signer.Init(False, PublicKey);
  410. Signer.BlockUpdate(&message, 0, System.Length(&message));
  411. if (not Signer.VerifySignature(sigBytes)) then
  412. begin
  413. Writeln(PublicKey.AlgorithmName + ' verification failed' + sLineBreak);
  414. end
  415. else
  416. begin
  417. Writeln(PublicKey.AlgorithmName + ' verification passed' + sLineBreak);
  418. end;
  419. end;
  420. class procedure TUsageExamples.GenerateKeyPairAndSignECDSA;
  421. var
  422. domain: IECDomainParameters;
  423. generator: IECKeyPairGenerator;
  424. keygenParams: IECKeyGenerationParameters;
  425. KeyPair: IAsymmetricCipherKeyPair;
  426. privParams: IECPrivateKeyParameters;
  427. pubParams: IECPublicKeyParameters;
  428. const
  429. MethodName = 'GenerateKeyPairAndSignECDSA';
  430. begin
  431. Writeln('MethodName is: ' + MethodName + sLineBreak);
  432. domain := TECDomainParameters.Create(FCurve.Curve, FCurve.G, FCurve.N,
  433. FCurve.H, FCurve.GetSeed);
  434. generator := TECKeyPairGenerator.Create('ECDSA');
  435. keygenParams := TECKeyGenerationParameters.Create(domain, FRandom);
  436. generator.Init(keygenParams);
  437. KeyPair := generator.GenerateKeyPair();
  438. privParams := KeyPair.Private as IECPrivateKeyParameters; // for signing
  439. pubParams := KeyPair.Public as IECPublicKeyParameters; // for verifying
  440. Writeln('Algorithm Name is: ' + pubParams.AlgorithmName + sLineBreak);
  441. Writeln('Public Key Normalized XCoord is: ' +
  442. pubParams.Q.Normalize.AffineXCoord.ToBigInteger.ToString(16) + sLineBreak);
  443. Writeln('Public Key Normalized YCoord is: ' +
  444. pubParams.Q.Normalize.AffineYCoord.ToBigInteger.ToString(16) + sLineBreak);
  445. Writeln('Private Key D Parameter is: ' + privParams.D.ToString(16) +
  446. sLineBreak);
  447. DoSigningAndVerifying(pubParams, privParams, MethodName, 'PascalECDSA');
  448. end;
  449. class procedure TUsageExamples.GenerateKeyPairAndSignECSchnorr;
  450. var
  451. domain: IECDomainParameters;
  452. generator: IECKeyPairGenerator;
  453. keygenParams: IECKeyGenerationParameters;
  454. KeyPair: IAsymmetricCipherKeyPair;
  455. privParams: IECPrivateKeyParameters;
  456. pubParams: IECPublicKeyParameters;
  457. const
  458. MethodName = 'GenerateKeyPairAndSignECSchnorr';
  459. begin
  460. Writeln('MethodName is: ' + MethodName + sLineBreak);
  461. domain := TECDomainParameters.Create(FCurve.Curve, FCurve.G, FCurve.N,
  462. FCurve.H, FCurve.GetSeed);
  463. generator := TECKeyPairGenerator.Create('ECSCHNORR');
  464. keygenParams := TECKeyGenerationParameters.Create(domain, FRandom);
  465. generator.Init(keygenParams);
  466. KeyPair := generator.GenerateKeyPair();
  467. privParams := KeyPair.Private as IECPrivateKeyParameters; // for signing
  468. pubParams := KeyPair.Public as IECPublicKeyParameters; // for verifying
  469. Writeln('Algorithm Name is: ' + pubParams.AlgorithmName + sLineBreak);
  470. Writeln('Public Key Normalized XCoord is: ' +
  471. pubParams.Q.Normalize.AffineXCoord.ToBigInteger.ToString(16) + sLineBreak);
  472. Writeln('Public Key Normalized YCoord is: ' +
  473. pubParams.Q.Normalize.AffineYCoord.ToBigInteger.ToString(16) + sLineBreak);
  474. Writeln('Private Key D Parameter is: ' + privParams.D.ToString(16) +
  475. sLineBreak);
  476. DoSigningAndVerifying(pubParams, privParams, MethodName, 'PascalECSCHNORR',
  477. SigningAlgorithmECSCHNORR);
  478. end;
  479. class function TUsageExamples.GetECIESPascalCoinCompatibilityEngine
  480. : IPascalCoinIESEngine;
  481. var
  482. cipher: IBufferedBlockCipher;
  483. AesEngine: IAesEngine;
  484. blockCipher: ICbcBlockCipher;
  485. ECDHBasicAgreementInstance: IECDHBasicAgreement;
  486. KDFInstance: IPascalCoinECIESKdfBytesGenerator;
  487. DigestMACInstance: IDigestMAC;
  488. begin
  489. // Set up IES Cipher Engine For Compatibility With PascalCoin
  490. ECDHBasicAgreementInstance := TECDHBasicAgreement.Create();
  491. KDFInstance := TPascalCoinECIESKdfBytesGenerator.Create
  492. (TDigestUtilities.GetDigest('SHA-512'));
  493. DigestMACInstance := TDigestUtilities.GetDigestMAC
  494. (TDigestUtilities.GetDigest('MD5'));
  495. // Set Up Block Cipher
  496. AesEngine := TAesEngine.Create(); // AES Engine
  497. blockCipher := TCbcBlockCipher.Create(AesEngine); // CBC
  498. cipher := TPaddedBufferedBlockCipher.Create(blockCipher,
  499. TZeroBytePadding.Create() as IZeroBytePadding); // ZeroBytePadding
  500. Result := TPascalCoinIESEngine.Create(ECDHBasicAgreementInstance, KDFInstance,
  501. DigestMACInstance, cipher);
  502. end;
  503. class function TUsageExamples.GetECKeyPair: IAsymmetricCipherKeyPair;
  504. var
  505. Lcurve: IX9ECParameters;
  506. domain: IECDomainParameters;
  507. KeyPairGeneratorInstance: IAsymmetricCipherKeyPairGenerator;
  508. const
  509. MethodName = 'GetECKeyPair';
  510. begin
  511. // Full Generation Method
  512. Lcurve := TSecNamedCurves.GetByName(CurveName);
  513. KeyPairGeneratorInstance := TGeneratorUtilities.GetKeyPairGenerator('ECDSA');
  514. domain := TECDomainParameters.Create(Lcurve.Curve, Lcurve.G, Lcurve.N,
  515. Lcurve.H, Lcurve.GetSeed);
  516. KeyPairGeneratorInstance.Init(TECKeyGenerationParameters.Create(domain,
  517. FRandom));
  518. Result := KeyPairGeneratorInstance.GenerateKeyPair();
  519. DoSigningAndVerifying(Result.Public as IECPublicKeyParameters,
  520. Result.Private as IECPrivateKeyParameters, MethodName, 'PascalECDSA');
  521. end;
  522. class function TUsageExamples.GetIESCipherParameters: IIESWithCipherParameters;
  523. var
  524. Derivation, Encoding, IVBytes: TBytes;
  525. MacKeySizeInBits, CipherKeySizeInBits: Int32;
  526. UsePointCompression: Boolean;
  527. begin
  528. // Set up IES Cipher Parameters For Compatibility With PascalCoin Current Implementation
  529. // The derivation and encoding vectors are used when initialising the KDF and MAC.
  530. // They're optional but if used then they need to be known by the other user so that
  531. // they can decrypt the ciphertext and verify the MAC correctly. The security is based
  532. // on the shared secret coming from the (static-ephemeral) ECDH key agreement.
  533. Derivation := Nil;
  534. Encoding := Nil;
  535. System.SetLength(IVBytes, 16); // using Zero Initialized IV for compatibility
  536. MacKeySizeInBits := 32 * 8;
  537. // Since we are using AES256_CBC for compatibility
  538. CipherKeySizeInBits := 32 * 8;
  539. // whether to use point compression when deriving the octets string
  540. // from a point or not in the EphemeralKeyPairGenerator
  541. UsePointCompression := True; // for compatibility
  542. Result := TIESWithCipherParameters.Create(Derivation, Encoding, IVBytes,
  543. MacKeySizeInBits, CipherKeySizeInBits, UsePointCompression);
  544. end;
  545. class procedure TUsageExamples.GetPublicKeyFromPrivateKey;
  546. var
  547. domain: IECDomainParameters;
  548. generator: IECKeyPairGenerator;
  549. keygenParams: IECKeyGenerationParameters;
  550. KeyPair: IAsymmetricCipherKeyPair;
  551. privParams: IECPrivateKeyParameters;
  552. pubParams, recreatedPubKeyParameters: IECPublicKeyParameters;
  553. EncodedPublicKey, RecreatedEncodedPublicKey: TBytes;
  554. qPoint: IECPoint;
  555. const
  556. MethodName = 'GetPublicKeyFromPrivateKey';
  557. begin
  558. Writeln('MethodName is: ' + MethodName + sLineBreak);
  559. domain := TECDomainParameters.Create(FCurve.Curve, FCurve.G, FCurve.N,
  560. FCurve.H, FCurve.GetSeed);
  561. generator := TECKeyPairGenerator.Create('ECDSA');
  562. keygenParams := TECKeyGenerationParameters.Create(domain, FRandom);
  563. generator.Init(keygenParams);
  564. KeyPair := generator.GenerateKeyPair();
  565. privParams := KeyPair.Private as IECPrivateKeyParameters; // for signing
  566. pubParams := KeyPair.Public as IECPublicKeyParameters; // for verifying
  567. Writeln('Algorithm Name is: ' + pubParams.AlgorithmName + sLineBreak);
  568. Writeln('Public Key Normalized XCoord is: ' +
  569. pubParams.Q.Normalize.AffineXCoord.ToBigInteger.ToString(16) + sLineBreak);
  570. Writeln('Public Key Normalized YCoord is: ' +
  571. pubParams.Q.Normalize.AffineYCoord.ToBigInteger.ToString(16) + sLineBreak);
  572. EncodedPublicKey := pubParams.Q.Normalize.GetEncoded;
  573. Writeln('Encoded Public Key is: ' + BytesToHexString(EncodedPublicKey) +
  574. sLineBreak);
  575. Writeln('Private Key D Parameter is: ' + privParams.D.ToString(16) +
  576. sLineBreak);
  577. // get public key from private key
  578. // Method One
  579. qPoint := domain.G.Multiply(privParams.D);
  580. RecreatedEncodedPublicKey := qPoint.GetEncoded();
  581. if CompareMem(PByte(EncodedPublicKey), PByte(RecreatedEncodedPublicKey),
  582. System.Length(EncodedPublicKey) * System.SizeOf(Byte)) then
  583. begin
  584. Writeln('Public Key Recreation From Private Key Was Successful' +
  585. sLineBreak);
  586. end
  587. else
  588. begin
  589. Writeln('Public Key Recreation From Private Key Failed' + sLineBreak);
  590. end;
  591. recreatedPubKeyParameters := TECPublicKeyParameters.Create(qPoint, domain);
  592. if pubParams.Equals(recreatedPubKeyParameters) then
  593. begin
  594. Writeln('Public Key Recreation Match With Original Public Key' +
  595. sLineBreak);
  596. end
  597. else
  598. begin
  599. Writeln('Public Key Recreation DOES NOT Match With Original Public Key' +
  600. sLineBreak);
  601. end;
  602. // Do Signing and Verifying to Assert Proper Recreation Of Public Key
  603. DoSigningAndVerifying(recreatedPubKeyParameters, privParams, MethodName,
  604. 'PascalECDSA');
  605. // or the easier method
  606. // Method Two (** Preferred **)
  607. recreatedPubKeyParameters := TECKeyPairGenerator.GetCorrespondingPublicKey
  608. (privParams);
  609. if pubParams.Equals(recreatedPubKeyParameters) then
  610. begin
  611. Writeln('Public Key Recreation Match With Original Public Key' +
  612. sLineBreak);
  613. end
  614. else
  615. begin
  616. Writeln('Public Key Recreation DOES NOT Match With Original Public Key' +
  617. sLineBreak);
  618. end;
  619. // Do Signing and Verifying to Assert Proper Recreation Of Public Key
  620. DoSigningAndVerifying(recreatedPubKeyParameters, privParams, MethodName,
  621. 'PascalECDSA');
  622. end;
  623. class procedure TUsageExamples.RecreatePublicAndPrivateKeyPairsFromByteArray;
  624. var
  625. domain: IECDomainParameters;
  626. generator: IECKeyPairGenerator;
  627. keygenParams: IECKeyGenerationParameters;
  628. KeyPair: IAsymmetricCipherKeyPair;
  629. privParams, RegeneratedPrivateKey: IECPrivateKeyParameters;
  630. pubParams, RegeneratedPublicKey: IECPublicKeyParameters;
  631. PublicKeyByteArray, PrivateKeyByteArray: TBytes;
  632. PrivD: TBigInteger;
  633. const
  634. MethodName = 'RecreatePublicAndPrivateKeyPairsFromByteArray';
  635. begin
  636. Writeln('MethodName is: ' + MethodName + sLineBreak);
  637. domain := TECDomainParameters.Create(FCurve.Curve, FCurve.G, FCurve.N,
  638. FCurve.H, FCurve.GetSeed);
  639. generator := TECKeyPairGenerator.Create('ECDSA');
  640. keygenParams := TECKeyGenerationParameters.Create(domain, FRandom);
  641. generator.Init(keygenParams);
  642. KeyPair := generator.GenerateKeyPair();
  643. privParams := KeyPair.Private as IECPrivateKeyParameters; // for signing
  644. pubParams := KeyPair.Public as IECPublicKeyParameters; // for verifying
  645. Writeln('Algorithm Name is: ' + pubParams.AlgorithmName + sLineBreak);
  646. Writeln('Public Key Normalized XCoord is: ' +
  647. pubParams.Q.Normalize.AffineXCoord.ToBigInteger.ToString(16) + sLineBreak);
  648. Writeln('Public Key Normalized YCoord is: ' +
  649. pubParams.Q.Normalize.AffineYCoord.ToBigInteger.ToString(16) + sLineBreak);
  650. Writeln('Private Key D Parameter is: ' + privParams.D.ToString(16) +
  651. sLineBreak);
  652. PublicKeyByteArray := pubParams.Q.GetEncoded;
  653. // using ToByteArray here because bytes are unsigned in Pascal
  654. PrivateKeyByteArray := privParams.D.ToByteArray;
  655. RegeneratedPublicKey := TECPublicKeyParameters.Create('ECDSA',
  656. FCurve.Curve.DecodePoint(PublicKeyByteArray), domain);
  657. if pubParams.Equals(RegeneratedPublicKey) then
  658. begin
  659. Writeln('Public Key Recreation Match With Original Public Key' +
  660. sLineBreak);
  661. end
  662. else
  663. begin
  664. Writeln('Public Key Recreation DOES NOT Match With Original Public Key' +
  665. sLineBreak);
  666. end;
  667. PrivD := TBigInteger.Create(PrivateKeyByteArray);
  668. RegeneratedPrivateKey := TECPrivateKeyParameters.Create('ECDSA',
  669. PrivD, domain);
  670. if privParams.Equals(RegeneratedPrivateKey) then
  671. begin
  672. Writeln('Private Key Recreation Match With Original Private Key' +
  673. sLineBreak);
  674. end
  675. else
  676. begin
  677. Writeln('Private Key Recreation DOES NOT Match With Original Private Key' +
  678. sLineBreak);
  679. end;
  680. // Do Signing and Verifying to Assert Proper Recreation Of Public Key
  681. DoSigningAndVerifying(RegeneratedPublicKey, privParams, MethodName,
  682. 'PascalECDSA');
  683. // Do Signing and Verifying to Assert Proper Recreation Of Private Key
  684. DoSigningAndVerifying(pubParams, RegeneratedPrivateKey, MethodName,
  685. 'PascalECDSA');
  686. end;
  687. class procedure TUsageExamples.RecreatePublicKeyFromXAndYCoordByteArray;
  688. var
  689. domain: IECDomainParameters;
  690. generator: IECKeyPairGenerator;
  691. keygenParams: IECKeyGenerationParameters;
  692. KeyPair: IAsymmetricCipherKeyPair;
  693. pubParams, RegeneratedPublicKey: IECPublicKeyParameters;
  694. privParams: IECPrivateKeyParameters;
  695. XCoordByteArray, YCoordByteArray: TBytes;
  696. BigXCoord, BigYCoord, BigXCoordRecreated, BigYCoordRecreated: TBigInteger;
  697. point: IECPoint;
  698. const
  699. MethodName = 'RecreatePublicKeyFromXAndYCoordByteArray';
  700. begin
  701. Writeln('MethodName is: ' + MethodName + sLineBreak);
  702. domain := TECDomainParameters.Create(FCurve.Curve, FCurve.G, FCurve.N,
  703. FCurve.H, FCurve.GetSeed);
  704. generator := TECKeyPairGenerator.Create('ECDSA');
  705. keygenParams := TECKeyGenerationParameters.Create(domain, FRandom);
  706. generator.Init(keygenParams);
  707. KeyPair := generator.GenerateKeyPair();
  708. privParams := KeyPair.Private as IECPrivateKeyParameters; // for signing
  709. pubParams := KeyPair.Public as IECPublicKeyParameters; // for verifying
  710. Writeln('Algorithm Name is: ' + pubParams.AlgorithmName + sLineBreak);
  711. BigXCoord := pubParams.Q.Normalize.AffineXCoord.ToBigInteger;
  712. BigYCoord := pubParams.Q.Normalize.AffineYCoord.ToBigInteger;
  713. Writeln('Public Key Normalized XCoord is: ' + BigXCoord.ToString(16) +
  714. sLineBreak);
  715. Writeln('Public Key Normalized YCoord is: ' + BigYCoord.ToString(16) +
  716. sLineBreak);
  717. XCoordByteArray := BigXCoord.ToByteArray;
  718. YCoordByteArray := BigYCoord.ToByteArray;
  719. BigXCoordRecreated := TBigInteger.Create(1, XCoordByteArray);
  720. BigYCoordRecreated := TBigInteger.Create(1, YCoordByteArray);
  721. point := FCurve.Curve.CreatePoint(BigXCoordRecreated, BigYCoordRecreated);
  722. RegeneratedPublicKey := TECPublicKeyParameters.Create(point, domain);
  723. if pubParams.Equals(RegeneratedPublicKey) then
  724. begin
  725. Writeln('Public Key Recreation Match With Original Public Key' +
  726. sLineBreak);
  727. end
  728. else
  729. begin
  730. Writeln('Public Key Recreation DOES NOT Match With Original Public Key' +
  731. sLineBreak);
  732. end;
  733. // Do Signing and Verifying to Assert Proper Recreation Of Public Key
  734. DoSigningAndVerifying(RegeneratedPublicKey, privParams, MethodName,
  735. 'PascalECDSA');
  736. end;
  737. class constructor TUsageExamples.UsageExamples;
  738. begin
  739. FRandom := TSecureRandom.Create();
  740. FCurve := TSecNamedCurves.GetByName(CurveName);
  741. end;
  742. end.