From 351fb821db56de44cbb43815a1aa894868a8e0d8 Mon Sep 17 00:00:00 2001 From: Ugochukwu Mmaduekwe Date: Mon, 11 May 2026 13:35:57 +0100 Subject: [PATCH] refactor XChaCha20Poly1305 --- .../src/Crypto/ChaCha20Poly1305Tests.pas | 6 +- .../src/Crypto/XChaCha20Poly1305Tests.pas | 163 ++++++++++++++++++ CryptoLib.Tests/src/Crypto/XChaCha20Tests.pas | 75 ++++++++ .../src/Crypto/Modes/ClpChaCha20Poly1305.pas | 54 +++--- .../src/Crypto/Modes/ClpXChaCha20Poly1305.pas | 110 +----------- .../Crypto/Engines/ClpIChaCha7539Engine.pas | 6 + 6 files changed, 286 insertions(+), 128 deletions(-) diff --git a/CryptoLib.Tests/src/Crypto/ChaCha20Poly1305Tests.pas b/CryptoLib.Tests/src/Crypto/ChaCha20Poly1305Tests.pas index 5f474e46..f09f1340 100644 --- a/CryptoLib.Tests/src/Crypto/ChaCha20Poly1305Tests.pas +++ b/CryptoLib.Tests/src/Crypto/ChaCha20Poly1305Tests.pas @@ -399,7 +399,7 @@ procedure TTestChaCha20Poly1305.TestExceptionsAndTampering; // incorrect MAC size on construction try LBadMac := TMacUtilities.GetMac('SIPHASH'); - LCipher := TChaCha20Poly1305.Create(LBadMac) as IChaCha20Poly1305; + LCipher := TChaCha20Poly1305.Create(LBadMac); Fail('incorrect mac size not picked up'); except on E: EArgumentCryptoLibException do @@ -409,7 +409,7 @@ procedure TTestChaCha20Poly1305.TestExceptionsAndTampering; end; // illegal parameter: KeyParameter only instead of AeadParameters - LCipher := TChaCha20Poly1305.Create() as IChaCha20Poly1305; + LCipher := TChaCha20Poly1305.Create(); try LCipher.Init(False, TKeyParameter.Create(TBytes.Create(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -434,7 +434,7 @@ procedure TTestChaCha20Poly1305.TestExceptionsAndTampering; LP := TConverters.ConvertStringToBytes('Hello world!', TEncoding.ANSI); SetLength(LBuf, 100); - LCipher := TChaCha20Poly1305.Create() as IChaCha20Poly1305; + LCipher := TChaCha20Poly1305.Create(); LCipher.Init(True, LParams as ICipherParameters); LCipher.ProcessBytes(LP, 0, Length(LP), LBuf, 0); LCipher.DoFinal(LBuf, 0); diff --git a/CryptoLib.Tests/src/Crypto/XChaCha20Poly1305Tests.pas b/CryptoLib.Tests/src/Crypto/XChaCha20Poly1305Tests.pas index a878f8d1..f32cd365 100644 --- a/CryptoLib.Tests/src/Crypto/XChaCha20Poly1305Tests.pas +++ b/CryptoLib.Tests/src/Crypto/XChaCha20Poly1305Tests.pas @@ -52,11 +52,17 @@ interface TTestXChaCha20Poly1305 = class(TCryptoLibAlgorithmTestCase) strict private procedure CheckEqual(const AName: string; const AExpected, AActual: TBytes); + procedure DeterministicFill(var AState: UInt32; + const ADest: TCryptoLibByteArray; ALen: Int32); inline; function InitCipher(AForEncryption: Boolean; const AParams: IAeadParameters): IXChaCha20Poly1305; published procedure TestAppendixA1; procedure TestAppendixA1Poly1305OneTimeKey; + procedure TestDeterministicRoundTrip2048; + procedure TestTamperedTagMacFailure; + procedure TestRejectNonce12Byte; + procedure TestReuseNonceEncryptionRejected; procedure TestGetCipherRegistry; end; @@ -72,6 +78,18 @@ procedure TTestXChaCha20Poly1305.CheckEqual(const AName: string; [AName, EncodeHex(AExpected), EncodeHex(AActual)])); end; +procedure TTestXChaCha20Poly1305.DeterministicFill(var AState: UInt32; + const ADest: TCryptoLibByteArray; ALen: Int32); +var + i: Int32; +begin + for i := 0 to ALen - 1 do + begin + AState := UInt32(UInt64(AState) * 1664525 + 1013904223); + ADest[i] := Byte(AState shr 16); + end; +end; + function TTestXChaCha20Poly1305.InitCipher(AForEncryption: Boolean; const AParams: IAeadParameters): IXChaCha20Poly1305; var @@ -182,6 +200,151 @@ procedure TTestXChaCha20Poly1305.TestAppendixA1Poly1305OneTimeKey; CopyOfRange(LFirstBlock, 0, 32)); end; +procedure TTestXChaCha20Poly1305.TestDeterministicRoundTrip2048; +var + LState: UInt32; + LK, LN, LA, LP, LCipherStream, LOut, LRecover: TCryptoLibByteArray; + LParams: IAeadParameters; + LCipherEnc, LCipherDec: IXChaCha20Poly1305; + Len: Int32; +begin + System.SetLength(LK, 32); + System.SetLength(LN, 24); + System.SetLength(LA, 33); + System.SetLength(LP, 2048); + LState := UInt32($9E3779B9); + DeterministicFill(LState, LK, System.Length(LK)); + DeterministicFill(LState, LN, System.Length(LN)); + DeterministicFill(LState, LA, System.Length(LA)); + DeterministicFill(LState, LP, System.Length(LP)); + + LParams := TAeadParameters.Create(TKeyParameter.Create(LK) as IKeyParameter, + 128, LN, LA); + + LCipherEnc := InitCipher(True, LParams); + System.SetLength(LCipherStream, + LCipherEnc.GetOutputSize(System.Length(LP))); + Len := LCipherEnc.ProcessBytes(LP, 0, System.Length(LP), + LCipherStream, 0); + Len := Len + LCipherEnc.DoFinal(LCipherStream, Len); + + LCipherDec := InitCipher(False, LParams); + System.SetLength(LOut, LCipherDec.GetOutputSize(Len)); + Len := LCipherDec.ProcessBytes(LCipherStream, 0, Len, LOut, 0); + Len := Len + LCipherDec.DoFinal(LOut, Len); + SetLength(LRecover, Len); + System.Move(LOut[0], LRecover[0], Len); + CheckEqual('XChaCha20Poly1305 deterministic 2048B round-trip', LP, LRecover); +end; + +procedure TTestXChaCha20Poly1305.TestTamperedTagMacFailure; +var + LK, LP, LA, LN, LEnc, LDecBuf: TCryptoLibByteArray; + LParams: IAeadParameters; + LCipher: IXChaCha20Poly1305; + LLen: Int32; +begin + LK := THexEncoder.Decode( + '808182838485868788898a8b8c8d8e8f' + + '909192939495969798999a9b9c9d9e9f'); + LP := THexEncoder.Decode( + '4c616469657320616e642047656e746c' + + '656d656e206f662074686520636c6173' + + '73206f66202739393a20496620492063' + + '6f756c64206f6666657220796f75206f' + + '6e6c79206f6e652074697020666f7220' + + '746865206675747572652c2073756e73' + + '637265656e20776f756c642062652069' + + '742e'); + LA := THexEncoder.Decode('50515253c0c1c2c3c4c5c6c7'); + LN := THexEncoder.Decode( + '404142434445464748494a4b4c4d4e4f5051525354555657'); + + LParams := TAeadParameters.Create(TKeyParameter.Create(LK) as IKeyParameter, + 128, LN, LA); + + LCipher := InitCipher(True, LParams); + System.SetLength(LEnc, LCipher.GetOutputSize(System.Length(LP))); + LLen := LCipher.ProcessBytes(LP, 0, System.Length(LP), LEnc, 0); + LLen := LLen + LCipher.DoFinal(LEnc, LLen); + + LEnc[System.High(LEnc)] := + Byte(LEnc[System.High(LEnc)] xor $01); + + LCipher := InitCipher(False, LParams); + System.SetLength(LDecBuf, LCipher.GetOutputSize(LLen)); + LLen := LCipher.ProcessBytes(LEnc, 0, System.Length(LEnc), LDecBuf, 0); + try + LCipher.DoFinal(LDecBuf, LLen); + Fail('Tampered tag should fail AEAD decryption'); + except + on E: EInvalidCipherTextCryptoLibException do + begin + if E.Message <> + 'mac check in XChaCha20Poly1305 failed' then + Fail('unexpected decrypt message: ' + E.Message); + end; + end; +end; + +procedure TTestXChaCha20Poly1305.TestRejectNonce12Byte; +var + LK, LN12: TCryptoLibByteArray; + LParams: IAeadParameters; + LCipher: IXChaCha20Poly1305; +begin + System.SetLength(LK, 32); + System.SetLength(LN12, 12); + LParams := TAeadParameters.Create(TKeyParameter.Create(LK) as IKeyParameter, + 128, LN12, nil); + LCipher := TXChaCha20Poly1305.Create; + try + LCipher.Init(True, LParams as ICipherParameters); + Fail('XChaCha20Poly1305 unexpectedly accepted a 96-bit nonce'); + except + on E: EArgumentCryptoLibException do + begin + if E.Message <> 'Nonce must be 192 bits' then + Fail('unexpected nonce length message: ' + E.Message); + end; + end; +end; + +procedure TTestXChaCha20Poly1305.TestReuseNonceEncryptionRejected; +var + LK, LN, LOut: TCryptoLibByteArray; + LParams1, LParams2: IAeadParameters; + LCipher: IXChaCha20Poly1305; +begin + LK := THexEncoder.Decode( + '808182838485868788898a8b8c8d8e8f' + + '909192939495969798999a9b9c9d9e9f'); + LN := THexEncoder.Decode( + '404142434445464748494a4b4c4d4e4f5051525354555657'); + + LParams1 := TAeadParameters.Create(TKeyParameter.Create(LK) as IKeyParameter, + 128, LN, nil); + LParams2 := TAeadParameters.Create(TKeyParameter.Create(LK) as IKeyParameter, + 128, LN, nil); + + LCipher := TXChaCha20Poly1305.Create; + LCipher.Init(True, LParams1 as ICipherParameters); + System.SetLength(LOut, LCipher.GetOutputSize(0)); + LCipher.DoFinal(LOut, 0); + + try + LCipher.Init(True, LParams2 as ICipherParameters); + Fail('XChaCha20Poly1305 unexpectedly allowed nonce reuse for encryption'); + except + on E: EArgumentCryptoLibException do + begin + if E.Message <> + 'cannot reuse nonce for XChaCha20Poly1305 encryption' then + Fail('unexpected nonce reuse message: ' + E.Message); + end; + end; +end; + procedure TTestXChaCha20Poly1305.TestGetCipherRegistry; var LCipher: IBufferedCipher; diff --git a/CryptoLib.Tests/src/Crypto/XChaCha20Tests.pas b/CryptoLib.Tests/src/Crypto/XChaCha20Tests.pas index 40dfc42d..30ddf9cf 100644 --- a/CryptoLib.Tests/src/Crypto/XChaCha20Tests.pas +++ b/CryptoLib.Tests/src/Crypto/XChaCha20Tests.pas @@ -52,6 +52,9 @@ TTestXChaCha20 = class(TCryptoLibAlgorithmTestCase) procedure TestAppendixA3_2_2KeystreamFromBlockCounter1; procedure TestAppendixA3_2_2CiphertextCounter1; procedure TestGetCipherXChaCha20Aliases; + procedure TestRoundTrip1024; + procedure TestRejectShortNonce64Bits; + procedure TestRejectShortNonce96Bits; end; implementation @@ -288,6 +291,78 @@ procedure TTestXChaCha20.TestGetCipherXChaCha20Aliases; Fail('TCipherUtilities.GetCipher(XChaCha20) returned nil'); end; +procedure TTestXChaCha20.TestRoundTrip1024; +var + LKey, LIv, LPlain, LCipher, LRecovered: TCryptoLibByteArray; + LEnc, LDec: IXChaCha20Engine; + LIdx: Int32; + LParams: IParametersWithIV; +begin + LKey := THexEncoder.Decode( + '0001020304050607080910111213141516171819202122232425262728293031'); + LIv := THexEncoder.Decode('000102030405060708090a0b0c0d0e0f1011121314151617'); + + System.SetLength(LPlain, 1024); + for LIdx := 0 to 1023 do + LPlain[LIdx] := Byte(LIdx and $FF); + + LEnc := TXChaCha20Engine.Create; + LParams := TParametersWithIV.Create(TKeyParameter.Create(LKey) as IKeyParameter, + LIv); + LEnc.Init(True, LParams); + System.SetLength(LCipher, 1024); + LEnc.ProcessBytes(LPlain, 0, 1024, LCipher, 0); + + LDec := TXChaCha20Engine.Create; + LDec.Init(False, LParams); + System.SetLength(LRecovered, 1024); + LDec.ProcessBytes(LCipher, 0, 1024, LRecovered, 0); + + if AreEqual(LPlain, LCipher) then + Fail('XChaCha20 produced no keystream XOR (plain equals cipher)'); + if not AreEqual(LPlain, LRecovered) then + Fail(Format('XChaCha20 round-trip mismatch: recovered %s', + [EncodeHex(LRecovered)])); +end; + +procedure TTestXChaCha20.TestRejectShortNonce64Bits; +var + LKey, LIv8: TCryptoLibByteArray; + LEngine: IXChaCha20Engine; +begin + System.SetLength(LKey, 32); + System.SetLength(LIv8, 8); + System.FillChar(LIv8[0], 8, 0); + try + LEngine := TXChaCha20Engine.Create; + LEngine.Init(True, TParametersWithIV.Create(TKeyParameter.Create(LKey) + as IKeyParameter, LIv8)); + Fail('XChaCha20 unexpectedly accepted an 8-byte nonce'); + except + on E: EArgumentCryptoLibException do + ; // expected + end; +end; + +procedure TTestXChaCha20.TestRejectShortNonce96Bits; +var + LKey: TCryptoLibByteArray; + LEngine: IXChaCha20Engine; + LNonce12: TCryptoLibByteArray; +begin + System.SetLength(LKey, 32); + System.SetLength(LNonce12, 12); + try + LEngine := TXChaCha20Engine.Create; + LEngine.Init(True, TParametersWithIV.Create(TKeyParameter.Create(LKey) + as IKeyParameter, LNonce12)); + Fail('XChaCha20 unexpectedly accepted a 12-byte nonce'); + except + on E: EArgumentCryptoLibException do + ; // expected + end; +end; + initialization {$IFDEF FPC} diff --git a/CryptoLib/src/Crypto/Modes/ClpChaCha20Poly1305.pas b/CryptoLib/src/Crypto/Modes/ClpChaCha20Poly1305.pas index d71f7518..35499836 100644 --- a/CryptoLib/src/Crypto/Modes/ClpChaCha20Poly1305.pas +++ b/CryptoLib/src/Crypto/Modes/ClpChaCha20Poly1305.pas @@ -28,6 +28,7 @@ interface ClpICipherParameters, ClpIKeyParameter, ClpCipherModeParameterUtilities, + ClpIChaCha7539Engine, ClpChaCha7539Engine, ClpPoly1305, ClpIMac, @@ -41,17 +42,17 @@ interface resourcestring SPoly1305Nil = 'poly1305'; SPoly1305MustBe128 = 'must be a 128-bit MAC'; - SInvalidParameters = 'invalid parameters passed to ChaCha20Poly1305'; + SInvalidParametersFmt = 'invalid parameters passed to %s'; SKeyMustBeSpecified = 'Key must be specified in initial init'; SKeyMustBe256 = 'Key must be 256 bits'; - SNonceMustBe96 = 'Nonce must be 96 bits'; - SCannotReuseNonce = 'cannot reuse nonce for ChaCha20Poly1305 encryption'; + SNonceMustBeBits = 'Nonce must be %d bits'; + SCannotReuseNonceFmt = 'cannot reuse nonce for %s encryption'; SInvalidMacSize = 'Invalid value for MAC size: %d'; SCannotBeNegative = 'cannot be negative'; SInputBufferTooShort = 'Input Buffer Too Short'; SOutputBufferTooShort = 'Output Buffer Too Short'; SDataTooShort = 'data too short'; - SMacCheckFailed = 'mac check in ChaCha20Poly1305 failed'; + SMacCheckFailedFmt = 'mac check in %s failed'; SCannotReuseEncryption = ' cannot be reused for encryption'; SNeedsInit = ' needs to be initialized'; SLimitExceeded = 'Limit exceeded'; @@ -84,7 +85,6 @@ TChaCha20Poly1305 = class(TInterfacedObject, IChaCha20Poly1305, IAeadCipher) const BufSize: Int32 = 64; KeySize: Int32 = 32; - NonceSize: Int32 = 12; MacSize: Int32 = 16; var @@ -101,7 +101,8 @@ TChaCha20Poly1305 = class(TInterfacedObject, IChaCha20Poly1305, IAeadCipher) FZeroes: TCryptoLibByteArray; var - FChaCha20: TChaCha7539Engine; + FChaCha20: IChaCha7539Engine; + FNonceBytes: Int32; FPoly1305: IMac; FKey: TCryptoLibByteArray; @@ -137,7 +138,8 @@ TChaCha20Poly1305 = class(TInterfacedObject, IChaCha20Poly1305, IAeadCipher) public constructor Create(); overload; constructor Create(const APoly1305: IMac); overload; - destructor Destroy; override; + constructor Create(const APoly1305: IMac; const AEngine: IChaCha7539Engine; + ANonceBytes: Int32); overload; procedure Init(AForEncryption: Boolean; const AParameters: ICipherParameters); virtual; @@ -174,6 +176,12 @@ constructor TChaCha20Poly1305.Create; end; constructor TChaCha20Poly1305.Create(const APoly1305: IMac); +begin + Create(APoly1305, TChaCha7539Engine.Create() as IChaCha7539Engine, 12); +end; + +constructor TChaCha20Poly1305.Create(const APoly1305: IMac; + const AEngine: IChaCha7539Engine; ANonceBytes: Int32); begin inherited Create(); @@ -181,24 +189,24 @@ constructor TChaCha20Poly1305.Create(const APoly1305: IMac); raise EArgumentNilCryptoLibException.CreateRes(@SPoly1305Nil); if (MacSize <> APoly1305.GetMacSize()) then raise EArgumentCryptoLibException.CreateRes(@SPoly1305MustBe128); + if (AEngine = nil) then + raise EArgumentNilCryptoLibException.Create('cipher engine'); + + if (ANonceBytes < 1) then + raise EArgumentCryptoLibException.Create('invalid nonce octet length'); - FChaCha20 := TChaCha7539Engine.Create(); FPoly1305 := APoly1305; + FChaCha20 := AEngine; + FNonceBytes := ANonceBytes; System.SetLength(FKey, KeySize); - System.SetLength(FNonce, NonceSize); + System.SetLength(FNonce, FNonceBytes); System.SetLength(FBuf, BufSize + MacSize); System.SetLength(FMac, MacSize); FState := TState.Uninitialized; end; -destructor TChaCha20Poly1305.Destroy; -begin - FChaCha20.Free; - inherited Destroy; -end; - function TChaCha20Poly1305.GetAlgorithmName: String; begin Result := 'ChaCha20Poly1305'; @@ -215,7 +223,8 @@ procedure TChaCha20Poly1305.Init(AForEncryption: Boolean; begin if not TCipherModeParameterUtilities.TryResolveAeadOrIv(AParameters, LChoice) then - raise EArgumentCryptoLibException.CreateRes(@SInvalidParameters); + raise EArgumentCryptoLibException.CreateResFmt(@SInvalidParametersFmt, + [AlgorithmName]); LInitKeyParam := LChoice.KeyParameter; LInitNonce := LChoice.Nonce; @@ -242,14 +251,16 @@ procedure TChaCha20Poly1305.Init(AForEncryption: Boolean; raise EArgumentCryptoLibException.CreateRes(@SKeyMustBe256); end; - if (NonceSize <> System.Length(LInitNonce)) then - raise EArgumentCryptoLibException.CreateRes(@SNonceMustBe96); + if (FNonceBytes <> System.Length(LInitNonce)) then + raise EArgumentCryptoLibException.CreateResFmt(@SNonceMustBeBits, + [UInt32(FNonceBytes) shl 3]); if (TState.Uninitialized <> FState) and AForEncryption and TArrayUtilities.AreEqual(FNonce, LInitNonce) then begin if (LInitKeyParam = nil) or LInitKeyParam.FixedTimeEquals(FKey) then - raise EArgumentCryptoLibException.CreateRes(@SCannotReuseNonce); + raise EArgumentCryptoLibException.CreateResFmt(@SCannotReuseNonceFmt, + [AlgorithmName]); end; if (LInitKeyParam <> nil) then @@ -257,7 +268,7 @@ procedure TChaCha20Poly1305.Init(AForEncryption: Boolean; LInitKeyParam.CopyKeyTo(FKey, 0, KeySize); end; - System.Move(LInitNonce[0], FNonce[0], NonceSize); + System.Move(LInitNonce[0], FNonce[0], FNonceBytes); FChaCha20.Init(True, LChaCha20Params); @@ -550,7 +561,8 @@ function TChaCha20Poly1305.DoFinal(const AOutput: TCryptoLibByteArray; FinishData(TState.DecFinal); if (not TArrayUtilities.FixedTimeEquals(MacSize, FMac, 0, FBuf, LResultLen)) then - raise EInvalidCipherTextCryptoLibException.CreateRes(@SMacCheckFailed); + raise EInvalidCipherTextCryptoLibException.CreateResFmt(@SMacCheckFailedFmt, + [AlgorithmName]); end; TState.EncData: begin diff --git a/CryptoLib/src/Crypto/Modes/ClpXChaCha20Poly1305.pas b/CryptoLib/src/Crypto/Modes/ClpXChaCha20Poly1305.pas index f1786f12..fa53361d 100644 --- a/CryptoLib/src/Crypto/Modes/ClpXChaCha20Poly1305.pas +++ b/CryptoLib/src/Crypto/Modes/ClpXChaCha20Poly1305.pas @@ -23,41 +23,22 @@ interface uses SysUtils, ClpIXChaCha20Poly1305, - ClpChaCha20Poly1305, ClpIAeadCipher, - ClpICipherParameters, - ClpIKeyParameter, + ClpIXChaCha20Engine, + ClpChaCha20Poly1305, ClpIMac, - ClpKeyParameter, - ClpAeadParameters, - ClpParametersWithIV, - ClpCipherModeParameterUtilities, - ClpChaChaEngine, - ClpArrayUtilities, - ClpCryptoLibTypes; - -resourcestring - SInvalidParameters = 'invalid parameters passed to XChaCha20Poly1305'; - SNonceMustBe192 = 'XChaCha20Poly1305 requires a 192 bit nonce'; - SInvalidMacSize = 'Invalid value for MAC size: %d'; - SKeyMustBe256 = 'Key must be 256 bits'; - SKeyMustBeSpecified = 'Key must be specified in initial init'; + ClpPoly1305, + ClpXChaCha20Engine; type TXChaCha20Poly1305 = class(TChaCha20Poly1305, IXChaCha20Poly1305, IAeadCipher) - strict private - FMasterKey: TCryptoLibByteArray; - strict protected function GetAlgorithmName: String; override; public constructor Create(); overload; constructor Create(const APoly1305: IMac); overload; - destructor Destroy; override; - - procedure Init(AForEncryption: Boolean; const AParameters: ICipherParameters); override; end; implementation @@ -66,20 +47,12 @@ implementation constructor TXChaCha20Poly1305.Create; begin - inherited Create(); - System.SetLength(FMasterKey, KeySize); + Create(TPoly1305.Create() as IMac); end; constructor TXChaCha20Poly1305.Create(const APoly1305: IMac); begin - inherited Create(APoly1305); - System.SetLength(FMasterKey, KeySize); -end; - -destructor TXChaCha20Poly1305.Destroy; -begin - TArrayUtilities.Fill(FMasterKey, 0, System.Length(FMasterKey), Byte(0)); - inherited Destroy; + inherited Create(APoly1305, TXChaCha20Engine.Create() as IXChaCha20Engine, 24); end; function TXChaCha20Poly1305.GetAlgorithmName: String; @@ -87,75 +60,4 @@ function TXChaCha20Poly1305.GetAlgorithmName: String; Result := 'XChaCha20Poly1305'; end; -procedure TXChaCha20Poly1305.Init(AForEncryption: Boolean; - const AParameters: ICipherParameters); -var - LChoice: TCipherAeadChoice; - LInitKeyParam: IKeyParameter; - LOuterNonce: TCryptoLibByteArray; - LMacSizeBits: Int32; - LSubKey: TCryptoLibByteArray; - LInnerIv: TCryptoLibByteArray; - LNoncePrefix: TCryptoLibByteArray; - LInnerParams: ICipherParameters; - LInnerKey: IKeyParameter; -begin - if not TCipherModeParameterUtilities.TryResolveAeadOrIv(AParameters, LChoice) - then - raise EArgumentCryptoLibException.CreateRes(@SInvalidParameters); - - LInitKeyParam := LChoice.KeyParameter; - LOuterNonce := LChoice.Nonce; - - if (LOuterNonce = nil) or (System.Length(LOuterNonce) <> 24) then - raise EArgumentCryptoLibException.CreateRes(@SNonceMustBe192); - - if LChoice.IsAead then - begin - LMacSizeBits := LChoice.MacSizeBits; - if ((MacSize * 8) <> LMacSizeBits) then - raise EArgumentCryptoLibException.CreateResFmt(@SInvalidMacSize, - [LMacSizeBits]); - end; - - if (LInitKeyParam = nil) then - begin - if (TState.Uninitialized = FState) then - raise EArgumentCryptoLibException.CreateRes(@SKeyMustBeSpecified); - end - else - begin - if (KeySize <> LInitKeyParam.KeyLength) then - raise EArgumentCryptoLibException.CreateRes(@SKeyMustBe256); - LInitKeyParam.CopyKeyTo(FMasterKey, 0, KeySize); - end; - - LNoncePrefix := Copy(LOuterNonce, 0, 16); - System.SetLength(LSubKey, 32); - try - TChaChaEngine.HChaCha20(FMasterKey, LNoncePrefix, LSubKey, 0); - finally - TArrayUtilities.Fill(LNoncePrefix, 0, System.Length(LNoncePrefix), - Byte(0)); - end; - - System.SetLength(LInnerIv, 12); - System.FillChar(LInnerIv[0], 4, 0); - System.Move(LOuterNonce[16], LInnerIv[4], 8); - - try - LInnerKey := TKeyParameter.Create(LSubKey); - finally - TArrayUtilities.Fill(LSubKey, 0, 32, Byte(0)); - end; - - if LChoice.IsAead then - LInnerParams := TAeadParameters.Create(LInnerKey, LMacSizeBits, LInnerIv, - LChoice.AssociatedText) - else - LInnerParams := TParametersWithIV.Create(LInnerKey, LInnerIv); - - inherited Init(AForEncryption, LInnerParams); -end; - end. diff --git a/CryptoLib/src/Interfaces/Crypto/Engines/ClpIChaCha7539Engine.pas b/CryptoLib/src/Interfaces/Crypto/Engines/ClpIChaCha7539Engine.pas index 81972072..7a8d7061 100644 --- a/CryptoLib/src/Interfaces/Crypto/Engines/ClpIChaCha7539Engine.pas +++ b/CryptoLib/src/Interfaces/Crypto/Engines/ClpIChaCha7539Engine.pas @@ -35,6 +35,12 @@ interface procedure ProcessBlock(const AInBytes: TCryptoLibByteArray; AInOff: Int32; const AOutBytes: TCryptoLibByteArray; AOutOff: Int32); + procedure ProcessBlocks2(const AInBytes: TCryptoLibByteArray; AInOff: Int32; + const AOutBytes: TCryptoLibByteArray; AOutOff: Int32); + + procedure ProcessBlocks4(const AInBytes: TCryptoLibByteArray; AInOff: Int32; + const AOutBytes: TCryptoLibByteArray; AOutOff: Int32); + end; implementation