123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- { *********************************************************************************** }
- { * CryptoLib Library * }
- { * Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe * }
- { * Github Repository <https://github.com/Xor-el> * }
- { * Distributed under the MIT software license, see the accompanying file LICENSE * }
- { * or visit http://www.opensource.org/licenses/mit-license.php. * }
- { * Acknowledgements: * }
- { * * }
- { * Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring * }
- { * development of this library * }
- { * ******************************************************************************* * }
- (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
- unit ClpPascalCoinIESEngine;
- {$I CryptoLib.inc}
- interface
- uses
- SysUtils,
- Classes,
- ClpIMac,
- ClpIPascalCoinIESEngine,
- ClpICipherParameters,
- ClpKeyParameter,
- ClpIKeyParameter,
- ClpParametersWithIV,
- ClpIKeyParser,
- ClpIEphemeralKeyPair,
- ClpKdfParameters,
- ClpIKdfParameters,
- ClpIESEngine,
- ClpArrayUtils,
- ClpBigInteger,
- ClpBigIntegers,
- ClpCryptoLibTypes;
- resourcestring
- SErrorRecoveringEphemeralPublicKey =
- 'Unable to Recover Ephemeral Public Key: "%s"';
- SInvalidCipherTextLength =
- 'Length of Input Must be Greater than the MAC and V Combined';
- SInvalidMAC = 'Invalid MAC';
- SCipherCannotbeNilInThisMode = 'Cipher Cannot be Nil in This Mode.';
- type
- /// <summary>
- /// Compatibility Class for PascalCoin IESEngine
- /// </summary>
- TPascalCoinIESEngine = class(TIESEngine, IPascalCoinIESEngine)
- strict private
- type
- /// <summary>
- /// Structure for Compatibility with PascalCoin Original
- /// Implementation.
- /// </summary>
- TSecureHead = record
- Key: Byte;
- Mac: Byte;
- Orig: UInt16;
- Body: UInt16;
- end;
- const
- /// <summary>
- /// <b>SizeOf <paramref name="TSecureHead" /></b>. <br />
- /// </summary>
- // SECURE_HEAD_SIZE = Int32(6);
- SECURE_HEAD_SIZE = System.SizeOf(TSecureHead);
- strict protected
- function EncryptBlock(const &in: TCryptoLibByteArray; inOff, inLen: Int32)
- : TCryptoLibByteArray; override;
- function DecryptBlock(const in_enc: TCryptoLibByteArray;
- inOff, inLen: Int32): TCryptoLibByteArray; override;
- public
- function ProcessBlock(const &in: TCryptoLibByteArray; inOff, inLen: Int32)
- : TCryptoLibByteArray; override;
- end;
- implementation
- { TPascalCoinIESEngine }
- function TPascalCoinIESEngine.DecryptBlock(const in_enc: TCryptoLibByteArray;
- inOff, inLen: Int32): TCryptoLibByteArray;
- var
- K1, K2, T1, T2: TCryptoLibByteArray;
- cp: ICipherParameters;
- begin
- // Ensure that the length of the input is greater than the MAC in bytes
- if (inLen < (System.Length(FV) + Fmac.GetMacSize)) then
- begin
- raise EInvalidCipherTextCryptoLibException.CreateRes
- (@SInvalidCipherTextLength);
- end;
- // note order is important: set up keys, do simple encryptions, check mac, do final encryption.
- if (Fcipher = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes
- (@SCipherCannotbeNilInThisMode);
- end
- else
- begin
- // Block cipher mode.
- SetupBlockCipherAndMacKeyBytes(K1, K2);
- cp := TKeyParameter.Create(K1);
- // If iv is provided use it to initialise the cipher
- if (FIV <> Nil) then
- begin
- cp := TParametersWithIV.Create(cp, FIV);
- end;
- Fcipher.Init(False, cp);
- end;
- // Verify the MAC.
- T1 := System.Copy(in_enc, System.Length(FV), Fmac.GetMacSize);
- System.SetLength(T2, System.Length(T1));
- Fmac.Init((TKeyParameter.Create(K2) as IKeyParameter) as ICipherParameters);
- Fmac.BlockUpdate(in_enc, inOff + System.Length(FV) + System.Length(T2),
- inLen - System.Length(FV) - System.Length(T2));
- T2 := Fmac.DoFinal();
- if (not TArrayUtils.ConstantTimeAreEqual(T1, T2)) then
- begin
- raise EInvalidCipherTextCryptoLibException.CreateRes(@SInvalidMAC);
- end;
- Result := Fcipher.DoFinal(in_enc, inOff + System.Length(FV) + Fmac.GetMacSize,
- inLen - System.Length(FV) - System.Length(T2));
- Exit;
- end;
- function TPascalCoinIESEngine.EncryptBlock(const &in: TCryptoLibByteArray;
- inOff, inLen: Int32): TCryptoLibByteArray;
- var
- C, K1, K2, T: TCryptoLibByteArray;
- MessageToEncryptPadSize, CipherBlockSize, MessageToEncryptSize: Int32;
- begin
- if (Fcipher = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes
- (@SCipherCannotbeNilInThisMode);
- end
- else
- begin
- // Block cipher mode.
- SetupBlockCipherAndMacKeyBytes(K1, K2);
- // If iv is provided use it to initialise the cipher
- if (FIV <> Nil) then
- begin
- Fcipher.Init(true, TParametersWithIV.Create(TKeyParameter.Create(K1)
- as IKeyParameter, FIV));
- end
- else
- begin
- Fcipher.Init(true, TKeyParameter.Create(K1) as IKeyParameter);
- end;
- C := Fcipher.DoFinal(&in, inOff, inLen);
- end;
- // Apply the MAC.
- System.SetLength(T, Fmac.GetMacSize);
- Fmac.Init((TKeyParameter.Create(K2) as IKeyParameter) as ICipherParameters);
- Fmac.BlockUpdate(C, 0, System.Length(C));
- T := Fmac.DoFinal();
- CipherBlockSize := Fcipher.GetBlockSize;
- MessageToEncryptSize := inLen - inOff;
- if (MessageToEncryptSize mod CipherBlockSize) = 0 then
- begin
- MessageToEncryptPadSize := 0
- end
- else
- begin
- MessageToEncryptPadSize := CipherBlockSize -
- (MessageToEncryptSize mod CipherBlockSize);
- end;
- // Output the quadruple (SECURE_HEAD_DETAILS,V,T,C).
- // SECURE_HEAD_DETAILS :=
- // [0] := Convert Byte(Length(V)) to a ByteArray,
- // [1] := Convert Byte(Length(T)) to a ByteArray,
- // [2] and [3] := Convert UInt16(MessageToEncryptSize) to a ByteArray,
- // [4] and [5] := Convert UInt16(MessageToEncryptSize + MessageToEncryptPadSize) to a ByteArray,
- // V := Ephemeral Public Key
- // T := Authentication Message (MAC)
- // C := Encrypted Payload
- System.SetLength(Result, SECURE_HEAD_SIZE + System.Length(FV) +
- System.Length(T) + System.Length(C));
- PByte(Result)^ := Byte(System.Length(FV));
- (PByte(Result) + 1)^ := Byte(System.Length(T));
- (PWord(Result) + 1)^ := UInt16(MessageToEncryptSize);
- (PWord(Result) + 2)^ :=
- UInt16(MessageToEncryptSize + MessageToEncryptPadSize);
- System.Move(FV[0], Result[SECURE_HEAD_SIZE], System.Length(FV) *
- System.SizeOf(Byte));
- System.Move(T[0], Result[SECURE_HEAD_SIZE + System.Length(FV)],
- System.Length(T) * System.SizeOf(Byte));
- System.Move(C[0], Result[SECURE_HEAD_SIZE + System.Length(FV) +
- System.Length(T)], System.Length(C) * System.SizeOf(Byte));
- end;
- function TPascalCoinIESEngine.ProcessBlock(const &in: TCryptoLibByteArray;
- inOff, inLen: Int32): TCryptoLibByteArray;
- var
- ephKeyPair: IEphemeralKeyPair;
- bIn: TBytesStream;
- encLength: Int32;
- z: TBigInteger;
- BigZ: TCryptoLibByteArray;
- kdfParam: IKDFParameters;
- begin
- if (FforEncryption) then
- begin
- if (FkeyPairGenerator <> Nil) then
- begin
- ephKeyPair := FkeyPairGenerator.Generate;
- FprivParam := ephKeyPair.GetKeyPair.Private;
- FV := ephKeyPair.GetEncodedPublicKey;
- end
- end
- else
- begin
- if (FkeyParser <> Nil) then
- begin
- // used TBytesStream here for one pass creation and population with byte array :)
- bIn := TBytesStream.Create(System.Copy(&in, inOff, inLen));
- try
- // for existing PascalCoin compatiblity purposes
- bIn.Position := SECURE_HEAD_SIZE;
- try
- FpubParam := FkeyParser.ReadKey(bIn);
- except
- on e: EIOCryptoLibException do
- begin
- raise EInvalidCipherTextCryptoLibException.CreateResFmt
- (@SErrorRecoveringEphemeralPublicKey, [e.Message]);
- end;
- on e: EArgumentCryptoLibException do
- begin
- raise EInvalidCipherTextCryptoLibException.CreateResFmt
- (@SErrorRecoveringEphemeralPublicKey, [e.Message]);
- end;
- end;
- encLength := (inLen - (bIn.Size - bIn.Position));
- FV := TArrayUtils.CopyOfRange(&in, inOff + SECURE_HEAD_SIZE,
- inOff + encLength);
- finally
- bIn.Free;
- end;
- end;
- end;
- // Compute the common value and convert to byte array.
- Fagree.Init(FprivParam);
- z := Fagree.CalculateAgreement(FpubParam);
- BigZ := TBigIntegers.AsUnsignedByteArray(Fagree.GetFieldSize, z);
- try
- // Initialise the KDF.
- kdfParam := TKDFParameters.Create(BigZ, Nil);
- Fkdf.Init(kdfParam);
- if FforEncryption then
- begin
- Result := EncryptBlock(&in, inOff, inLen);
- Exit;
- end
- else
- begin
- Result := DecryptBlock(System.Copy(&in, inOff + SECURE_HEAD_SIZE,
- inLen - SECURE_HEAD_SIZE), inOff, inLen - SECURE_HEAD_SIZE);
- Exit;
- end;
- finally
- TArrayUtils.Fill(BigZ, 0, System.Length(BigZ), Byte(0));
- end;
- end;
- end.
|