UsageExamples.pas 32 KB

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