UsageExamples.pas 32 KB

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