{***************************************************************************** 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 TestDECHashKDF; interface // Needs to be included before any other statements {$INCLUDE TestDefines.inc} {$INCLUDE ..\..\Source\DECOptions.inc} uses System.Classes, System.SysUtils, Generics.Collections, {$IFDEF DUnitX} DUnitX.TestFramework,DUnitX.DUnitCompatibility, {$ELSE} TestFramework, {$ENDIF} TestDECTestDataContainer, DECTypes, DECBaseClass, DECHash, DECHashBase, DECHashAuthentication, DECUtil, DECFormatBase; type /// /// Meta class to store class references in the list as there is no pointer /// to class methods as it seems /// THashClass = class of TDECHash; /// /// Type of the KDF or MGF variant to be tested /// TKDFMGFAlgorithm = (ktKDF1, ktKDF2, ktKDF3, ktKDFx, ktMGF1, ktMGFx); /// /// Record containing everything necessary for a single key deviation /// method test /// TKeyDeviationTestData = record /// /// Test data as normal text /// InputData : RawByteString; /// /// Optional parameter for some key deviation tests. /// SeedData : RawByteString; /// /// Test output in hexadecimal format /// OutputData : RawByteString; /// /// Requested output length /// MaskSize : Integer; /// /// If the entry is for a KDF1-KDF3 or KDFx test define which test method to call /// Algorithm : TKDFMGFAlgorithm; /// /// Class reference containing the class methods to be tested /// HashClass : TDECHashAuthenticationClass; /// /// Index, which i being used for the KDFx and MGFx variants of the /// original author of DEC /// Index : UInt32; end; /// /// List of all the test cases /// TKeyDeviationTestList = class(TList) public /// /// Add one entry to the list /// /// /// Test data as normal text /// /// /// Test output in hexadecimal format /// /// /// Requested output length /// /// /// Class reference containing the class methods to be tested /// /// /// Algorithm for which the test data specified is /// /// /// Index, which i being used for the KDFx and MGFx variants of the /// original author of DEC /// procedure Add(const InputData, OutputData: RawByteString; MaskSize : Integer; HashClass: TDECHashAuthenticationClass; AlgorithmType : TKDFMGFAlgorithm = ktKDF1; Index : UInt32 = 1); overload; /// /// Add one entry to the list /// /// /// Test data as normal text /// /// /// Optional parameter for some tests. Given in hexadecimal format. /// /// /// Test output in hexadecimal format /// /// /// Requested output length /// /// /// Class reference containing the class methods to be tested /// /// /// Algorithm for which the test data specified is /// /// /// Index, which i being used for the KDFx and MGFx variants of the /// original author of DEC /// procedure Add(const InputData, SeedData, OutputData: RawByteString; MaskSize : Integer; HashClass: TDECHashAuthenticationClass; AlgorithmType : TKDFMGFAlgorithm = ktKDF1; Index : UInt32 = 1); overload; end; {$IFDEF DUnitX} [TestFixture] {$ENDIF} /// /// All test cases for the MGF1 class methods. These are in this class rather /// than in TestTDECHash as the MGF1 class methods can only be called on a /// concrete hash class as they use the DigestSize and would otherwise fail. /// We currently mostly have test data for the SHA1 (= SHA with 128 bit length) /// algorithm, but the MGF1 method is universally useable so the tests got /// separated here. /// TestTHash_MGF1 = class(TTestCase) strict protected // List of test cases, defined in such a way that input, length, // output and hash class to be used shall be spoecified. FTestData : TKeyDeviationTestList; public procedure SetUp; override; procedure TearDown; override; procedure TestTBytesInternal(Algorithm : TKDFMGFAlgorithm); procedure TestRawMemoryInternal(Algorithm : TKDFMGFAlgorithm); published procedure TestMGF1TBytes; procedure TestMGF1RawMemory; procedure TestMGFxTBytes; procedure TestMGFxRawMemory; end; {$IFDEF DUnitX} [TestFixture] {$ENDIF} /// /// All test cases for the KDF class methods. These are in this class rather /// than in TestTDECHash as the KDF class methods can only be called on a /// concrete hash class as they use the DigestSize and would otherwise fail. /// We currently mostly have test data for the SHA and SHA256 algorithms, /// but the MGF1 method is universally useable so the tests got separated here. /// TestTHash_KDF = class(TTestCase) strict protected // List of test cases, defined in such a way that input, length, // output and hash class to be used shall be spoecified. FTestData : TKeyDeviationTestList; procedure InternalTest(KDFType: TKDFMGFAlgorithm); procedure InternalTestTBytes(KDFType: TKDFMGFAlgorithm); public procedure SetUp; override; procedure TearDown; override; published procedure TestKDF1; procedure TestKDF1TBytes; procedure TestKDF2; procedure TestKDF2TBytes; procedure TestKDF3; procedure TestKDF3TBytes; procedure TestKDFx; procedure TestKDFxTBytes; end; implementation uses DECFormat; { TKeyDeviationTestList } procedure TKeyDeviationTestList.Add(const InputData, OutputData: RawByteString; MaskSize: Integer; HashClass: TDECHashAuthenticationClass; AlgorithmType : TKDFMGFAlgorithm = ktKDF1; Index : UInt32 = 1); var Data: TKeyDeviationTestData; begin Data.InputData := InputData; Data.OutputData := OutputData; Data.MaskSize := MaskSize; Data.HashClass := HashClass; Data.Algorithm := AlgorithmType; Data.Index := Index; self.Add(Data); end; procedure TKeyDeviationTestList.Add(const InputData, SeedData, OutputData: RawByteString; MaskSize: Integer; HashClass: TDECHashAuthenticationClass; AlgorithmType : TKDFMGFAlgorithm = ktKDF1; Index : UInt32 = 1); var Data: TKeyDeviationTestData; begin Data.InputData := InputData; Data.SeedData := SeedData; //SysUtils.BytesOf(TFormat_HexL.Decode(SeedData)); Data.OutputData := OutputData; Data.MaskSize := MaskSize; Data.HashClass := HashClass; Data.Algorithm := AlgorithmType; Data.Index := Index; self.Add(Data); end; { TestTHash_KDF } procedure TestTHash_KDF.InternalTest(KDFType: TKDFMGFAlgorithm); var TestData : TKeyDeviationTestData; Result, ExpResult, Data, Seed : TBytes; begin for TestData in FTestData do begin if (TestData.Algorithm = KDFType) then begin Data := System.SysUtils.BytesOf(TestData.InputData); Seed := System.SysUtils.BytesOf(TestData.SeedData); ExpResult := System.SysUtils.BytesOf(TestData.OutputData); case KDFType of ktKDF1 : if (length(Seed) = 0) then Result := TestData.HashClass.KDF1(Data[0], length(Data), NullStr, 0, TestData.MaskSize) else Result := TestData.HashClass.KDF1(Data[0], length(Data), Seed[0], length(Seed), TestData.MaskSize); ktKDF2 : if (length(Seed) = 0) then Result := TestData.HashClass.KDF2(Data[0], length(Data), NullStr, 0, TestData.MaskSize) else Result := TestData.HashClass.KDF2(Data[0], length(Data), Seed[0], length(Seed), TestData.MaskSize); ktKDF3 : if (length(Seed) = 0) then Result := TestData.HashClass.KDF3(Data[0], length(Data), NullStr, 0, TestData.MaskSize) else Result := TestData.HashClass.KDF3(Data[0], length(Data), Seed[0], length(Seed), TestData.MaskSize); ktKDFx : if (length(Seed) = 0) then Result := TestData.HashClass.KDFx(Data[0], length(Data), NullStr, 0, TestData.MaskSize, TestData.Index) else Result := TestData.HashClass.KDFx(Data[0], length(Data), Seed[0], length(Seed), TestData.MaskSize, TestData.Index); end; CheckEquals(DECUtil.BytesToRawString(ExpResult), DECUtil.BytesToRawString(Result)); end; end; end; procedure TestTHash_KDF.InternalTestTBytes(KDFType: TKDFMGFAlgorithm); var TestData : TKeyDeviationTestData; Result, ExpResult, Data, Seed : TBytes; begin for TestData in FTestData do begin if (TestData.Algorithm = KDFType) then begin Data := System.SysUtils.BytesOf(TestData.InputData); Seed := System.SysUtils.BytesOf(TestData.SeedData); ExpResult := System.SysUtils.BytesOf(TestData.OutputData); if (KDFType = ktKDF1) then Result := TestData.HashClass.KDF1(Data, Seed, TestData.MaskSize); if (KDFType = ktKDF2) then Result := TestData.HashClass.KDF2(Data, Seed, TestData.MaskSize); if (KDFType = ktKDF3) then Result := TestData.HashClass.KDF3(Data, Seed, TestData.MaskSize); if (KDFType = ktKDFx) then Result := TestData.HashClass.KDFx(Data, Seed, TestData.MaskSize, TestData.Index); CheckEquals(DECUtil.BytesToRawString(ExpResult), DECUtil.BytesToRawString(Result)); end; end; end; procedure TestTHash_KDF.SetUp; begin inherited; FTestData := TKeyDeviationTestList.Create; FTestData.Add(TFormat_HexL.Decode('0001020304'), TFormat_HexL.Decode('0506070809'), TFormat_HexL.Decode('f52b'), 2, THash_MD2, ktKDF1); // Test data from Wolfgang Erhard's library FTestData.Add(TFormat_HexL.Decode('deadbeeffeebdaed'), '', TFormat_HexL.Decode('b0ad565b14b478cad4763856ff3016b1' + 'a93d840f87261bede7ddf0f9305a6e44'), 32, THash_SHA1, ktKDF1); FTestData.Add(TFormat_HexL.Decode('deadbeeffeebdaed'), '', TFormat_HexL.Decode('87261bede7ddf0f9305a6e44a74e6a08' + '46dede27f48205c6b141888742b0ce2c'), 32, THash_SHA1, ktKDF2); FTestData.Add(TFormat_HexL.Decode('deadbeeffeebdaed'), '', TFormat_HexL.Decode('60cef67059af33f6aebce1e10188f434' + 'f80306ac0360470aeb41f81bafb35790'), 32, THash_SHA1, ktKDF3); FTestData.Add(TFormat_HexL.Decode('032e45326fa859a72ec235acff929b15' + 'd1372e30b207255f0611b8f785d76437' + '4152e0ac009e509e7ba30cd2f1778e11' + '3b64e135cf4e2292c75efe5288edfda4'), '', TFormat_HexL.Decode('10a2403db42a8743cb989de86e668d16' + '8cbe6046e23ff26f741e87949a3bba13' + '11ac179f819a3d18412e9eb45668f292' + '3c087c1299005f8d5fd42ca257bc93e8' + 'fee0c5a0d2a8aa70185401fbbd99379e' + 'c76c663e9a29d0b70f3fe261a59cdc24' + '875a60b4aacb1319fa11c3365a8b79a4' + '4669f26fba933d012db213d7e3b16349'), 128, THash_SHA256, ktKDF2); FTestData.Add(TFormat_HexL.Decode('032e45326fa859a72ec235acff929b15' + 'd1372e30b207255f0611b8f785d76437' + '4152e0ac009e509e7ba30cd2f1778e11' + '3b64e135cf4e2292c75efe5288edfda4'), '', TFormat_HexL.Decode('0e6a26eb7b956ccb8b3bdc1ca975bc57' + 'c3989e8fbad31a224655d800c4695484' + '0ff32052cdf0d640562bdfadfa263cfc' + 'cf3c52b29f2af4a1869959bc77f854cf' + '15bd7a25192985a842dbff8e13efee5b' + '7e7e55bbe4d389647c686a9a9ab3fb88' + '9b2d7767d3837eea4e0a2f04b53ca8f5' + '0fb31225c1be2d0126c8c7a4753b0807'), 128, THash_SHA1, ktKDF2); FTestData.Add(TFormat_HexL.Decode('ca7c0f8c3ffa87a96e1b74ac8e6af594' + '347bb40a'), '', TFormat_HexL.Decode('744ab703f5bc082e59185f6d049d2d36' + '7db245c2'), 20, THash_SHA1, ktKDF2); FTestData.Add(TFormat_HexL.Decode('0499b502fc8b5bafb0f4047e731d1f9f' + 'd8cd0d8881'), '', TFormat_HexL.Decode('03c62280c894e103c680b13cd4b4ae74' + '0a5ef0c72547292f82dc6b1777f47d63' + 'ba9d1ea732dbf386'), 40, THash_SHA1, ktKDF2); // Test vector #1, ANSI X9.63 FTestData.Add(TFormat_HexL.Decode('96c05619d56c328ab95fe84b18264b08' + '725b85e33fd34f08'), '', TFormat_HexL.Decode('443024c3dae66b95e6f5670601558f71'), 16, THash_SHA256, ktKDF2); // Test vector #2, ANSI X9.63 FTestData.Add(TFormat_HexL.Decode('96f600b73ad6ac5629577eced51743dd' + '2c24c21b1ac83ee4'), '', TFormat_HexL.Decode('b6295162a7804f5667ba9070f82fa522'), 16, THash_SHA256, ktKDF2); // Test vector #3, ANSI X9.63 FTestData.Add(TFormat_HexL.Decode('22518b10e70f2a3f243810ae3254139e' + 'fbee04aa57c7af7d'), TFormat_HexL.Decode('75eef81aa3041e33b80971203d2c0c52'), TFormat_HexL.Decode('c498af77161cc59f2962b9a713e2b215' + '152d139766ce34a776df11866a69bf2e' + '52a13d9c7c6fc878c50c5ea0bc7b00e0' + 'da2447cfd874f6cf92f30d0097111485' + '500c90c3af8b487872d04685d14c8d1d' + 'c8d7fa08beb0ce0ababc11f0bd496269' + '142d43525a78e5bc79a17f59676a5706' + 'dc54d54d4d1f0bd7e386128ec26afc21'), 128, THash_SHA256, ktKDF2); // Test vector #4, ANSI X9.63 FTestData.Add(TFormat_HexL.Decode('7e335afa4b31d772c0635c7b0e06f26f' + 'cd781df947d2990a'), TFormat_HexL.Decode('d65a4812733f8cdbcdfb4b2f4c191d87'), TFormat_HexL.Decode('c0bd9e38a8f9de14c2acd35b2f3410c6' + '988cf02400543631e0d6a4c1d030365a' + 'cbf398115e51aaddebdc9590664210f9' + 'aa9fed770d4c57edeafa0b8c14f93300' + '865251218c262d63dadc47dfa0e02848' + '26793985137e0a544ec80abf2fdf5ab9' + '0bdaea66204012efe34971dc431d625c' + 'd9a329b8217cc8fd0d9f02b13f2f6b0b'), 128, THash_SHA256, ktKDF2); // Test for DEC's own KDFx variant, testdata synthesised and verified against // DEC V5.2 FTestData.Add(TFormat_HexL.Decode('deadbeeffeebdaed'), '', TFormat_HexL.Decode('e473e6b6065219bab4fde9113bd80301'+ '6cc49979783559585b0c8bb5bbdfa4cd'), 32, THash_SHA1, ktKDFx, 1); FTestData.Add(TFormat_HexL.Decode('deadbeeffeebdaed'), '', TFormat_HexL.Decode('2dfb9508c07cd1521849d8dd92585ec0'+ '9499132de0f6b8d4ed2768ec1c83f0ed'), 32, THash_SHA1, ktKDFx, 2); FTestData.Add(TFormat_HexL.Decode('7e335afa4b31d772c0635c7b0e06f26f' + 'cd781df947d2990a'), TFormat_HexL.Decode('d65a4812733f8cdbcdfb4b2f4c191d87'), TFormat_HexL.Decode('934006d019879d1ee2787b27ed57841b' + '66433425d6a0f4ca6abb20f6967dc660' + 'd04f8577b13ec8d4ec54610a78e0881f' + '2ae26f482c81053c6d8951e787b2e4a9' + '9b3c2a95bc196948e1f1819c55ba08d6' + '6a6ca395e9929eaee752b5dc324e980d' + '71f0e8c1b244bb3b0c09b903ebc446e2' + '925bf1a7041923a3910959e5dcd6afd2'), 128, THash_SHA256, ktKDFx, 1); FTestData.Add(TFormat_HexL.Decode('7e335afa4b31d772c0635c7b0e06f26f' + 'cd781df947d2990a'), TFormat_HexL.Decode('d65a4812733f8cdbcdfb4b2f4c191d87'), TFormat_HexL.Decode('2c26a1303d2146d61384e689debf541f' + 'bcd832e9343f2771b7e28dd877f096d5' + '95e0e12c768d74d72a91176908b34842' + 'a0a32d7b3f8293d169fa873a5a7e747e' + '0e6e054e73c2ca1bb89a1772e4e5b0f6' + '7cead338829bb02e7012254f4f79e63a' + '619e6f14782af946e169c2870ec6ca3a' + '68377d2ad42196987278f93674c7d861'), 128, THash_SHA256, ktKDFx, 2); end; procedure TestTHash_KDF.TearDown; begin FTestData.Free; inherited; end; procedure TestTHash_KDF.TestKDF1; begin InternalTest(ktKDF1); end; procedure TestTHash_KDF.TestKDF1TBytes; begin InternalTestTBytes(ktKDF1); end; procedure TestTHash_KDF.TestKDF2; begin InternalTest(ktKDF2); end; procedure TestTHash_KDF.TestKDF2TBytes; begin InternalTestTBytes(ktKDF2); end; procedure TestTHash_KDF.TestKDF3; begin InternalTest(ktKDF3); end; procedure TestTHash_KDF.TestKDF3TBytes; begin InternalTestTBytes(ktKDF3); end; procedure TestTHash_KDF.TestKDFx; begin InternalTest(ktKDFx); end; procedure TestTHash_KDF.TestKDFxTBytes; begin InternalTestTBytes(ktKDFx); end; { THash_TestMGF1 } procedure TestTHash_MGF1.SetUp; begin inherited; FTestData := TKeyDeviationTestList.Create; FTestData.Add('foo', '1ac907', 3, THash_SHA1, ktMGF1); FTestData.Add('foo', '1ac9075cd4', 5, THash_SHA1, ktMGF1); FTestData.Add('bar', 'bc0c655e01', 5, THash_SHA1, ktMGF1); FTestData.Add('bar', 'bc0c655e016bc2931d85a2e675181adcef7f581f76df2739da74f' + 'aac41627be2f7f415c89e983fd0ce80ced9878641cb4876', 50, THash_SHA1, ktMGF1); FTestData.Add('bar', '382576a7841021cc28fc4c0948753fb8312090cea942ea4c4e735' + 'd10dc724b155f9f6069f289d61daca0cb814502ef04eae1', 50, THash_SHA256, ktMGF1); FTestData.Add('foo', 'b2ae0e', 3, THash_SHA1, ktMGFx, 1); FTestData.Add('foo', '44ffe3', 3, THash_SHA1, ktMGFx, 2); FTestData.Add('foo', 'b2ae0e6e26', 5, THash_SHA1, ktMGFx, 1); FTestData.Add('foo', '44ffe3a40b', 5, THash_SHA1, ktMGFx, 2); FTestData.Add('bar', '21dfca12e1', 5, THash_SHA1, ktMGFx, 1); FTestData.Add('bar', '596eb7fe1b', 5, THash_SHA1, ktMGFx, 2); FTestData.Add('bar', '21dfca12e13ebcaa77a5b6c0ff7023266e0dd54498306070fc735' + 'ad7b0d88e14cb1acc887f564c7adb677a1b6b4b1e6b3f07', 50, THash_SHA1, ktMGFx, 1); FTestData.Add('bar', '596eb7fe1ba0a133e7c445c745270bf6433dc88cef9f922840f75' + 'd4867a247ea37fc9458c934e4675bcd7300722ee8d07b37', 50, THash_SHA1, ktMGFx, 2); FTestData.Add('bar', 'e01f7238400a2f1501bbaaf937d3d081bda4fe5bccc713134f5d3' + 'a580bd66783d379e6d91c6e91a1072744ae42fe4e182f32', 50, THash_SHA256, ktMGFx, 1); FTestData.Add('bar', '816453f0040d4f0469ccfcb520bf63fbf4616e46adff6708d40b1' + '63041b91a234baa7f8a1fb86b23ef81df6e1121233dd88e', 50, THash_SHA256, ktMGFx, 2); end; procedure TestTHash_MGF1.TearDown; begin FTestData.Free; inherited; end; procedure TestTHash_MGF1.TestMGF1RawMemory; begin TestRawMemoryInternal(ktMGF1) end; procedure TestTHash_MGF1.TestMGF1TBytes; begin TestTBytesInternal(ktMGF1); end; procedure TestTHash_MGF1.TestMGFxRawMemory; begin TestRawMemoryInternal(ktMGFx) end; procedure TestTHash_MGF1.TestMGFxTBytes; begin TestTBytesInternal(ktMGFx); end; procedure TestTHash_MGF1.TestRawMemoryInternal(Algorithm : TKDFMGFAlgorithm); var InputData : TBytes; OutputData : TBytes; i : Integer; begin for i := 0 to FTestData.Count - 1 do begin InputData := BytesOf(FTestData[i].InputData); // Skip tests which are not for the selected algorithm if FTestData[i].Algorithm <> Algorithm then Continue; case FTestData[i].Algorithm of ktMGF1 : OutputData := FTestData[i].HashClass.MGF1(InputData[0], length(InputData), FTestData[i].MaskSize); ktMGFx : OutputData := FTestData[i].HashClass.MGFx(InputData[0], length(InputData), FTestData[i].MaskSize, FTestData[i].Index); end; CheckEquals(FTestData[i].OutputData, DECUtil.BytesToRawString(TFormat_HEXL.Encode(OutputData)), 'MGFT1/MGFx test failed at index ' + IntToStr(i)); end; end; procedure TestTHash_MGF1.TestTBytesInternal(Algorithm : TKDFMGFAlgorithm); var InputData : TBytes; OutputData : TBytes; i : Integer; begin for i := 0 to FTestData.Count - 1 do begin InputData := BytesOf(FTestData[i].InputData); // Skip tests which are not for the selected algorithm if FTestData[i].Algorithm <> Algorithm then Continue; case FTestData[i].Algorithm of ktMGF1 : OutputData := FTestData[i].HashClass.MGF1(InputData, FTestData[i].MaskSize); ktMGFx : OutputData := FTestData[i].HashClass.MGFx(InputData, FTestData[i].MaskSize, FTestData[i].Index); end; CheckEquals(FTestData[i].OutputData, DECUtil.BytesToRawString(TFormat_HEXL.Encode(OutputData)), 'MGF1/MGFx test failed at index ' + IntToStr(i)); end; end; initialization // Register any test cases with the test runner {$IFDEF DUnitX} TDUnitX.RegisterTestFixture(TestTHash_MGF1); TDUnitX.RegisterTestFixture(TestTHash_KDF); {$ELSE} RegisterTests('DECHashKDF', [TestTHash_MGF1.Suite, TestTHash_KDF.Suite]); {$ENDIF} end.