ClpPascalCoinIESEngine.pas 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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 ClpPascalCoinIESEngine;
  14. {$I CryptoLib.inc}
  15. interface
  16. uses
  17. SysUtils,
  18. Classes,
  19. ClpIMac,
  20. ClpIPascalCoinIESEngine,
  21. ClpICipherParameters,
  22. ClpKeyParameter,
  23. ClpIKeyParameter,
  24. ClpParametersWithIV,
  25. ClpIKeyParser,
  26. ClpIEphemeralKeyPair,
  27. ClpKdfParameters,
  28. ClpIKdfParameters,
  29. ClpIESEngine,
  30. ClpArrayUtils,
  31. ClpBigInteger,
  32. ClpBigIntegers,
  33. ClpCryptoLibTypes;
  34. resourcestring
  35. SErrorRecoveringEphemeralPublicKey =
  36. 'Unable to Recover Ephemeral Public Key: "%s"';
  37. SInvalidCipherTextLength =
  38. 'Length of Input Must be Greater than the MAC and V Combined';
  39. SInvalidMAC = 'Invalid MAC';
  40. SCipherCannotbeNilInThisMode = 'Cipher Cannot be Nil in This Mode.';
  41. type
  42. /// <summary>
  43. /// Compatibility Class for PascalCoin IESEngine
  44. /// </summary>
  45. TPascalCoinIESEngine = class(TIESEngine, IPascalCoinIESEngine)
  46. strict private
  47. type
  48. /// <summary>
  49. /// Structure for Compatibility with PascalCoin Original
  50. /// Implementation.
  51. /// </summary>
  52. TSecureHead = record
  53. Key: Byte;
  54. Mac: Byte;
  55. Orig: UInt16;
  56. Body: UInt16;
  57. end;
  58. const
  59. /// <summary>
  60. /// <b>SizeOf <paramref name="TSecureHead" /></b>. <br />
  61. /// </summary>
  62. // SECURE_HEAD_SIZE = Int32(6);
  63. SECURE_HEAD_SIZE = System.SizeOf(TSecureHead);
  64. strict protected
  65. function EncryptBlock(const &in: TCryptoLibByteArray; inOff, inLen: Int32)
  66. : TCryptoLibByteArray; override;
  67. function DecryptBlock(const in_enc: TCryptoLibByteArray;
  68. inOff, inLen: Int32): TCryptoLibByteArray; override;
  69. public
  70. function ProcessBlock(const &in: TCryptoLibByteArray; inOff, inLen: Int32)
  71. : TCryptoLibByteArray; override;
  72. end;
  73. implementation
  74. { TPascalCoinIESEngine }
  75. function TPascalCoinIESEngine.DecryptBlock(const in_enc: TCryptoLibByteArray;
  76. inOff, inLen: Int32): TCryptoLibByteArray;
  77. var
  78. K1, K2, T1, T2: TCryptoLibByteArray;
  79. cp: ICipherParameters;
  80. begin
  81. // Ensure that the length of the input is greater than the MAC in bytes
  82. if (inLen < (System.Length(FV) + Fmac.GetMacSize)) then
  83. begin
  84. raise EInvalidCipherTextCryptoLibException.CreateRes
  85. (@SInvalidCipherTextLength);
  86. end;
  87. // note order is important: set up keys, do simple encryptions, check mac, do final encryption.
  88. if (Fcipher = Nil) then
  89. begin
  90. raise EArgumentNilCryptoLibException.CreateRes
  91. (@SCipherCannotbeNilInThisMode);
  92. end
  93. else
  94. begin
  95. // Block cipher mode.
  96. SetupBlockCipherAndMacKeyBytes(K1, K2);
  97. cp := TKeyParameter.Create(K1);
  98. // If iv is provided use it to initialise the cipher
  99. if (FIV <> Nil) then
  100. begin
  101. cp := TParametersWithIV.Create(cp, FIV);
  102. end;
  103. Fcipher.Init(False, cp);
  104. end;
  105. // Verify the MAC.
  106. T1 := System.Copy(in_enc, System.Length(FV), Fmac.GetMacSize);
  107. System.SetLength(T2, System.Length(T1));
  108. Fmac.Init((TKeyParameter.Create(K2) as IKeyParameter) as ICipherParameters);
  109. Fmac.BlockUpdate(in_enc, inOff + System.Length(FV) + System.Length(T2),
  110. inLen - System.Length(FV) - System.Length(T2));
  111. T2 := Fmac.DoFinal();
  112. if (not TArrayUtils.ConstantTimeAreEqual(T1, T2)) then
  113. begin
  114. raise EInvalidCipherTextCryptoLibException.CreateRes(@SInvalidMAC);
  115. end;
  116. Result := Fcipher.DoFinal(in_enc, inOff + System.Length(FV) + Fmac.GetMacSize,
  117. inLen - System.Length(FV) - System.Length(T2));
  118. Exit;
  119. end;
  120. function TPascalCoinIESEngine.EncryptBlock(const &in: TCryptoLibByteArray;
  121. inOff, inLen: Int32): TCryptoLibByteArray;
  122. var
  123. C, K1, K2, T: TCryptoLibByteArray;
  124. MessageToEncryptPadSize, CipherBlockSize, MessageToEncryptSize: Int32;
  125. begin
  126. if (Fcipher = Nil) then
  127. begin
  128. raise EArgumentNilCryptoLibException.CreateRes
  129. (@SCipherCannotbeNilInThisMode);
  130. end
  131. else
  132. begin
  133. // Block cipher mode.
  134. SetupBlockCipherAndMacKeyBytes(K1, K2);
  135. // If iv is provided use it to initialise the cipher
  136. if (FIV <> Nil) then
  137. begin
  138. Fcipher.Init(true, TParametersWithIV.Create(TKeyParameter.Create(K1)
  139. as IKeyParameter, FIV));
  140. end
  141. else
  142. begin
  143. Fcipher.Init(true, TKeyParameter.Create(K1) as IKeyParameter);
  144. end;
  145. C := Fcipher.DoFinal(&in, inOff, inLen);
  146. end;
  147. // Apply the MAC.
  148. System.SetLength(T, Fmac.GetMacSize);
  149. Fmac.Init((TKeyParameter.Create(K2) as IKeyParameter) as ICipherParameters);
  150. Fmac.BlockUpdate(C, 0, System.Length(C));
  151. T := Fmac.DoFinal();
  152. CipherBlockSize := Fcipher.GetBlockSize;
  153. MessageToEncryptSize := inLen - inOff;
  154. if (MessageToEncryptSize mod CipherBlockSize) = 0 then
  155. begin
  156. MessageToEncryptPadSize := 0
  157. end
  158. else
  159. begin
  160. MessageToEncryptPadSize := CipherBlockSize -
  161. (MessageToEncryptSize mod CipherBlockSize);
  162. end;
  163. // Output the quadruple (SECURE_HEAD_DETAILS,V,T,C).
  164. // SECURE_HEAD_DETAILS :=
  165. // [0] := Convert Byte(Length(V)) to a ByteArray,
  166. // [1] := Convert Byte(Length(T)) to a ByteArray,
  167. // [2] and [3] := Convert UInt16(MessageToEncryptSize) to a ByteArray,
  168. // [4] and [5] := Convert UInt16(MessageToEncryptSize + MessageToEncryptPadSize) to a ByteArray,
  169. // V := Ephemeral Public Key
  170. // T := Authentication Message (MAC)
  171. // C := Encrypted Payload
  172. System.SetLength(Result, SECURE_HEAD_SIZE + System.Length(FV) +
  173. System.Length(T) + System.Length(C));
  174. PByte(Result)^ := Byte(System.Length(FV));
  175. (PByte(Result) + 1)^ := Byte(System.Length(T));
  176. (PWord(Result) + 1)^ := UInt16(MessageToEncryptSize);
  177. (PWord(Result) + 2)^ :=
  178. UInt16(MessageToEncryptSize + MessageToEncryptPadSize);
  179. System.Move(FV[0], Result[SECURE_HEAD_SIZE], System.Length(FV) *
  180. System.SizeOf(Byte));
  181. System.Move(T[0], Result[SECURE_HEAD_SIZE + System.Length(FV)],
  182. System.Length(T) * System.SizeOf(Byte));
  183. System.Move(C[0], Result[SECURE_HEAD_SIZE + System.Length(FV) +
  184. System.Length(T)], System.Length(C) * System.SizeOf(Byte));
  185. end;
  186. function TPascalCoinIESEngine.ProcessBlock(const &in: TCryptoLibByteArray;
  187. inOff, inLen: Int32): TCryptoLibByteArray;
  188. var
  189. ephKeyPair: IEphemeralKeyPair;
  190. bIn: TBytesStream;
  191. encLength: Int32;
  192. z: TBigInteger;
  193. BigZ: TCryptoLibByteArray;
  194. kdfParam: IKDFParameters;
  195. begin
  196. if (FforEncryption) then
  197. begin
  198. if (FkeyPairGenerator <> Nil) then
  199. begin
  200. ephKeyPair := FkeyPairGenerator.Generate;
  201. FprivParam := ephKeyPair.GetKeyPair.Private;
  202. FV := ephKeyPair.GetEncodedPublicKey;
  203. end
  204. end
  205. else
  206. begin
  207. if (FkeyParser <> Nil) then
  208. begin
  209. // used TBytesStream here for one pass creation and population with byte array :)
  210. bIn := TBytesStream.Create(System.Copy(&in, inOff, inLen));
  211. try
  212. // for existing PascalCoin compatiblity purposes
  213. bIn.Position := SECURE_HEAD_SIZE;
  214. try
  215. FpubParam := FkeyParser.ReadKey(bIn);
  216. except
  217. on e: EIOCryptoLibException do
  218. begin
  219. raise EInvalidCipherTextCryptoLibException.CreateResFmt
  220. (@SErrorRecoveringEphemeralPublicKey, [e.Message]);
  221. end;
  222. on e: EArgumentCryptoLibException do
  223. begin
  224. raise EInvalidCipherTextCryptoLibException.CreateResFmt
  225. (@SErrorRecoveringEphemeralPublicKey, [e.Message]);
  226. end;
  227. end;
  228. encLength := (inLen - (bIn.Size - bIn.Position));
  229. FV := TArrayUtils.CopyOfRange(&in, inOff + SECURE_HEAD_SIZE,
  230. inOff + encLength);
  231. finally
  232. bIn.Free;
  233. end;
  234. end;
  235. end;
  236. // Compute the common value and convert to byte array.
  237. Fagree.Init(FprivParam);
  238. z := Fagree.CalculateAgreement(FpubParam);
  239. BigZ := TBigIntegers.AsUnsignedByteArray(Fagree.GetFieldSize, z);
  240. try
  241. // Initialise the KDF.
  242. kdfParam := TKDFParameters.Create(BigZ, Nil);
  243. Fkdf.Init(kdfParam);
  244. if FforEncryption then
  245. begin
  246. Result := EncryptBlock(&in, inOff, inLen);
  247. Exit;
  248. end
  249. else
  250. begin
  251. Result := DecryptBlock(System.Copy(&in, inOff + SECURE_HEAD_SIZE,
  252. inLen - SECURE_HEAD_SIZE), inOff, inLen - SECURE_HEAD_SIZE);
  253. Exit;
  254. end;
  255. finally
  256. TArrayUtils.Fill(BigZ, 0, System.Length(BigZ), Byte(0));
  257. end;
  258. end;
  259. end.