Browse Source

add some more tests.

- minor improvements like shake128 and shake256 addition
Ugochukwu Mmaduekwe 6 years ago
parent
commit
dd3c7a4435

+ 3 - 1
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.TestInsight.dpr

@@ -418,7 +418,9 @@ uses
   ShortenedDigestTests in '..\src\Others\ShortenedDigestTests.pas',
   ShortenedDigestTests in '..\src\Others\ShortenedDigestTests.pas',
   Kdf1GeneratorTests in '..\src\Crypto\Kdf1GeneratorTests.pas',
   Kdf1GeneratorTests in '..\src\Crypto\Kdf1GeneratorTests.pas',
   Kdf2GeneratorTests in '..\src\Crypto\Kdf2GeneratorTests.pas',
   Kdf2GeneratorTests in '..\src\Crypto\Kdf2GeneratorTests.pas',
-  Argon2Tests in '..\src\Crypto\Argon2Tests.pas';
+  Argon2Tests in '..\src\Crypto\Argon2Tests.pas',
+  DigestUtilitiesTests in '..\src\Security\DigestUtilitiesTests.pas',
+  DigestTests in '..\src\Others\DigestTests.pas';
 
 
 begin
 begin
 
 

+ 3 - 1
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr

@@ -421,7 +421,9 @@ uses
   ShortenedDigestTests in '..\src\Others\ShortenedDigestTests.pas',
   ShortenedDigestTests in '..\src\Others\ShortenedDigestTests.pas',
   Kdf1GeneratorTests in '..\src\Crypto\Kdf1GeneratorTests.pas',
   Kdf1GeneratorTests in '..\src\Crypto\Kdf1GeneratorTests.pas',
   Kdf2GeneratorTests in '..\src\Crypto\Kdf2GeneratorTests.pas',
   Kdf2GeneratorTests in '..\src\Crypto\Kdf2GeneratorTests.pas',
-  Argon2Tests in '..\src\Crypto\Argon2Tests.pas';
+  Argon2Tests in '..\src\Crypto\Argon2Tests.pas',
+  DigestUtilitiesTests in '..\src\Security\DigestUtilitiesTests.pas',
+  DigestTests in '..\src\Others\DigestTests.pas';
 
 
 begin
 begin
 
 

+ 9 - 1
CryptoLib.Tests/FreePascal.Tests/CryptoLib.Tests.lpi

@@ -77,7 +77,7 @@
         <PackageName Value="FCL"/>
         <PackageName Value="FCL"/>
       </Item4>
       </Item4>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="67">
+    <Units Count="69">
       <Unit0>
       <Unit0>
         <Filename Value="CryptoLib.lpr"/>
         <Filename Value="CryptoLib.lpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -347,6 +347,14 @@
         <Filename Value="..\src\Crypto\Argon2Tests.pas"/>
         <Filename Value="..\src\Crypto\Argon2Tests.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit66>
       </Unit66>
+      <Unit67>
+        <Filename Value="..\src\Others\DigestTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit67>
+      <Unit68>
+        <Filename Value="..\src\Security\DigestUtilitiesTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit68>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>

+ 2 - 0
CryptoLib.Tests/FreePascal.Tests/CryptoLib.lpr

@@ -68,6 +68,8 @@ uses
   Kdf1GeneratorTests,
   Kdf1GeneratorTests,
   Kdf2GeneratorTests,
   Kdf2GeneratorTests,
   Argon2Tests,
   Argon2Tests,
+  DigestTests,
+  DigestUtilitiesTests,
   ClpFixedSecureRandom,
   ClpFixedSecureRandom,
   ClpIFixedSecureRandom,
   ClpIFixedSecureRandom,
   ClpShortenedDigest,
   ClpShortenedDigest,

+ 9 - 1
CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.Tests.lpi

@@ -37,7 +37,7 @@
         <PackageName Value="FCL"/>
         <PackageName Value="FCL"/>
       </Item2>
       </Item2>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="67">
+    <Units Count="69">
       <Unit0>
       <Unit0>
         <Filename Value="CryptoLibConsole.lpr"/>
         <Filename Value="CryptoLibConsole.lpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -306,6 +306,14 @@
         <Filename Value="..\src\Crypto\Argon2Tests.pas"/>
         <Filename Value="..\src\Crypto\Argon2Tests.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit66>
       </Unit66>
+      <Unit67>
+        <Filename Value="..\src\Others\DigestTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit67>
+      <Unit68>
+        <Filename Value="..\src\Security\DigestUtilitiesTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit68>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>

+ 2 - 0
CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpr

@@ -66,6 +66,8 @@ uses
   Kdf1GeneratorTests,
   Kdf1GeneratorTests,
   Kdf2GeneratorTests,
   Kdf2GeneratorTests,
   Argon2Tests,
   Argon2Tests,
