UsageExamples.pas 33 KB

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