UPCCryptoLib4Pascal.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. unit UPCCryptoLib4Pascal;
  2. { Copyright (c) 2019 by Albert Molina
  3. Distributed under the MIT software license, see the accompanying file LICENSE
  4. or visit http://www.opensource.org/licenses/mit-license.php.
  5. This unit is a part of the PascalCoin Project, an infinitely scalable
  6. cryptocurrency. Find us here:
  7. Web: https://www.pascalcoin.org
  8. Source: https://github.com/PascalCoin/PascalCoin
  9. If you like it, consider a donation using Bitcoin:
  10. 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
  11. This unit contains code made by Ugochukwu Mmaduekwe (aka Xor-el at GitHub)
  12. https://github.com/PascalCoin/PascalCoinTools/tree/master/Tools/PascalCoinKeyTool
  13. Available under MIT License
  14. THIS LICENSE HEADER MUST NOT BE REMOVED.
  15. }
  16. {
  17. This unit is a bridge between PascalCoin and CryptoLib4Pascal in order to
  18. do not use OpenSSL library to do some cryptographic functions.
  19. Specially will define:
  20. - Use of BigIntegers
  21. - ECDSA keys generation
  22. - ECDSA Sign
  23. - ECDSA Verify
  24. - PascalCoin ECDSA encryption
  25. - PascalCoin AES encryption
  26. }
  27. interface
  28. Uses SysUtils, UBaseTypes, UPCDataTypes,
  29. ClpBigInteger,
  30. ClpSecureRandom,
  31. ClpISecureRandom,
  32. ClpIECDomainParameters,
  33. ClpECDomainParameters,
  34. ClpIX9ECParameters,
  35. ClpIIESEngine,
  36. ClpIBaseKdfBytesGenerator,
  37. ClpIIESWithCipherParameters,
  38. ClpIPascalCoinECIESKdfBytesGenerator,
  39. ClpIPascalCoinIESEngine
  40. ;
  41. Type
  42. TPCCryptoLib4Pascal = Class
  43. strict private
  44. const
  45. PKCS5_SALT_LEN = Int32(8);
  46. SALT_MAGIC_LEN = Int32(8);
  47. SALT_SIZE = Int32(8);
  48. SALT_MAGIC: string = 'Salted__';
  49. strict private
  50. class var FRandom: ISecureRandom;
  51. class var FDomain_SECP256K1 : IECDomainParameters;
  52. class var FDomain_SECP384R1 : IECDomainParameters;
  53. class var FDomain_SECT283K1 : IECDomainParameters;
  54. class var FDomain_SECP521R1 : IECDomainParameters;
  55. class var FCurve_SECP256K1 : IX9ECParameters;
  56. class var FCurve_SECP384R1 : IX9ECParameters;
  57. class var FCurve_SECT283K1 : IX9ECParameters;
  58. class var FCurve_SECP521R1 : IX9ECParameters;
  59. class var FPascalCoinIESEngine : IPascalCoinIESEngine;
  60. class var FPascalCoinIESWithCipherParameters : IIESWithCipherParameters;
  61. class constructor TPCCryptoLib4Pascal();
  62. class function GetCurveAndDomainParameters(const AEC_OpenSSL_NID : Word; var OCurve : IX9ECParameters; var ODomain : IECDomainParameters; ARaiseIfNotForPascal : Boolean = True ) : Boolean;
  63. class function GetDomainParameters(const AEC_OpenSSL_NID : Word) : IECDomainParameters;
  64. class function EVP_GetSalt(): TBytes; static; inline;
  65. class function EVP_GetKeyIV(const APasswordBytes, ASaltBytes: TBytes; out AKeyBytes, AIVBytes: TBytes): boolean; static;
  66. protected
  67. public
  68. class function DoECDSASign(const AEC_OpenSSL_NID : Word; const APrivateKey, AMessage: TBytes; var ASignature : TECDSA_SIG) : Boolean;
  69. class function DoECDSAVerify(const APublicKey : TECDSA_Public; const AMessage: TBytes; const ASignature : TECDSA_SIG) : Boolean;
  70. class function DoPascalCoinECIESEncrypt(const APublicKey : TECDSA_Public; const AMessage : TBytes; var AEncryptedMessage : TBytes) : Boolean;
  71. class function DoPascalCoinECIESDecrypt(const AEC_OpenSSL_NID : Word; const APrivateKey, AEncryptedMessage : TBytes; var ADecryptedMessage : TBytes) : Boolean;
  72. class function DoPascalCoinAESEncrypt(const AMessage, APassword: TBytes): TBytes; static;
  73. class function DoPascalCoinAESDecrypt(const AEncryptedMessage, APassword: TBytes; out ADecryptedMessage: TBytes): boolean; static;
  74. class function DoGetRandomPrivateKey(const AEC_OpenSSL_NID : Word) : TBytes;
  75. class function DoGetPublicKey(const AEC_OpenSSL_NID : Word; const APrivateKey: TBytes) : TECDSA_Public;
  76. class procedure DoSHA256(const AInput : TBytes; var AOutput : TBytes);
  77. class procedure DoRIPEMD160(const AInput : TBytes; var AOutput : TBytes);
  78. End;
  79. implementation
  80. Uses
  81. ClpCustomNamedCurves,
  82. ClpIECPrivateKeyParameters,
  83. ClpECPrivateKeyParameters,
  84. ClpIParametersWithRandom,
  85. ClpParametersWithRandom,
  86. ClpIECDsaSigner,
  87. ClpECDsaSigner,
  88. ClpCryptoLibTypes,
  89. //
  90. ClpIECPublicKeyParameters,
  91. ClpECPublicKeyParameters,
  92. ClpIECC,
  93. //
  94. ClpIIESCipher,
  95. ClpIESCipher,
  96. ClpIBufferedBlockCipher,
  97. ClpIAesEngine,
  98. ClpIBlockCipherModes,
  99. ClpIBasicAgreement,
  100. ClpIESWithCipherParameters,
  101. ClpIECDHBasicAgreement,
  102. ClpIMac,
  103. ClpECDHBasicAgreement,
  104. ClpPascalCoinECIESKdfBytesGenerator,
  105. ClpDigestUtilities,
  106. ClpMacUtilities,
  107. ClpAesEngine,
  108. ClpBlockCipherModes,
  109. ClpPaddedBufferedBlockCipher,
  110. ClpPaddingModes,
  111. ClpIPaddingModes,
  112. ClpPascalCoinIESEngine,
  113. //
  114. ClpIParametersWithIV,
  115. ClpIBufferedCipher,
  116. ClpArrayUtils,
  117. ClpCipherUtilities,
  118. ClpParametersWithIV,
  119. ClpParameterUtilities,
  120. ClpIDigest,
  121. //
  122. ClpIAsymmetricCipherKeyPairGenerator,
  123. ClpGeneratorUtilities,
  124. ClpECKeyGenerationParameters,
  125. ClpIECKeyGenerationParameters,
  126. ClpIAsymmetricCipherKeyPair,
  127. ClpECKeyPairGenerator,
  128. //
  129. HlpSHA2_256,
  130. //
  131. UAccounts,
  132. UConst,
  133. ULog;
  134. { TPCCryptoLib4Pascal }
  135. class function TPCCryptoLib4Pascal.DoECDSASign(const AEC_OpenSSL_NID : Word;
  136. Const APrivateKey, AMessage: TBytes; var ASignature: TECDSA_SIG): Boolean;
  137. var
  138. LDomain: IECDomainParameters;
  139. LPrivD: TBigInteger;
  140. LPrivKeyParams : IECPrivateKeyParameters;
  141. LParam: IParametersWithRandom;
  142. LSigner : IECDsaSigner;
  143. LSignerResult : TCryptoLibGenericArray<TBigInteger>;
  144. begin
  145. LDomain := GetDomainParameters(AEC_OpenSSL_NID);
  146. LPrivD := TBigInteger.Create(1, APrivateKey);
  147. LPrivKeyParams := TECPrivateKeyParameters.Create('ECDSA',LPrivD,LDomain);
  148. //
  149. LParam := TParametersWithRandom.Create(LPrivKeyParams, FRandom);
  150. LSigner := TECDsaSigner.Create();
  151. LSigner.Init(True, LParam);
  152. LSignerResult := LSigner.GenerateSignature(AMessage);
  153. ASignature.r := LSignerResult[0].ToByteArray();
  154. ASignature.s := LSignerResult[1].ToByteArray();
  155. Result := True;
  156. end;
  157. class function TPCCryptoLib4Pascal.DoECDSAVerify(const APublicKey: TECDSA_Public; const AMessage: TBytes; const ASignature: TECDSA_SIG): Boolean;
  158. var
  159. LDomain: IECDomainParameters;
  160. LCurve: IX9ECParameters;
  161. LSigner: IECDsaSigner;
  162. LPubKeyParams : IECPublicKeyParameters;
  163. LPoint: IECPoint;
  164. LBigXCoord, LBigYCoord,
  165. LSigR, LSigS: TBigInteger;
  166. begin
  167. GetCurveAndDomainParameters(APublicKey.EC_OpenSSL_NID,LCurve,LDomain);
  168. LBigXCoord := TBigInteger.Create(1, APublicKey.x);
  169. LBigYCoord := TBigInteger.Create(1, APublicKey.y);
  170. LPoint := LCurve.Curve.CreatePoint(LBigXCoord, LBigYCoord);
  171. LPubKeyParams := TECPublicKeyParameters.Create('ECDSA', LPoint, LDomain);
  172. LSigR := TBigInteger.Create(1, ASignature.r);
  173. LSigS := TBigInteger.Create(1, ASignature.s);
  174. LSigner := TECDsaSigner.Create();
  175. LSigner.Init(False, LPubKeyParams);
  176. Result := LSigner.VerifySignature(AMessage, LSigR, LSigS);
  177. end;
  178. class function TPCCryptoLib4Pascal.DoGetPublicKey(const AEC_OpenSSL_NID: Word; const APrivateKey: TBytes): TECDSA_Public;
  179. var
  180. LDomain: IECDomainParameters;
  181. LPrivD : TBigInteger;
  182. LECPrivateKeyParameters : IECPrivateKeyParameters;
  183. LPublicKey: IECPublicKeyParameters;
  184. begin
  185. LDomain := GetDomainParameters(AEC_OpenSSL_NID);
  186. LPrivD := TBigInteger.Create(1,APrivateKey); // Obtain a big num based on private key
  187. LECPrivateKeyParameters := TECPrivateKeyParameters.Create('ECDSA',LPrivD,LDomain);
  188. LPublicKey := TECKeyPairGenerator.GetCorrespondingPublicKey(LECPrivateKeyParameters);
  189. Result.EC_OpenSSL_NID := AEC_OpenSSL_NID;
  190. Result.X := LPublicKey.Q.AffineXCoord.ToBigInteger().ToByteArray();
  191. Result.Y := LPublicKey.Q.AffineYCoord.ToBigInteger().ToByteArray();
  192. end;
  193. class function TPCCryptoLib4Pascal.DoGetRandomPrivateKey(const AEC_OpenSSL_NID: Word): TBytes;
  194. var
  195. LDomain: IECDomainParameters;
  196. LCurve: IX9ECParameters;
  197. KeyPairGeneratorInstance: IAsymmetricCipherKeyPairGenerator;
  198. LKeyPair: IAsymmetricCipherKeyPair;
  199. LPrivateKey: IECPrivateKeyParameters;
  200. begin
  201. GetCurveAndDomainParameters(AEC_OpenSSL_NID,LCurve,LDomain);
  202. KeyPairGeneratorInstance := TGeneratorUtilities.GetKeyPairGenerator('ECDSA');
  203. KeyPairGeneratorInstance.Init(TECKeyGenerationParameters.Create(LDomain, FRandom) as IECKeyGenerationParameters);
  204. LKeyPair := KeyPairGeneratorInstance.GenerateKeyPair();
  205. LPrivateKey := LKeyPair.&Private as IECPrivateKeyParameters;
  206. Result := LPrivateKey.D.ToByteArray();
  207. end;
  208. class function TPCCryptoLib4Pascal.DoPascalCoinAESDecrypt(
  209. const AEncryptedMessage, APassword: TBytes; out ADecryptedMessage: TBytes): boolean;
  210. var
  211. SaltBytes, KeyBytes, IVBytes, Buf, Chopped: TRawBytes;
  212. KeyParametersWithIV: IParametersWithIV;
  213. cipher: IBufferedCipher;
  214. LBufStart, LSrcStart, LCount: Int32;
  215. begin
  216. try
  217. System.SetLength(SaltBytes, SALT_SIZE);
  218. // First read the magic text and the salt - if any
  219. Chopped := System.Copy(AEncryptedMessage, 0, SALT_MAGIC_LEN);
  220. if (System.Length(AEncryptedMessage) >= SALT_MAGIC_LEN) and
  221. (Chopped.ToString = SALT_MAGIC) then
  222. begin
  223. System.Move(AEncryptedMessage[SALT_MAGIC_LEN], SaltBytes[0], SALT_SIZE);
  224. if not EVP_GetKeyIV(APassword, SaltBytes, KeyBytes, IVBytes) then
  225. begin
  226. Result := False;
  227. Exit;
  228. end;
  229. LSrcStart := SALT_MAGIC_LEN + SALT_SIZE;
  230. end
  231. else
  232. begin
  233. if not EVP_GetKeyIV(APassword, nil, KeyBytes, IVBytes) then
  234. begin
  235. Result := False;
  236. Exit;
  237. end;
  238. LSrcStart := 0;
  239. end;
  240. cipher := TCipherUtilities.GetCipher('AES/CBC/PKCS7PADDING');
  241. KeyParametersWithIV := TParametersWithIV.Create(TParameterUtilities.CreateKeyParameter('AES', KeyBytes), IVBytes);
  242. cipher.Init(False, KeyParametersWithIV); // init decryption cipher
  243. System.SetLength(Buf, System.Length(AEncryptedMessage));
  244. LBufStart := 0;
  245. LCount := cipher.ProcessBytes(AEncryptedMessage, LSrcStart, System.Length(AEncryptedMessage) - LSrcStart, Buf, LBufStart);
  246. System.Inc(LBufStart, LCount);
  247. LCount := cipher.DoFinal(Buf, LBufStart);
  248. System.Inc(LBufStart, LCount);
  249. System.SetLength(Buf, LBufStart);
  250. ADecryptedMessage := System.Copy(Buf);
  251. Result := True;
  252. except
  253. Result := False;
  254. end;
  255. end;
  256. class function TPCCryptoLib4Pascal.DoPascalCoinAESEncrypt(const AMessage, APassword: TBytes): TBytes;
  257. var
  258. SaltBytes, KeyBytes, IVBytes, Buf, LAuxBuf: TRawBytes;
  259. KeyParametersWithIV: IParametersWithIV;
  260. cipher: IBufferedCipher;
  261. LBlockSize, LBufStart, Count: Int32;
  262. begin
  263. SaltBytes := EVP_GetSalt();
  264. EVP_GetKeyIV(APassword, SaltBytes, KeyBytes, IVBytes);
  265. cipher := TCipherUtilities.GetCipher('AES/CBC/PKCS7PADDING');
  266. KeyParametersWithIV := TParametersWithIV.Create
  267. (TParameterUtilities.CreateKeyParameter('AES', KeyBytes), IVBytes);
  268. cipher.Init(True, KeyParametersWithIV); // init encryption cipher
  269. LBlockSize := cipher.GetBlockSize;
  270. System.SetLength(Buf, System.Length(AMessage) + LBlockSize + SALT_MAGIC_LEN + PKCS5_SALT_LEN);
  271. LBufStart := 0;
  272. LAuxBuf.FromString(SALT_MAGIC);
  273. System.Move(LAuxBuf[0], Buf[LBufStart], SALT_MAGIC_LEN * System.SizeOf(byte));
  274. System.Inc(LBufStart, SALT_MAGIC_LEN);
  275. System.Move(SaltBytes[0], Buf[LBufStart], PKCS5_SALT_LEN * System.SizeOf(byte));
  276. System.Inc(LBufStart, PKCS5_SALT_LEN);
  277. Count := cipher.ProcessBytes(AMessage, 0, System.Length(AMessage), Buf, LBufStart);
  278. System.Inc(LBufStart, Count);
  279. Count := cipher.DoFinal(Buf, LBufStart);
  280. System.Inc(LBufStart, Count);
  281. System.SetLength(Buf, LBufStart);
  282. Result := Buf;
  283. end;
  284. class function TPCCryptoLib4Pascal.DoPascalCoinECIESDecrypt(
  285. const AEC_OpenSSL_NID: Word; const APrivateKey, AEncryptedMessage: TBytes;
  286. var ADecryptedMessage: TBytes): Boolean;
  287. var
  288. LDomain: IECDomainParameters;
  289. LPrivD: TBigInteger;
  290. LPrivKeyParams : IECPrivateKeyParameters;
  291. LCurve: IX9ECParameters;
  292. LBigXCoord, LBigYCoord : TBigInteger;
  293. LPoint: IECPoint;
  294. LPubKeyParams : IECPublicKeyParameters;
  295. //
  296. LCipherDecrypt: IIESCipher;
  297. begin
  298. try
  299. LDomain := GetDomainParameters(AEC_OpenSSL_NID);
  300. LPrivD := TBigInteger.Create(1, APrivateKey);
  301. LPrivKeyParams := TECPrivateKeyParameters.Create('ECDSA',LPrivD,LDomain);
  302. // Decryption
  303. LCipherDecrypt := TIESCipher.Create(FPascalCoinIESEngine);
  304. LCipherDecrypt.Init(False, LPrivKeyParams, FPascalCoinIESWithCipherParameters, FRandom);
  305. ADecryptedMessage := System.Copy(LCipherDecrypt.DoFinal(AEncryptedMessage));
  306. Result := True;
  307. except
  308. Result := False;
  309. end;
  310. end;
  311. class function TPCCryptoLib4Pascal.DoPascalCoinECIESEncrypt(
  312. const APublicKey: TECDSA_Public; const AMessage: TBytes;
  313. var AEncryptedMessage: TBytes): Boolean;
  314. var
  315. LDomain: IECDomainParameters;
  316. LCurve: IX9ECParameters;
  317. LBigXCoord, LBigYCoord : TBigInteger;
  318. LPoint: IECPoint;
  319. LPubKeyParams : IECPublicKeyParameters;
  320. //
  321. LCipherEncrypt: IIESCipher;
  322. begin
  323. GetCurveAndDomainParameters(APublicKey.EC_OpenSSL_NID,LCurve,LDomain);
  324. LBigXCoord := TBigInteger.Create(1, APublicKey.x);
  325. LBigYCoord := TBigInteger.Create(1, APublicKey.y);
  326. LPoint := LCurve.Curve.CreatePoint(LBigXCoord, LBigYCoord);
  327. LPubKeyParams := TECPublicKeyParameters.Create('ECDSA', LPoint, LDomain);
  328. // Encryption
  329. LCipherEncrypt := TIESCipher.Create(FPascalCoinIESEngine);
  330. LCipherEncrypt.Init(True, LPubKeyParams, FPascalCoinIESWithCipherParameters, FRandom);
  331. AEncryptedMessage := LCipherEncrypt.DoFinal(AMessage);
  332. Result := True;
  333. end;
  334. class procedure TPCCryptoLib4Pascal.DoRIPEMD160(const AInput: TBytes; var AOutput: TBytes);
  335. begin
  336. AOutput := TDigestUtilities.CalculateDigest('RIPEMD160', AInput);
  337. end;
  338. class procedure TPCCryptoLib4Pascal.DoSHA256(const AInput: TBytes; var AOutput: TBytes);
  339. begin
  340. AOutput := TDigestUtilities.CalculateDigest('SHA-256', AInput);
  341. end;
  342. class function TPCCryptoLib4Pascal.EVP_GetKeyIV(const APasswordBytes,
  343. ASaltBytes: TBytes; out AKeyBytes, AIVBytes: TBytes): boolean;
  344. var
  345. LKey, LIV: Int32;
  346. LDigest: IDigest;
  347. begin
  348. LKey := 32; // AES256 CBC Key Length
  349. LIV := 16; // AES256 CBC IV Length
  350. System.SetLength(AKeyBytes, LKey);
  351. System.SetLength(AIVBytes, LKey);
  352. // Max size to start then reduce it at the end
  353. LDigest := TDigestUtilities.GetDigest('SHA-256'); // SHA2_256
  354. System.Assert(LDigest.GetDigestSize >= LKey);
  355. System.Assert(LDigest.GetDigestSize >= LIV);
  356. // Derive Key First
  357. LDigest.BlockUpdate(APasswordBytes, 0, System.Length(APasswordBytes));
  358. if ASaltBytes <> Nil then
  359. begin
  360. LDigest.BlockUpdate(ASaltBytes, 0, System.Length(ASaltBytes));
  361. end;
  362. LDigest.DoFinal(AKeyBytes, 0);
  363. // Derive IV Next
  364. LDigest.Reset();
  365. LDigest.BlockUpdate(AKeyBytes, 0, System.Length(AKeyBytes));
  366. LDigest.BlockUpdate(APasswordBytes, 0, System.Length(APasswordBytes));
  367. if ASaltBytes <> Nil then
  368. begin
  369. LDigest.BlockUpdate(ASaltBytes, 0, System.Length(ASaltBytes));
  370. end;
  371. LDigest.DoFinal(AIVBytes, 0);
  372. System.SetLength(AIVBytes, LIV);
  373. Result := True;
  374. end;
  375. class function TPCCryptoLib4Pascal.EVP_GetSalt: TBytes;
  376. begin
  377. System.SetLength(Result, PKCS5_SALT_LEN);
  378. FRandom.NextBytes(Result);
  379. end;
  380. class function TPCCryptoLib4Pascal.GetCurveAndDomainParameters(
  381. const AEC_OpenSSL_NID: Word; var OCurve: IX9ECParameters;
  382. var ODomain: IECDomainParameters; ARaiseIfNotForPascal: Boolean): Boolean;
  383. begin
  384. Result := True;
  385. case AEC_OpenSSL_NID of
  386. CT_NID_secp256k1 : begin
  387. OCurve := FCurve_SECP256K1;
  388. ODomain := FDomain_SECP256K1;
  389. end;
  390. CT_NID_secp384r1 : begin
  391. OCurve := FCurve_SECP384R1;
  392. ODomain := FDomain_SECP384R1;
  393. end;
  394. CT_NID_secp521r1 : begin
  395. OCurve := FCurve_SECP521R1;
  396. ODomain := FDomain_SECP521R1;
  397. end;
  398. CT_NID_sect283k1 : begin
  399. OCurve := FCurve_SECT283K1;
  400. ODomain := FDomain_SECT283K1;
  401. end;
  402. else
  403. if ARaiseIfNotForPascal then raise Exception.Create(Format('Invalid Curve type:%d',[AEC_OpenSSL_NID]))
  404. else Result := False;
  405. end;
  406. end;
  407. class function TPCCryptoLib4Pascal.GetDomainParameters(const AEC_OpenSSL_NID: Word): IECDomainParameters;
  408. begin
  409. case AEC_OpenSSL_NID of
  410. CT_NID_secp256k1 : Result := FDomain_SECP256K1;
  411. CT_NID_secp384r1 : Result := FDomain_SECP384R1;
  412. CT_NID_secp521r1 : Result := FDomain_SECP521R1;
  413. CT_NID_sect283k1 : Result := FDomain_SECT283K1;
  414. else raise Exception.Create(Format('Invalid Curve type:%d',[AEC_OpenSSL_NID]));
  415. end;
  416. end;
  417. class constructor TPCCryptoLib4Pascal.TPCCryptoLib4Pascal;
  418. function GetIESCipherParameters: IIESWithCipherParameters;
  419. var
  420. Derivation, Encoding, IVBytes: TBytes;
  421. MacKeySizeInBits, CipherKeySizeInBits: Int32;
  422. UsePointCompression: boolean;
  423. begin
  424. // Set up IES Cipher Parameters For Compatibility With PascalCoin Current Implementation
  425. // The derivation and encoding vectors are used when initialising the KDF and MAC.
  426. // They're optional but if used then they need to be known by the other user so that
  427. // they can decrypt the ciphertext and verify the MAC correctly. The security is based
  428. // on the shared secret coming from the (static-ephemeral) ECDH key agreement.
  429. Derivation := nil;
  430. Encoding := nil;
  431. System.SetLength(IVBytes, 16); // using Zero Initialized IV for compatibility
  432. MacKeySizeInBits := 32 * 8;
  433. // Since we are using AES256_CBC for compatibility
  434. CipherKeySizeInBits := 32 * 8;
  435. // whether to use point compression when deriving the octets string
  436. // from a point or not in the EphemeralKeyPairGenerator
  437. UsePointCompression := True; // for compatibility
  438. Result := TIESWithCipherParameters.Create(Derivation, Encoding,
  439. MacKeySizeInBits, CipherKeySizeInBits, IVBytes, UsePointCompression);
  440. end;
  441. function GetECIESPascalCoinCompatibilityEngine(): IPascalCoinIESEngine;
  442. var
  443. cipher: IBufferedBlockCipher;
  444. AesEngine: IAesEngine;
  445. blockCipher: ICbcBlockCipher;
  446. ECDHBasicAgreementInstance: IECDHBasicAgreement;
  447. KDFInstance: IPascalCoinECIESKdfBytesGenerator;
  448. DigestMACInstance: IMac;
  449. begin
  450. // Set up IES Cipher Engine For Compatibility With PascalCoin
  451. ECDHBasicAgreementInstance := TECDHBasicAgreement.Create();
  452. KDFInstance := TPascalCoinECIESKdfBytesGenerator.Create
  453. (TDigestUtilities.GetDigest('SHA-512'));
  454. DigestMACInstance := TMacUtilities.GetMac('HMAC-MD5');
  455. // Set Up Block Cipher
  456. AesEngine := TAesEngine.Create(); // AES Engine
  457. blockCipher := TCbcBlockCipher.Create(AesEngine); // CBC
  458. cipher := TPaddedBufferedBlockCipher.Create(blockCipher,
  459. TZeroBytePadding.Create() as IZeroBytePadding); // ZeroBytePadding
  460. Result := TPascalCoinIESEngine.Create(ECDHBasicAgreementInstance, KDFInstance,
  461. DigestMACInstance, cipher);
  462. end;
  463. var LCipher: IBufferedBlockCipher;
  464. LAesEngine: IAesEngine;
  465. blockCipher: ICbcBlockCipher;
  466. ECDHBasicAgreementInstance: IECDHBasicAgreement;
  467. KDFInstance: IPascalCoinECIESKdfBytesGenerator;
  468. DigestMACInstance: IMac;
  469. begin
  470. FRandom := TSecureRandom.Create();
  471. // Init Curves and Domains for quick usage
  472. FCurve_SECP256K1 := TCustomNamedCurves.GetByName('SECP256K1');
  473. FDomain_SECP256K1 := TECDomainParameters.Create(FCurve_SECP256K1.Curve, FCurve_SECP256K1.G, FCurve_SECP256K1.N, FCurve_SECP256K1.H, FCurve_SECP256K1.GetSeed);
  474. FCurve_SECP384R1 := TCustomNamedCurves.GetByName('SECP384R1');
  475. FDomain_SECP384R1 := TECDomainParameters.Create(FCurve_SECP384R1.Curve, FCurve_SECP384R1.G, FCurve_SECP384R1.N, FCurve_SECP384R1.H, FCurve_SECP384R1.GetSeed);
  476. FCurve_SECT283K1 := TCustomNamedCurves.GetByName('SECT283K1');
  477. FDomain_SECT283K1 := TECDomainParameters.Create(FCurve_SECT283K1.Curve, FCurve_SECT283K1.G, FCurve_SECT283K1.N, FCurve_SECT283K1.H, FCurve_SECT283K1.GetSeed);
  478. FCurve_SECP521R1 := TCustomNamedCurves.GetByName('SECP521R1');
  479. FDomain_SECP521R1 := TECDomainParameters.Create(FCurve_SECP521R1.Curve, FCurve_SECP521R1.G, FCurve_SECP521R1.N, FCurve_SECP521R1.H, FCurve_SECP521R1.GetSeed);
  480. // Init ECIES
  481. FPascalCoinIESEngine := GetECIESPascalCoinCompatibilityEngine;
  482. FPascalCoinIESWithCipherParameters := GetIESCipherParameters;
  483. end;
  484. end.