+  DigestTests,
+  DigestUtilitiesTests,
   ClpFixedSecureRandom,
   ClpFixedSecureRandom,
   ClpIFixedSecureRandom,
   ClpIFixedSecureRandom,
   ClpShortenedDigest,
   ClpShortenedDigest,

+ 4 - 4
CryptoLib.Tests/src/Crypto/DSATests.pas

@@ -204,8 +204,8 @@ begin
 
 
   if (not TArrayUtils.AreEqual(sigBytes, sig)) then
   if (not TArrayUtils.AreEqual(sigBytes, sig)) then
   begin
   begin
-    Fail(TConverters.ConvertBytesToString(&message, TEncoding.UTF8) +
-      ' signature incorrect');
+    Fail(Format('%s %s', [TConverters.ConvertBytesToString(&message,
+      TEncoding.UTF8), 'signature incorrect']));
   end;
   end;
 
 
   sgr.Init(false, vKey);
   sgr.Init(false, vKey);
@@ -214,8 +214,8 @@ begin
 
 
   if (not(sgr.VerifySignature(sigBytes))) then
   if (not(sgr.VerifySignature(sigBytes))) then
   begin
   begin
-    Fail(TConverters.ConvertBytesToString(&message, TEncoding.UTF8) +
-      ' verification failed');
+    Fail(Format('%s %s', [TConverters.ConvertBytesToString(&message,
+      TEncoding.UTF8), 'verification failed']));
   end;
   end;
 end;
 end;
 
 

+ 6 - 4
CryptoLib.Tests/src/Math/PascalCoinECIESTests.pas

@@ -51,6 +51,7 @@ uses
   ClpIMac,
   ClpIMac,
   ClpMacUtilities,
   ClpMacUtilities,
   ClpIX9ECParameters,
   ClpIX9ECParameters,
+  ClpConverters,
   ClpCryptoLibTypes;
   ClpCryptoLibTypes;
 
 
 type
 type
@@ -250,8 +251,8 @@ begin
   CipherEncrypt.Init(True, RecreatePublicKeyFromAffineXandAffineYCoord(keyType,
   CipherEncrypt.Init(True, RecreatePublicKeyFromAffineXandAffineYCoord(keyType,
     THex.Decode(RawAffineXCoord), THex.Decode(RawAffineYCoord)),
     THex.Decode(RawAffineXCoord), THex.Decode(RawAffineYCoord)),
     GetPascalCoinIESParameterSpec(), FRandom);
     GetPascalCoinIESParameterSpec(), FRandom);
