Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CryptoLib.Tests/src/Crypto/ChaCha20Poly1305Tests.pas
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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);
Expand Down
163 changes: 163 additions & 0 deletions CryptoLib.Tests/src/Crypto/XChaCha20Poly1305Tests.pas
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand Down
75 changes: 75 additions & 0 deletions CryptoLib.Tests/src/Crypto/XChaCha20Tests.pas
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
Loading
Loading