{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory of
this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
{$M+} // DUnitX would add it anyway
unit TestDECCipherModes;
interface
// Needs to be included before any other statements
{$INCLUDE TestDefines.inc}
uses
{$IFDEF DUnitX}
DUnitX.TestFramework,DUnitX.DUnitCompatibility,
{$ELSE}
TestFramework,
{$ENDIF}
System.SysUtils,
DECCipherBase, DECCipherModes, DECCipherFormats, DECCiphers;
type
///
/// Class reference to be abe to specify duifferent cipher classes for
/// carrying out the different tests.
///
TFormattedCipherClass = class of TDECFormattedCipher;
///
/// One entry in a list of tests
///
TTestEntry = record
///
/// Input value, needs to be of block size length or a multiple of it
///
Input : RawByteString;
///
/// Expected output value, needs to be of block size length or a multiple of it
///
Output : RawByteString;
///
/// Expected output value which is used if Output is empty. Contains the
/// output in hexadecimal notation.
///
OutputHex : RawByteString;
///
/// Init Vektor für den ersten Test
///
InitVector : RawByteString;
///
/// Class reference for the cipher class used for this test.
///
TestClass : TFormattedCipherClass;
///
/// Block concatenating/padding mode
///
Mode : TCipherMode;
end;
///
/// Prototype for a function to be passed to the generic test method
///
TTestFunction = procedure(Source, Dest: PByteArray; Size: Integer) of object;
///
/// Testmethoden für Klasse TDECCipherModes
///
{$IFDEF DUnitX} [TestFixture] {$ENDIF}
TestTDECCipherModes = class(TTestCase)
strict private
const
Data: array[1..27] of TTestEntry = ((Input: 'ABCDEFGHIJKLMNOPQRSTUVWX';
Output: 'ABCDEFGHIJKLMNOPQRSTUVWX';
TestClass: TCipher_Null;
Mode: TCipherMode.cmECBx),
(Input: '000000000000000000000000';
Output: '000000000000000000000000';
TestClass: TCipher_Null;
Mode: TCipherMode.cmECBx),
(Input: '12345678';
Output: '12345678';
TestClass: TCipher_Null;
Mode: TCipherMode.cmECBx),
(Input: 'ABCDEFGHIJKLMNOPQRSTUVWX';
Output: '';
OutputHex: 'FE5A89A7A1F4BD29DFFADFCF2239E1F581106DA64C0AE704';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmOFB8),
(Input: '000000000000000000000000';
Output: '';
OutputHex: '8F28FAD3D482CA51A680A4B35F479E95E0720EC2296C806C';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmOFB8),
(Input: '12345678';
Output: '';
OutputHex: '8E2AF9D7D184CD59';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmOFB8),
(Input: 'ABCDEFGHIJKLMNOPQRSTUVWX';
Output: '';
OutputHex: 'FE604D3DF9C2AE3D7839AF5BDEE8FD9078544A1996EC4F1C';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFB8),
(Input: '000000000000000000000000';
Output: '';
OutputHex: '8FD637FC449CF89F1E5EEBB66BED15C7F8C63B4481F74C5A';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFB8),
(Input: '12345678';
Output: '';
OutputHex: '8EF08D6414063543';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFB8),
(Input: 'ABCDEFGHIJKLMNOPQRSTUVWX';
Output: '';
OutputHex: 'FEAB3839BBA059FC1FECBF798CEF537803F10F15967E3ABD';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFS8),
(Input: '000000000000000000000000';
Output: '';
OutputHex: '8F9661B53B06D611BA916562F4420DA4B6EFD550BF01DA2C';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFS8),
(Input: '12345678';
Output: '';
OutputHex: '8EEA2F2F86159953';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFS8),
(Input: 'ABCDEFGHIJKLMNOPQRSTUVWX';
Output: '';
OutputHex: 'FED41297FD52669B4221F913AF978D77292C958B2A9E289A';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmOFBx),
(Input: '000000000000000000000000';
Output: '';
OutputHex: '8FA661E3882411E33B5B826FD2E9F217484EF6EF4FF84FF2';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmOFBx),
(Input: '12345678';
Output: '';
OutputHex: '8EA462E78D2216EB';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmOFBx),
(Input: 'ABCDEFGHIJKLMNOPQRSTUVWX';
Output: '';
OutputHex: 'FED41297FD52669B0DEC818A383ADA358E469BE634B7AFBC';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFSx),
(Input: '000000000000000000000000';
Output: '';
OutputHex: '8FA661E3882411E3DB7258A29424D11F2BB6B4607D24D5DB';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFSx),
(Input: '12345678';
Output: '';
OutputHex: '8EA462E78D2216EB';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFSx),
(Input : 'ABCDEFGHIJKLMNOPQRSTUVWX';
Output : 'qsqwqsq'+#$7f+'89:;<=>/ikioikiw';
InitVector: '01234567';
TestClass : TCipher_NULL;
Mode : TCipherMode.cmCBCx),
(Input : '000000000000000000000000';
Output : '00000000' + #0#0#0#0#0#0#0#0 + '00000000';
InitVector: #0#0#0#0#0#0#0#0;
TestClass : TCipher_NULL;
Mode : TCipherMode.cmCBCx),
(Input : '000000000000000000000000';
Output : #0#1#2#3#4#5#6#7 + '01234567' + #0#1#2#3#4#5#6#7;
InitVector: '01234567';
TestClass : TCipher_NULL;
Mode : TCipherMode.cmCBCx),
(Input: 'ABCDEFGHIJKLMNOPQRSTUVWX';
Output: '';
OutputHex: 'FD73DA2F279926A19A65EFA8EBA5EEB67A778C6CD73294F5';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCTSx),
(Input: '000000000000000000000000';
Output: '';
OutputHex: '1D538CCCF38138A6BD4655272CC67443A0E32865EB422745';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCTSx),
(Input: '12345678';
Output: '';
OutputHex: '8EE274B893296F9E';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCTSx),
(Input: 'ABCDEFGHIJKLMNOPQRSTUVWX';
Output: '';
OutputHex: 'FED41297FD52669BF5361295F3BD937EF0644802ED92DC21';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFBx),
(Input: '000000000000000000000000';
Output: '';
OutputHex: '8FA661E3882411E35337C15BAE99B7CBDD988AC4FABB3368';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFBx),
(Input: '12345678';
Output: '';
OutputHex: '8EA462E78D2216EB';
TestClass: TCipher_1DES;
Mode: TCipherMode.cmCFBx));
///
/// Carries out the actual encode test
///
///
/// Array with the data definint inputs and outputs for the tests
///
///
/// Cipher mode which shall be tested
///
///
/// if true parameter Mode will be ignored and tests for all modes be
/// carried out
///
procedure DoTestEncode(Data: array of TTestEntry; Mode: TCipherMode; TestAllModes: Boolean = false);
///
/// Carries out the actual decode test
///
///
/// Array with the data definint inputs and outputs for the tests
///
///
/// Cipher mode which shall be tested
///
///
/// if true parameter Mode will be ignored and tests for all modes be
/// carried out
///
procedure DoTestDecode(Data: array of TTestEntry; Mode: TCipherMode; TestAllModes: Boolean = false);
published
procedure TestEncodeECBx;
procedure TestEncodeOFB8;
procedure TestEncodeCFB8;
procedure TestEncodeCFS8;
procedure TestEncodeCFBx;
procedure TestEncodeOFBx;
procedure TestEncodeCFSx;
procedure TestEncodeCBCx;
procedure TestEncodeCTSx;
procedure TestDecodeECBx;
procedure TestDecodeOFB8;
procedure TestDecodeCFB8;
procedure TestDecodeCFS8;
procedure TestDecodeCFBx;
procedure TestDecodeOFBx;
procedure TestDecodeCFSx;
procedure TestDecodeCBCx;
procedure TestDecodeCTSx;
procedure TestEncode;
procedure TestDecode;
end;
implementation
uses
DECUtil;
procedure TestTDECCipherModes.DoTestEncode(Data: array of TTestEntry; Mode: TCipherMode; TestAllModes: Boolean = false);
var
Dest : TBytes;
Source : TBytes;
i, n : Integer;
Result : string;
Cipher : TDECCipherModes;
begin
for i := Low(Data) to High(Data) do
begin
if not TestAllModes then
// Skip data for other modes
if Data[i].Mode <> Mode then
Continue;
Cipher := Data[i].TestClass.Create;
Cipher.Mode := Data[i].Mode;
try
Cipher.Init(BytesOf(RawByteString('ABCDEFGH')), BytesOf(Data[i].InitVector), $FF);
SetLength(Source, Length(Data[i].Input));
FillChar(Source[0], Length(Source), $FF);
Move(Data[i].Input[1], Source[0], Length(Data[i].Input));
SetLength(Dest, length(Source));
Cipher.Encode(Source[0], Dest[0], length(Source));
// Output is noted non hexadecimal
if Data[i].Output <> '' then
begin
for n := Low(Dest) to High(Dest) do
begin
CheckEquals(Ord(Data[i].Output[n+1]), Dest[n],
IntToStr(n+1) + '. position is wrong. ' +
IntToStr(i) + '. test series. Expected: ' +
string(Data[i].Output) + ' was: ' + string(DECUtil.BytesToRawString(Dest)));
end;
end
else
begin
// Output is noted in hex
Result := '';
for n := Low(Dest) to High(Dest) do
Result := Result + IntToHex(Dest[n], 2);
{$IF CompilerVersion >= 24.0}
for n := Low(Result) to High(Result) do
CheckEquals(char(Data[i].OutputHex[n]), Result[n],
IntToStr(n+1) + '. position is wrong. ' +
IntToStr(i) + '. test series. Expected: ' +
string(Data[i].OutputHex) + ' was: ' + Result);
{$ELSE}
for n := 1 to Length(Result) do
CheckEquals(char(Data[i].OutputHex[n]), Result[n],
IntToStr(n+1) + '. position is wrong. ' +
IntToStr(i) + '. test series. Expected: ' +
string(Data[i].OutputHex) + ' was: ' + Result);
{$IFEND}
end;
finally
Cipher.Free;
end;
end;
end;
procedure TestTDECCipherModes.DoTestDecode(Data: array of TTestEntry; Mode: TCipherMode; TestAllModes: Boolean = false);
var
Dest : TBytes;
Source : TBytes;
i, n, m : Integer;
Cipher : TDECCipherModes;
begin
for i := Low(Data) to High(Data) do
begin
if not TestAllModes then
// Skip data for other modes
if Data[i].Mode <> Mode then
Continue;
Cipher := Data[i].TestClass.Create;
Cipher.Mode := Data[i].Mode;
try
Cipher.Init(BytesOf(RawByteString('ABCDEFGH')), BytesOf(Data[i].InitVector), $FF);
if (Data[i].Output <> '') then
begin
SetLength(Source, Length(Data[i].Output));
FillChar(Source[0], Length(Source), $FF);
Move(Data[i].Output[1], Source[0], Length(Data[i].Output));
end
else
begin
SetLength(Source, Length(Data[i].OutputHex) div 2);
FillChar(Source[0], Length(Source), $FF);
n := 1; m := 0;
repeat
Source[m] := StrToInt('$' + char(Data[i].OutputHex[n]) + char(Data[i].OutputHex[n +1]));
inc(n, 2);
inc(m);
until (n > Length(Data[i].OutputHex));
end;
SetLength(Dest, length(Source));
Cipher.Decode(Source[0], Dest[0], length(Source));
for n := Low(Dest) to High(Dest) do
begin
CheckEquals(Ord(Data[i].Input[n+1]), Dest[n],
IntToStr(n+1) + '. position is wrong. ' +
IntToStr(i) + '. test series. Expected: ' +
string(Data[i].Input) + ' was: ' + string(DECUtil.BytesToRawString(Dest)));
end;
finally
Cipher.Free;
end;
end;
end;
procedure TestTDECCipherModes.TestEncodeECBx;
begin
DoTestEncode(Data, TCipherMode.cmECBx);
end;
procedure TestTDECCipherModes.TestEncodeOFB8;
begin
DoTestEncode(Data, TCipherMode.cmOFB8);
end;
procedure TestTDECCipherModes.TestEncodeCFB8;
begin
DoTestEncode(Data, TCipherMode.cmCFB8);
end;
procedure TestTDECCipherModes.TestEncodeCFS8;
begin
DoTestEncode(Data, TCipherMode.cmCFS8);
end;
procedure TestTDECCipherModes.TestEncodeCFBx;
begin
DoTestEncode(Data, TCipherMode.cmCFBx);
end;
procedure TestTDECCipherModes.TestEncodeOFBx;
begin
DoTestEncode(Data, TCipherMode.cmOFBx);
end;
procedure TestTDECCipherModes.TestEncodeCFSx;
begin
DoTestEncode(Data, TCipherMode.cmCFSx);
end;
procedure TestTDECCipherModes.TestEncodeCBCx;
begin
DoTestEncode(Data, TCipherMode.cmCBCx);
end;
procedure TestTDECCipherModes.TestEncodeCTSx;
begin
DoTestEncode(Data, TCipherMode.cmCTSx);
end;
procedure TestTDECCipherModes.TestDecodeECBx;
begin
DoTestDecode(Data, TCipherMode.cmECBx);
end;
procedure TestTDECCipherModes.TestDecodeOFB8;
begin
DoTestDecode(Data, TCipherMode.cmOFB8);
end;
procedure TestTDECCipherModes.TestDecodeCFB8;
begin
DoTestDecode(Data, TCipherMode.cmCFB8);
end;
procedure TestTDECCipherModes.TestDecodeCFS8;
begin
DoTestDecode(Data, TCipherMode.cmCFS8);
end;
procedure TestTDECCipherModes.TestDecodeCFBx;
begin
DoTestDecode(Data, TCipherMode.cmCFBx);
end;
procedure TestTDECCipherModes.TestDecodeOFBx;
begin
DoTestDecode(Data, TCipherMode.cmOFBx);
end;
procedure TestTDECCipherModes.TestDecodeCFSx;
begin
DoTestDecode(Data, TCipherMode.cmCFSx);
end;
procedure TestTDECCipherModes.TestDecodeCBCx;
begin
DoTestDecode(Data, TCipherMode.cmCBCx);
end;
procedure TestTDECCipherModes.TestDecodeCTSx;
begin
DoTestDecode(Data, TCipherMode.cmCTSx);
end;
procedure TestTDECCipherModes.TestEncode;
begin
DoTestEncode(Data, TCipherMode.cmCTSx, true);
end;
procedure TestTDECCipherModes.TestDecode;
begin
DoTestDecode(Data, TCipherMode.cmCTSx, true);
end;
initialization
// Register all test cases to be run
{$IFDEF DUnitX}
TDUnitX.RegisterTestFixture(TestTDECCipherModes);
{$ELSE}
RegisterTest(TestTDECCipherModes.Suite);
{$ENDIF}
end.