-  Result := THex.Encode(CipherEncrypt.DoFinal(TEncoding.ASCII.GetBytes
-    (UnicodeString(PayloadToEncrypt))));
+  Result := THex.Encode(CipherEncrypt.DoFinal(TConverters.ConvertStringToBytes
+    (PayloadToEncrypt, TEncoding.ASCII)));
 end;
 end;
 
 
 function TTestPascalCoinECIES.DoPascalCoinECIESDecrypt(keyType: TKeyType;
 function TTestPascalCoinECIES.DoPascalCoinECIESDecrypt(keyType: TKeyType;
@@ -264,8 +265,9 @@ begin
     CipherDecrypt := TIESCipher.Create(GetECIESPascalCoinCompatibilityEngine());
     CipherDecrypt := TIESCipher.Create(GetECIESPascalCoinCompatibilityEngine());
     CipherDecrypt.Init(False, RecreatePrivateKeyFromByteArray(keyType,
     CipherDecrypt.Init(False, RecreatePrivateKeyFromByteArray(keyType,
       THex.Decode(RawPrivateKey)), GetPascalCoinIESParameterSpec(), FRandom);
       THex.Decode(RawPrivateKey)), GetPascalCoinIESParameterSpec(), FRandom);
-    Result := String(TEncoding.ASCII.GetString
-      ((CipherDecrypt.DoFinal(THex.Decode(PayloadToDecrypt)))));
+
+    Result := TConverters.ConvertBytesToString
+      (CipherDecrypt.DoFinal(THex.Decode(PayloadToDecrypt)), TEncoding.ASCII);
   except
   except
     // should only happen if decryption fails
     // should only happen if decryption fails
     raise;
     raise;

+ 304 - 0
CryptoLib.Tests/src/Others/DigestTests.pas

@@ -0,0 +1,304 @@
+{ *********************************************************************************** }
+{ *                              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 DigestTests;
+
+interface
+
+{$IFDEF FPC}
+{$MODE DELPHI}
+{$ENDIF FPC}
+
+uses
+  SysUtils,
+{$IFDEF FPC}
+  fpcunit,
+  testregistry,
+{$ELSE}
+  TestFramework,
+{$ENDIF FPC}
+  ClpMiscObjectIdentifiers,
+  ClpRosstandartObjectIdentifiers,
+  ClpIDigest,
+  ClpDigestUtilities,
+  ClpEncoders,
+  ClpArrayUtils,
+  ClpCryptoLibTypes,
+  ClpConverters;
+
+type
+
+  TCryptoLibTestCase = class abstract(TTestCase)
+
+  end;
+
+type
+
+  TTestDigest = class(TCryptoLibTestCase)
+  private
+  var
+    FabcVectors: TCryptoLibMatrixGenericArray<String>;
+
+    procedure DoTest(const algorithm: String);
+    procedure DoAbcTest(const algorithm, hash: String);
+
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+  published
+    procedure TestDigests();
+
+  end;
+
+implementation
+
+{ TTestDigest }
+
+procedure TTestDigest.SetUp;
+begin
+  inherited;
+  FabcVectors := TCryptoLibMatrixGenericArray<String>.Create
+    (TCryptoLibStringArray.Create('MD2', 'da853b0d3f88d99b30283a69e6ded6bb'),
+    TCryptoLibStringArray.Create('MD4', 'a448017aaf21d8525fc10ae87aa6729d'),
+    TCryptoLibStringArray.Create('MD5', '900150983cd24fb0d6963f7d28e17f72'),
+    TCryptoLibStringArray.Create('SHA-1',
+    'a9993e364706816aba3e25717850c26c9cd0d89d'),
+    TCryptoLibStringArray.Create('SHA-224',
+    '23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7'),
+    TCryptoLibStringArray.Create('SHA-256',
+    'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'),
+    TCryptoLibStringArray.Create('SHA-384',
+    'cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7'),
+    TCryptoLibStringArray.Create('SHA-512',
+    'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f'),
+    TCryptoLibStringArray.Create('SHA-512/224',
+    '4634270F707B6A54DAAE7530460842E20E37ED265CEEE9A43E8924AA'),
+    TCryptoLibStringArray.Create('SHA-512/256',
+    '53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23'),
+    TCryptoLibStringArray.Create('RIPEMD128',
+    'c14a12199c66e4ba84636b0f69144c77'),
+    TCryptoLibStringArray.Create('RIPEMD160',
+    '8eb208f7e05d987a9b044a8e98c6b087f15a0bfc'),
+    TCryptoLibStringArray.Create('RIPEMD256',
+    'afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65'),
+    TCryptoLibStringArray.Create('RIPEMD320',
+    'de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d'),
+    TCryptoLibStringArray.Create('Tiger',
+    '2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93'),
+    TCryptoLibStringArray.Create('GOST3411',
+    'b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c'),
+    TCryptoLibStringArray.Create('WHIRLPOOL',
+    '4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5'),
+    TCryptoLibStringArray.Create('SM3',
+    '66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0'),
+    TCryptoLibStringArray.Create('SHA3-224',
+    'e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf'),
+    TCryptoLibStringArray.Create('SHA3-256',
+    '3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532'),
+    TCryptoLibStringArray.Create('SHA3-384',
+    'ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25'),
+    TCryptoLibStringArray.Create('SHA3-512',
+    'b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0'),
+    TCryptoLibStringArray.Create('KECCAK-224',
+    'c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8'),
+    TCryptoLibStringArray.Create('KECCAK-256',
+    '4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45'),
+    TCryptoLibStringArray.Create('KECCAK-288',
+    '20ff13d217d5789fa7fc9e0e9a2ee627363ec28171d0b6c52bbd2f240554dbc94289f4d6'),
+    TCryptoLibStringArray.Create('KECCAK-384',
+    'f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e'),
+    TCryptoLibStringArray.Create('KECCAK-512',
+    '18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96'),
+    TCryptoLibStringArray.Create('BLAKE2B-160',
+    '384264f676f39536840523f284921cdc68b6846b'),
+    TCryptoLibStringArray.Create('BLAKE2B-256',
+    'bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319'),
+    TCryptoLibStringArray.Create('BLAKE2B-384',
+    '6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4'),
+    TCryptoLibStringArray.Create('BLAKE2B-512',
+    'ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923'),
+    TCryptoLibStringArray.Create(TMiscObjectIdentifiers.id_blake2b160.Id,
+    '384264f676f39536840523f284921cdc68b6846b'),
+    TCryptoLibStringArray.Create(TMiscObjectIdentifiers.id_blake2b256.Id,
+    'bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319'),
+    TCryptoLibStringArray.Create(TMiscObjectIdentifiers.id_blake2b384.Id,
+    '6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4'),
+    TCryptoLibStringArray.Create(TMiscObjectIdentifiers.id_blake2b512.Id,
+    'ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923'),
+    TCryptoLibStringArray.Create('BLAKE2S-128',
+    'aa4938119b1dc7b87cbad0ffd200d0ae'),
+    TCryptoLibStringArray.Create('BLAKE2S-160',
+    '5ae3b99be29b01834c3b508521ede60438f8de17'),
+    TCryptoLibStringArray.Create('BLAKE2S-224',
+    '0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55'),
+    TCryptoLibStringArray.Create('BLAKE2S-256',
+    '508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982'),
+    TCryptoLibStringArray.Create(TMiscObjectIdentifiers.id_blake2s128.Id,
+    'aa4938119b1dc7b87cbad0ffd200d0ae'),
+    TCryptoLibStringArray.Create(TMiscObjectIdentifiers.id_blake2s160.Id,
+    '5ae3b99be29b01834c3b508521ede60438f8de17'),
+    TCryptoLibStringArray.Create(TMiscObjectIdentifiers.id_blake2s224.Id,
+    '0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55'),
+    TCryptoLibStringArray.Create(TMiscObjectIdentifiers.id_blake2s256.Id,
+    '508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982'),
+    TCryptoLibStringArray.Create('GOST3411-2012-256',
+    '4e2919cf137ed41ec4fb6270c61826cc4fffb660341e0af3688cd0626d23b481'),
+    TCryptoLibStringArray.Create(TRosstandartObjectIdentifiers.
+    id_tc26_gost_3411_12_256.Id,
+    '4e2919cf137ed41ec4fb6270c61826cc4fffb660341e0af3688cd0626d23b481'),
+    TCryptoLibStringArray.Create('GOST3411-2012-512',
+    '28156e28317da7c98f4fe2bed6b542d0dab85bb224445fcedaf75d46e26d7eb8d5997f3e0915dd6b7f0aab08d9c8beb0d8c64bae2ab8b3c8c6bc53b3bf0db728'),
+    TCryptoLibStringArray.Create(TRosstandartObjectIdentifiers.
+    id_tc26_gost_3411_12_512.Id,
+    '28156e28317da7c98f4fe2bed6b542d0dab85bb224445fcedaf75d46e26d7eb8d5997f3e0915dd6b7f0aab08d9c8beb0d8c64bae2ab8b3c8c6bc53b3bf0db728'),
+    TCryptoLibStringArray.Create('DSTU7564-256',
+    '0bd1b36109f1318411a0517315aa46b8839df06622a278676f5487996c9cfc04'));
+end;
+
+procedure TTestDigest.TearDown;
+begin
+  FabcVectors := Nil;
+  inherited;
+end;
+
+procedure TTestDigest.DoAbcTest(const algorithm, hash: String);
+var
+  abc, result: TCryptoLibByteArray;
+  digest: IDigest;
+begin
+  abc := TBytes.Create($61, $62, $63);
+
+  digest := TDigestUtilities.GetDigest(algorithm);
+
+  digest.BlockUpdate(abc, 0, System.Length(abc));
+  result := TDigestUtilities.DoFinal(digest);
+
+  if (not TArrayUtils.AreEqual(result, THex.Decode(hash))) then
+  begin
+    Fail(Format('abc result not equal for %s', [algorithm]));
+  end;
+end;
+
+procedure TTestDigest.DoTest(const algorithm: String);
+var
+  &message, result, result2: TCryptoLibByteArray;
+  digest, d: IDigest;
+  i: Int32;
+begin
+  &message := TConverters.ConvertStringToBytes('hello world', TEncoding.ASCII);
+
+  digest := TDigestUtilities.GetDigest(algorithm);
+
+  digest.BlockUpdate(&message, 0, System.Length(&message));
+  result := TDigestUtilities.DoFinal(digest);
+
+  digest.BlockUpdate(&message, 0, System.Length(&message));
+  result2 := TDigestUtilities.DoFinal(digest);
+
+  // test one digest the same message with the same instance
+  if (not TArrayUtils.AreEqual(result, result2)) then
+  begin
+    Fail('Result object 1 not equal');
+  end;
+
+  // test two, single byte updates
+  for i := 0 to System.Pred(System.Length(&message)) do
+  begin
+    digest.Update(&message[i]);
+  end;
+
+  result2 := TDigestUtilities.DoFinal(digest);
+
+  if (not TArrayUtils.AreEqual(result, result2)) then
+  begin
+    Fail('Result object 2 not equal');
+  end;
+
+  // test three, two half updates
+  digest.BlockUpdate(&message, 0, System.Length(&message) div 2);
+  digest.BlockUpdate(&message, System.Length(&message) div 2,
+    System.Length(&message) - (System.Length(&message) div 2));
+
+  result2 := TDigestUtilities.DoFinal(digest);
+
+  if (not TArrayUtils.AreEqual(result, result2)) then
+  begin
+    Fail('Result object 3 not equal');
+  end;
+
+  // test four, clone test
+  digest.BlockUpdate(&message, 0, System.Length(&message) div 2);
+  d := digest.Clone();
+  digest.BlockUpdate(&message, System.Length(&message) div 2,
+    System.Length(&message) - (System.Length(&message) div 2));
+
+  result2 := TDigestUtilities.DoFinal(digest);
+
+  if (not TArrayUtils.AreEqual(result, result2)) then
+  begin
+    Fail('Result object 4(a) not equal');
+  end;
+
+  d.BlockUpdate(&message, System.Length(&message) div 2, System.Length(&message)
+    - (System.Length(&message) div 2));
+
+  result2 := TDigestUtilities.DoFinal(d);
+
+  if (not TArrayUtils.AreEqual(result, result2)) then
+  begin
+    Fail('Result object 4(b) not equal');
+  end;
+
+  // test five, check reset() method
+  digest.BlockUpdate(&message, 0, System.Length(&message) div 2);
+  digest.Reset();
+  digest.BlockUpdate(&message, 0, System.Length(&message) div 2);
+  digest.BlockUpdate(&message, System.Length(&message) div 2,
+    System.Length(&message) - (System.Length(&message) div 2));
+
+  result2 := TDigestUtilities.DoFinal(digest);
+
+  if (not TArrayUtils.AreEqual(result, result2)) then
+  begin
+    Fail('Result object 5 not equal');
+  end;
+
+end;
+
+procedure TTestDigest.TestDigests;
+var
+  i: Int32;
+begin
+  for i := 0 to System.Pred(System.Length(FabcVectors[0])) do
+  begin
+    DoTest(FabcVectors[i][0]);
+
+    DoAbcTest(FabcVectors[i][0], FabcVectors[i][1]);
+  end;
+end;
+
+initialization
+
+// Register any test cases with the test runner
+
+{$IFDEF FPC}
+  RegisterTest(TTestDigest);
+{$ELSE}
+  RegisterTest(TTestDigest.Suite);
+{$ENDIF FPC}
+
+end.

+ 280 - 0
CryptoLib.Tests/src/Security/DigestUtilitiesTests.pas

@@ -0,0 +1,280 @@
+{ *********************************************************************************** }
+{ *                              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 DigestUtilitiesTests;
+
+interface
+
+{$IFDEF FPC}
+{$MODE DELPHI}
+{$ENDIF FPC}
+
+uses
+  SysUtils,
+{$IFDEF FPC}
+  fpcunit,
+  testregistry,
+{$ELSE}
+  TestFramework,
+{$ENDIF FPC}
+  HlpIHashInfo,
+  HlpHashFactory,
+  ClpIDigest,
+  ClpDigest,
+  ClpDigestUtilities,
+  ClpArrayUtils,
+  ClpCryptoLibTypes;
+
+type
+
+  TCryptoLibTestCase = class abstract(TTestCase)
+
+  end;
+
+type
+
+  TTestDigestUtilities = class(TCryptoLibTestCase)
+  private
+  var
+    FTestBytes: TCryptoLibByteArray;
+
+    function MakeTestPlainDigest(const digest: IDigest): TCryptoLibByteArray;
+    procedure CheckPlainDigestAlgorithm(const name: String;
+      const digest: IDigest);
+
+    function MakeTestXofDigest(const digest: IDigest; count: Int32)
+      : TCryptoLibByteArray;
+    procedure CheckXofDigestAlgorithm(const name: String;
+      const digest: IDigest);
+
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+  published
+    procedure TestAlgorithms();
+
+  end;
+
+implementation
+
+{ TTestDigestUtilities }
+
+procedure TTestDigestUtilities.SetUp;
+begin
+  inherited;
+  System.SetLength(FTestBytes, 100);
+end;
+
+procedure TTestDigestUtilities.TearDown;
+begin
+  FTestBytes := Nil;
+  inherited;
+end;
+
+function TTestDigestUtilities.MakeTestXofDigest(const digest: IDigest;
+  count: Int32): TCryptoLibByteArray;
+begin
+  System.SetLength(Result, count);
+  digest.BlockUpdate(FTestBytes, 0, System.Length(FTestBytes));
+  digest.DoFinal(Result, 0);
+end;
+
+function TTestDigestUtilities.MakeTestPlainDigest(const digest: IDigest)
+  : TCryptoLibByteArray;
+var
+  i: Int32;
+begin
+  for i := 0 to System.Pred(digest.GetDigestSize()) do
+  begin
+    digest.Update(Byte(i));
+  end;
+
+  digest.BlockUpdate(FTestBytes, 0, System.Length(FTestBytes));
+
+  Result := TDigestUtilities.DoFinal(digest);
+end;
+
+procedure TTestDigestUtilities.CheckXofDigestAlgorithm(const name: String;
+  const digest: IDigest);
+var
+  hash1, hash2: TCryptoLibByteArray;
+  i: Int32;
+begin
+  for i := 1 to 100 do
+  begin
+    hash1 := MakeTestXofDigest(digest, i);
+    hash2 := MakeTestXofDigest(TDigestUtilities.GetDigest(name), i);
+
+    if not TArrayUtils.AreEqual(hash1, hash2) then
+    begin
+      Fail(Format
+        ('%s (%d) at Index %d CheckXofDigestAlgorithm Operation Failed',
+        [name, (digest as IXOF).XOFSizeInBits, i]));
+    end;
+  end;
+end;
+
+procedure TTestDigestUtilities.CheckPlainDigestAlgorithm(const name: String;
+  const digest: IDigest);
+var
+  hash1, hash2: TCryptoLibByteArray;
+begin
+  hash1 := MakeTestPlainDigest(digest);
+  hash2 := MakeTestPlainDigest(TDigestUtilities.GetDigest(name));
+
+  if not TArrayUtils.AreEqual(hash1, hash2) then
+  begin
+    Fail(Format('%s CheckPlainDigestAlgorithm Operation Failed', [name]));
+  end;
+end;
+
+procedure TTestDigestUtilities.TestAlgorithms;
+begin
+  // plain digest test
+  CheckPlainDigestAlgorithm('MD2',
+    TDigest.Create(THashFactory.TCrypto.CreateMD2()) as IDigest);
+
+  CheckPlainDigestAlgorithm('MD4',
+    TDigest.Create(THashFactory.TCrypto.CreateMD4()) as IDigest);
+
+  CheckPlainDigestAlgorithm('MD5',
+    TDigest.Create(THashFactory.TCrypto.CreateMD5()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA-1',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA1()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA-224',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA2_224()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA-256',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA2_256()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA-384',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA2_384()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA-512',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA2_512()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA-512/224',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA2_512_224()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA-512/256',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA2_512_256()) as IDigest);
+
+  CheckPlainDigestAlgorithm('KECCAK224',
+    TDigest.Create(THashFactory.TCrypto.CreateKeccak_224()) as IDigest);
+
+  CheckPlainDigestAlgorithm('KECCAK256',
+    TDigest.Create(THashFactory.TCrypto.CreateKeccak_256()) as IDigest);
+
+  CheckPlainDigestAlgorithm('KECCAK288',
+    TDigest.Create(THashFactory.TCrypto.CreateKeccak_288()) as IDigest);
+
+  CheckPlainDigestAlgorithm('KECCAK384',
+    TDigest.Create(THashFactory.TCrypto.CreateKeccak_384()) as IDigest);
+
+  CheckPlainDigestAlgorithm('KECCAK512',
+    TDigest.Create(THashFactory.TCrypto.CreateKeccak_512()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA3-224',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA3_224()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA3-256',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA3_256()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA3-384',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA3_384()) as IDigest);
+
+  CheckPlainDigestAlgorithm('SHA3-512',
+    TDigest.Create(THashFactory.TCrypto.CreateSHA3_512()) as IDigest);
+
+  CheckXofDigestAlgorithm('SHAKE128',
+    TDigest.Create(THashFactory.TCrypto.CreateShake_128(128)) as IDigest);
+
+  CheckXofDigestAlgorithm('SHAKE256',
+    TDigest.Create(THashFactory.TCrypto.CreateShake_256(256)) as IDigest);
+
+  CheckPlainDigestAlgorithm('RIPEMD128',
+    TDigest.Create(THashFactory.TCrypto.CreateRIPEMD128()) as IDigest);
+
+  CheckPlainDigestAlgorithm('RIPEMD160',
+    TDigest.Create(THashFactory.TCrypto.CreateRIPEMD160()) as IDigest);
+
+  CheckPlainDigestAlgorithm('RIPEMD256',
+    TDigest.Create(THashFactory.TCrypto.CreateRIPEMD256()) as IDigest);
+
+  CheckPlainDigestAlgorithm('RIPEMD320',
+    TDigest.Create(THashFactory.TCrypto.CreateRIPEMD320()) as IDigest);
+
+  CheckPlainDigestAlgorithm('GOST3411',
+    TDigest.Create(THashFactory.TCrypto.CreateGost()) as IDigest);
+
+  CheckPlainDigestAlgorithm('BLAKE2B-160',
+    TDigest.Create(THashFactory.TCrypto.CreateBlake2B_160()) as IDigest);
+
+  CheckPlainDigestAlgorithm('BLAKE2B-256',
+    TDigest.Create(THashFactory.TCrypto.CreateBlake2B_256()) as IDigest);
+
+  CheckPlainDigestAlgorithm('BLAKE2B-384',
+    TDigest.Create(THashFactory.TCrypto.CreateBlake2B_384()) as IDigest);
+
+  CheckPlainDigestAlgorithm('BLAKE2B-512',
+    TDigest.Create(THashFactory.TCrypto.CreateBlake2B_512()) as IDigest);
+
+  CheckPlainDigestAlgorithm('BLAKE2S-128',
+    TDigest.Create(THashFactory.TCrypto.CreateBlake2S_128()) as IDigest);
+
+  CheckPlainDigestAlgorithm('BLAKE2S-160',
+    TDigest.Create(THashFactory.TCrypto.CreateBlake2S_160()) as IDigest);
+
+  CheckPlainDigestAlgorithm('BLAKE2S-224',
+    TDigest.Create(THashFactory.TCrypto.CreateBlake2S_224()) as IDigest);
+
+  CheckPlainDigestAlgorithm('BLAKE2S-256',
+    TDigest.Create(THashFactory.TCrypto.CreateBlake2S_256()) as IDigest);
+
+  CheckPlainDigestAlgorithm('GOST3411-2012-256',
+    TDigest.Create(THashFactory.TCrypto.CreateGOST3411_2012_256()) as IDigest);
+
+  CheckPlainDigestAlgorithm('GOST3411-2012-512',
+    TDigest.Create(THashFactory.TCrypto.CreateGOST3411_2012_512()) as IDigest);
+
+  CheckPlainDigestAlgorithm('Tiger',
+    TDigest.Create(THashFactory.TCrypto.CreateTiger_3_192()) as IDigest);
+
+  CheckPlainDigestAlgorithm('Whirlpool',
+    TDigest.Create(THashFactory.TCrypto.CreateWhirlPool()) as IDigest);
+
+  // Xof test
+  CheckXofDigestAlgorithm('SHAKE128',
+    TDigest.Create(THashFactory.TCrypto.CreateShake_128(128)) as IDigest);
+
+  CheckXofDigestAlgorithm('SHAKE256',
+    TDigest.Create(THashFactory.TCrypto.CreateShake_256(256)) as IDigest);
+end;
+
+initialization
+
+// Register any test cases with the test runner
+
+{$IFDEF FPC}
+  RegisterTest(TTestDigestUtilities);
+{$ELSE}
+  RegisterTest(TTestDigestUtilities.Suite);
+{$ENDIF FPC}
+
+end.

+ 8 - 0
CryptoLib.Tests/src/Utils/ClpShortenedDigest.pas

@@ -86,6 +86,8 @@ type
 
 
     property AlgorithmName: String read GetAlgorithmName;
     property AlgorithmName: String read GetAlgorithmName;
 
 
+    function Clone(): IDigest;
+
   end;
   end;
 
 
 implementation
 implementation
@@ -165,4 +167,10 @@ begin
   FBaseDigest.Reset();
   FBaseDigest.Reset();
 end;
 end;
 
 
+function TShortenedDigest.Clone(): IDigest;
+begin
+  result := (TShortenedDigest.Create(FBaseDigest.Clone(), FLength)
+    as IShortenedDigest) as IDigest;
+end;
+
 end.
 end.

+ 32 - 4
CryptoLib/src/Crypto/Digests/ClpDigest.pas

@@ -21,7 +21,9 @@ unit ClpDigest;
 interface
 interface
 
 
 uses
 uses
+  SysUtils,
   HlpIHash,
   HlpIHash,
+  HlpIHashInfo,
   ClpIDigest,
   ClpIDigest,
   ClpCryptoLibTypes;
   ClpCryptoLibTypes;
 
 
@@ -44,7 +46,7 @@ type
     function DoFinal: TCryptoLibByteArray; overload;
     function DoFinal: TCryptoLibByteArray; overload;
 
 
   public
   public
-    constructor Create(const hash: IHash);
+    constructor Create(const hash: IHash; doInitialize: Boolean = True);
 
 
     /// <summary>
     /// <summary>
     /// Gets the Underlying <b>IHash</b> Instance
     /// Gets the Underlying <b>IHash</b> Instance
@@ -98,6 +100,11 @@ type
     /// </summary>
     /// </summary>
     procedure Reset();
     procedure Reset();
 
 
+    /// <summary>
+    /// Clone the digest instance
+    /// </summary>
+    function Clone(): IDigest;
+
     /// <summary>
     /// <summary>
     /// the algorithm name
     /// the algorithm name
     /// </summary>
     /// </summary>
@@ -151,20 +158,35 @@ begin
   FHash.TransformBytes(input, inOff, len);
   FHash.TransformBytes(input, inOff, len);
 end;
 end;
 
 
-constructor TDigest.Create(const hash: IHash);
+constructor TDigest.Create(const hash: IHash; doInitialize: Boolean);
 begin
 begin
   Inherited Create();
   Inherited Create();
   FHash := hash;
   FHash := hash;
-  FHash.Initialize;
+  if doInitialize then
+  begin
+    FHash.Initialize;
+  end;
 end;
 end;
 
 
 function TDigest.DoFinal(const output: TCryptoLibByteArray;
 function TDigest.DoFinal(const output: TCryptoLibByteArray;
   outOff: Int32): Int32;
   outOff: Int32): Int32;
 var
 var
   buf: TCryptoLibByteArray;
   buf: TCryptoLibByteArray;
+  Limit, LXOFSizeInBits: Int32;
 begin
 begin
 
 
-  if (System.Length(output) - outOff) < GetDigestSize then
+  if Supports(FHash, IXOF) then
+  begin
+    LXOFSizeInBits := (System.Length(output) - outOff) * 8;
+    (FHash as IXOF).XOFSizeInBits := LXOFSizeInBits;
+    Limit := LXOFSizeInBits shr 3;
+  end
+  else
+  begin
+    Limit := GetDigestSize;
+  end;
+
+  if (System.Length(output) - outOff) < Limit then
   begin
   begin
     raise EDataLengthCryptoLibException.CreateRes(@SOutputBufferTooShort);
     raise EDataLengthCryptoLibException.CreateRes(@SOutputBufferTooShort);
   end
   end
@@ -174,6 +196,7 @@ begin
     System.Move(buf[0], output[outOff], System.Length(buf) *
     System.Move(buf[0], output[outOff], System.Length(buf) *
       System.SizeOf(Byte));
       System.SizeOf(Byte));
   end;
   end;
+
   result := System.Length(buf);
   result := System.Length(buf);
 end;
 end;
 
 
@@ -187,4 +210,9 @@ begin
   FHash.TransformUntyped(input, System.SizeOf(Byte));
   FHash.TransformUntyped(input, System.SizeOf(Byte));
 end;
 end;
 
 
+function TDigest.Clone(): IDigest;
+begin
+  result := TDigest.Create(FHash.Clone(), False);
+end;
+
 end.
 end.

+ 5 - 0
CryptoLib/src/Interfaces/ClpIDigest.pas

@@ -88,6 +88,11 @@ type
     /// </summary>
     /// </summary>
     procedure Reset();
     procedure Reset();
 
 
+    /// <summary>
+    /// Clone the digest instance
+    /// </summary>
+    function Clone(): IDigest;
+
   end;
   end;
 
 
 implementation
 implementation

+ 14 - 2
CryptoLib/src/Security/ClpDigestUtilities.pas

@@ -58,8 +58,8 @@ type
       GOST3411_2012_256, GOST3411_2012_512, KECCAK_224, KECCAK_256, KECCAK_288,
       GOST3411_2012_256, GOST3411_2012_512, KECCAK_224, KECCAK_256, KECCAK_288,
       KECCAK_384, KECCAK_512, MD2, MD4, MD5, NONE, RIPEMD128, RIPEMD160,
       KECCAK_384, KECCAK_512, MD2, MD4, MD5, NONE, RIPEMD128, RIPEMD160,
       RIPEMD256, RIPEMD320, SHA_1, SHA_224, SHA_256, SHA_384, SHA_512,
       RIPEMD256, RIPEMD320, SHA_1, SHA_224, SHA_256, SHA_384, SHA_512,
-      SHA_512_224, SHA_512_256, SHA3_224, SHA3_256, SHA3_384, SHA3_512, TIGER,
-      WHIRLPOOL);
+      SHA_512_224, SHA_512_256, SHA3_224, SHA3_256, SHA3_384, SHA3_512,
+      SHAKE128, SHAKE256, TIGER, WHIRLPOOL);
 {$SCOPEDENUMS OFF}
 {$SCOPEDENUMS OFF}
   class procedure Boot(); static;
   class procedure Boot(); static;
   class constructor CreateDigestUtilities();
   class constructor CreateDigestUtilities();
@@ -343,6 +343,18 @@ begin
         Exit;
         Exit;
       end;
       end;
 
 
+    TDigestAlgorithm.SHAKE128:
+      begin
+        result := TDigest.Create(THashFactory.TCrypto.CreateShake_128(128));
+        Exit;
+      end;
+
+    TDigestAlgorithm.SHAKE256:
+      begin
+        result := TDigest.Create(THashFactory.TCrypto.CreateShake_256(256));
+        Exit;
+      end;
+
     TDigestAlgorithm.TIGER:
     TDigestAlgorithm.TIGER:
       begin
       begin
         result := TDigest.Create(THashFactory.TCrypto.CreateTiger_3_192);
         result := TDigest.Create(THashFactory.TCrypto.CreateTiger_3_192);