Browse Source

add support for Salsa20, XSalsa20 and ChaCha stream ciphers.

Ugochukwu Mmaduekwe 6 years ago
parent
commit
fecc5553ea
28 changed files with 2562 additions and 35 deletions
  1. 9 0
      CryptoLib.Samples/Delphi.Samples/UsageSamples.dpr
  2. 14 1
      CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.TestInsight.dpr
  3. 14 1
      CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr
  4. 17 1
      CryptoLib.Tests/FreePascal.Tests/CryptoLib.Tests.lpi
  5. 4 0
      CryptoLib.Tests/FreePascal.Tests/CryptoLib.lpr
  6. 17 1
      CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.Tests.lpi
  7. 4 0
      CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpr
  8. 383 0
      CryptoLib.Tests/src/Crypto/ChaChaTests.pas
  9. 376 0
      CryptoLib.Tests/src/Crypto/Salsa20Tests.pas
  10. 243 0
      CryptoLib.Tests/src/Crypto/StreamCipherResetTests.pas
  11. 162 0
      CryptoLib.Tests/src/Crypto/XSalsa20Tests.pas
  12. 1 1
      CryptoLib/src/Crypto/ClpBufferedCipherBase.pas
  13. 195 0
      CryptoLib/src/Crypto/ClpBufferedStreamCipher.pas
  14. 263 0
      CryptoLib/src/Crypto/Engines/ClpChaChaEngine.pas
  15. 502 0
      CryptoLib/src/Crypto/Engines/ClpSalsa20Engine.pas
  16. 114 0
      CryptoLib/src/Crypto/Engines/ClpXSalsa20Engine.pas
  17. 36 0
      CryptoLib/src/Interfaces/ClpIBufferedStreamCipher.pas
  18. 36 0
      CryptoLib/src/Interfaces/ClpIChaChaEngine.pas
  19. 36 0
      CryptoLib/src/Interfaces/ClpISalsa20Engine.pas
  20. 0 10
      CryptoLib/src/Interfaces/ClpISignersEncodings.pas
  21. 30 14
      CryptoLib/src/Interfaces/ClpIStreamCipher.pas
  22. 36 0
      CryptoLib/src/Interfaces/ClpIXSalsa20Engine.pas
  23. 35 3
      CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.lpk
  24. 4 1
      CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.pas
  25. 26 1
      CryptoLib/src/Security/ClpCipherUtilities.pas
  26. 3 1
      CryptoLib/src/Security/ClpGeneratorUtilities.pas
  27. 1 0
      CryptoLib/src/Security/ClpParameterUtilities.pas
  28. 1 0
      CryptoLib/src/Utils/ClpCryptoLibTypes.pas

+ 9 - 0
CryptoLib.Samples/Delphi.Samples/UsageSamples.dpr

@@ -273,6 +273,15 @@ uses
   ClpECCurveConstants in '..\..\CryptoLib\src\Math\EC\ClpECCurveConstants.pas',
   ClpECCurveConstants in '..\..\CryptoLib\src\Math\EC\ClpECCurveConstants.pas',
   ClpAsn1Objects in '..\..\CryptoLib\src\Asn1\ClpAsn1Objects.pas',
   ClpAsn1Objects in '..\..\CryptoLib\src\Asn1\ClpAsn1Objects.pas',
   ClpSignersEncodings in '..\..\CryptoLib\src\Crypto\Signers\SignersEncodings\ClpSignersEncodings.pas',
   ClpSignersEncodings in '..\..\CryptoLib\src\Crypto\Signers\SignersEncodings\ClpSignersEncodings.pas',
+  ClpIStreamCipher in '..\..\CryptoLib\src\Interfaces\ClpIStreamCipher.pas',
+  ClpBufferedStreamCipher in '..\..\CryptoLib\src\Crypto\ClpBufferedStreamCipher.pas',
+  ClpIBufferedStreamCipher in '..\..\CryptoLib\src\Interfaces\ClpIBufferedStreamCipher.pas',
+  ClpSalsa20Engine in '..\..\CryptoLib\src\Crypto\Engines\ClpSalsa20Engine.pas',
+  ClpISalsa20Engine in '..\..\CryptoLib\src\Interfaces\ClpISalsa20Engine.pas',
+  ClpIXSalsa20Engine in '..\..\CryptoLib\src\Interfaces\ClpIXSalsa20Engine.pas',
+  ClpXSalsa20Engine in '..\..\CryptoLib\src\Crypto\Engines\ClpXSalsa20Engine.pas',
+  ClpIChaChaEngine in '..\..\CryptoLib\src\Interfaces\ClpIChaChaEngine.pas',
+  ClpChaChaEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpChaChaEngine.pas',
   UsageExamples in '..\src\UsageExamples.pas';
   UsageExamples in '..\src\UsageExamples.pas';
 
 
 begin
 begin

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

@@ -283,6 +283,15 @@ uses
   ClpECCurveConstants in '..\..\CryptoLib\src\Math\EC\ClpECCurveConstants.pas',
   ClpECCurveConstants in '..\..\CryptoLib\src\Math\EC\ClpECCurveConstants.pas',
   ClpAsn1Objects in '..\..\CryptoLib\src\Asn1\ClpAsn1Objects.pas',
   ClpAsn1Objects in '..\..\CryptoLib\src\Asn1\ClpAsn1Objects.pas',
   ClpSignersEncodings in '..\..\CryptoLib\src\Crypto\Signers\SignersEncodings\ClpSignersEncodings.pas',
   ClpSignersEncodings in '..\..\CryptoLib\src\Crypto\Signers\SignersEncodings\ClpSignersEncodings.pas',
+  ClpIStreamCipher in '..\..\CryptoLib\src\Interfaces\ClpIStreamCipher.pas',
+  ClpBufferedStreamCipher in '..\..\CryptoLib\src\Crypto\ClpBufferedStreamCipher.pas',
+  ClpIBufferedStreamCipher in '..\..\CryptoLib\src\Interfaces\ClpIBufferedStreamCipher.pas',
+  ClpSalsa20Engine in '..\..\CryptoLib\src\Crypto\Engines\ClpSalsa20Engine.pas',
+  ClpISalsa20Engine in '..\..\CryptoLib\src\Interfaces\ClpISalsa20Engine.pas',
+  ClpIXSalsa20Engine in '..\..\CryptoLib\src\Interfaces\ClpIXSalsa20Engine.pas',
+  ClpXSalsa20Engine in '..\..\CryptoLib\src\Crypto\Engines\ClpXSalsa20Engine.pas',
+  ClpIChaChaEngine in '..\..\CryptoLib\src\Interfaces\ClpIChaChaEngine.pas',
+  ClpChaChaEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpChaChaEngine.pas',
   ClpFixedSecureRandom in '..\src\Utils\ClpFixedSecureRandom.pas',
   ClpFixedSecureRandom in '..\src\Utils\ClpFixedSecureRandom.pas',
   ClpIFixedSecureRandom in '..\src\Utils\ClpIFixedSecureRandom.pas',
   ClpIFixedSecureRandom in '..\src\Utils\ClpIFixedSecureRandom.pas',
   BlowfishTestVectors in '..\src\Crypto\BlowfishTestVectors.pas',
   BlowfishTestVectors in '..\src\Crypto\BlowfishTestVectors.pas',
@@ -331,7 +340,11 @@ uses
   StringTests in '..\src\Asn1\StringTests.pas',
   StringTests in '..\src\Asn1\StringTests.pas',
   ParsingTests in '..\src\Asn1\ParsingTests.pas',
   ParsingTests in '..\src\Asn1\ParsingTests.pas',
   ParseTests in '..\src\Asn1\ParseTests.pas',
   ParseTests in '..\src\Asn1\ParseTests.pas',
-  EnumeratedTests in '..\src\Asn1\EnumeratedTests.pas';
+  EnumeratedTests in '..\src\Asn1\EnumeratedTests.pas',
+  Salsa20Tests in '..\src\Crypto\Salsa20Tests.pas',
+  ChaChaTests in '..\src\Crypto\ChaChaTests.pas',
+  XSalsa20Tests in '..\src\Crypto\XSalsa20Tests.pas',
+  StreamCipherResetTests in '..\src\Crypto\StreamCipherResetTests.pas';
 
 
 begin
 begin
 
 

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

@@ -286,6 +286,15 @@ uses
   ClpECCurveConstants in '..\..\CryptoLib\src\Math\EC\ClpECCurveConstants.pas',
   ClpECCurveConstants in '..\..\CryptoLib\src\Math\EC\ClpECCurveConstants.pas',
   ClpAsn1Objects in '..\..\CryptoLib\src\Asn1\ClpAsn1Objects.pas',
   ClpAsn1Objects in '..\..\CryptoLib\src\Asn1\ClpAsn1Objects.pas',
   ClpSignersEncodings in '..\..\CryptoLib\src\Crypto\Signers\SignersEncodings\ClpSignersEncodings.pas',
   ClpSignersEncodings in '..\..\CryptoLib\src\Crypto\Signers\SignersEncodings\ClpSignersEncodings.pas',
+  ClpIStreamCipher in '..\..\CryptoLib\src\Interfaces\ClpIStreamCipher.pas',
+  ClpBufferedStreamCipher in '..\..\CryptoLib\src\Crypto\ClpBufferedStreamCipher.pas',
+  ClpIBufferedStreamCipher in '..\..\CryptoLib\src\Interfaces\ClpIBufferedStreamCipher.pas',
+  ClpSalsa20Engine in '..\..\CryptoLib\src\Crypto\Engines\ClpSalsa20Engine.pas',
+  ClpISalsa20Engine in '..\..\CryptoLib\src\Interfaces\ClpISalsa20Engine.pas',
+  ClpIXSalsa20Engine in '..\..\CryptoLib\src\Interfaces\ClpIXSalsa20Engine.pas',
+  ClpXSalsa20Engine in '..\..\CryptoLib\src\Crypto\Engines\ClpXSalsa20Engine.pas',
+  ClpIChaChaEngine in '..\..\CryptoLib\src\Interfaces\ClpIChaChaEngine.pas',
+  ClpChaChaEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpChaChaEngine.pas',
   ClpFixedSecureRandom in '..\src\Utils\ClpFixedSecureRandom.pas',
   ClpFixedSecureRandom in '..\src\Utils\ClpFixedSecureRandom.pas',
   ClpIFixedSecureRandom in '..\src\Utils\ClpIFixedSecureRandom.pas',
   ClpIFixedSecureRandom in '..\src\Utils\ClpIFixedSecureRandom.pas',
   BlowfishTestVectors in '..\src\Crypto\BlowfishTestVectors.pas',
   BlowfishTestVectors in '..\src\Crypto\BlowfishTestVectors.pas',
@@ -334,7 +343,11 @@ uses
   StringTests in '..\src\Asn1\StringTests.pas',
   StringTests in '..\src\Asn1\StringTests.pas',
   ParsingTests in '..\src\Asn1\ParsingTests.pas',
   ParsingTests in '..\src\Asn1\ParsingTests.pas',
   ParseTests in '..\src\Asn1\ParseTests.pas',
   ParseTests in '..\src\Asn1\ParseTests.pas',
-  EnumeratedTests in '..\src\Asn1\EnumeratedTests.pas';
+  EnumeratedTests in '..\src\Asn1\EnumeratedTests.pas',
+  Salsa20Tests in '..\src\Crypto\Salsa20Tests.pas',
+  ChaChaTests in '..\src\Crypto\ChaChaTests.pas',
+  XSalsa20Tests in '..\src\Crypto\XSalsa20Tests.pas',
+  StreamCipherResetTests in '..\src\Crypto\StreamCipherResetTests.pas';
 
 
 begin
 begin
 
 

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

@@ -35,7 +35,7 @@
         <PackageName Value="FCL"/>
         <PackageName Value="FCL"/>
       </Item4>
       </Item4>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="50">
+    <Units Count="54">
       <Unit0>
       <Unit0>
         <Filename Value="CryptoLib.lpr"/>
         <Filename Value="CryptoLib.lpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -237,6 +237,22 @@
         <Filename Value="..\src\Crypto\SPECKTests.pas"/>
         <Filename Value="..\src\Crypto\SPECKTests.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit49>
       </Unit49>
+      <Unit50>
+        <Filename Value="..\src\Crypto\XSalsa20Tests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit50>
+      <Unit51>
+        <Filename Value="..\src\Crypto\Salsa20Tests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit51>
+      <Unit52>
+        <Filename Value="..\src\Crypto\StreamCipherResetTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit52>
+      <Unit53>
+        <Filename Value="..\src\Crypto\ChaChaTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit53>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>

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

@@ -53,6 +53,10 @@ uses
   PaddingTests,
   PaddingTests,
   DSATests,
   DSATests,
   DeterministicDsaTests,
   DeterministicDsaTests,
+  Salsa20Tests,
+  XSalsa20Tests,
+  ChaChaTests,
+  StreamCipherResetTests,
   ClpFixedSecureRandom,
   ClpFixedSecureRandom,
   ClpIFixedSecureRandom;
   ClpIFixedSecureRandom;
 
 

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

@@ -30,7 +30,7 @@
         <PackageName Value="FCL"/>
         <PackageName Value="FCL"/>
       </Item2>
       </Item2>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="50">
+    <Units Count="54">
       <Unit0>
       <Unit0>
         <Filename Value="CryptoLibConsole.lpr"/>
         <Filename Value="CryptoLibConsole.lpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -231,6 +231,22 @@
         <Filename Value="..\src\Crypto\SpeckTestVectors.pas"/>
         <Filename Value="..\src\Crypto\SpeckTestVectors.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit49>
       </Unit49>
+      <Unit50>
+        <Filename Value="..\src\Crypto\XSalsa20Tests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit50>
+      <Unit51>
+        <Filename Value="..\src\Crypto\Salsa20Tests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit51>
+      <Unit52>
+        <Filename Value="..\src\Crypto\StreamCipherResetTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit52>
+      <Unit53>
+        <Filename Value="..\src\Crypto\ChaChaTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit53>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>

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

@@ -51,6 +51,10 @@ uses
   PaddingTests,
   PaddingTests,
   DSATests,
   DSATests,
   DeterministicDsaTests,
   DeterministicDsaTests,
+  Salsa20Tests,
+  XSalsa20Tests,
+  ChaChaTests,
+  StreamCipherResetTests,
   ClpFixedSecureRandom,
   ClpFixedSecureRandom,
   ClpIFixedSecureRandom;
   ClpIFixedSecureRandom;
 
 

+ 383 - 0
CryptoLib.Tests/src/Crypto/ChaChaTests.pas

@@ -0,0 +1,383 @@
+{ *********************************************************************************** }
+{ *                              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 ChaChaTests;
+
+interface
+
+{$IFDEF FPC}
+{$MODE DELPHI}
+{$ENDIF FPC}
+
+uses
+  SysUtils,
+{$IFDEF FPC}
+  fpcunit,
+  testregistry,
+{$ELSE}
+  TestFramework,
+{$ENDIF FPC}
+  ClpChaChaEngine,
+  ClpIChaChaEngine,
+  ClpICipherParameters,
+  ClpKeyParameter,
+  ClpIKeyParameter,
+  ClpParametersWithIV,
+  ClpIParametersWithIV,
+  ClpEncoders,
+  ClpArrayUtils,
+  ClpCryptoLibTypes;
+
+type
+
+  TCryptoLibTestCase = class abstract(TTestCase)
+
+  end;
+
+type
+
+  /// <summary>
+  /// <para>
+  /// ChaCha Test
+  /// </para>
+  /// <para>
+  /// Test cases generated using ref version of ChaCha20 in
+  /// estreambench-20080905.
+  /// </para>
+  /// </summary>
+  TTestChaCha = class(TCryptoLibTestCase)
+  private
+  var
+    FZeroes: TCryptoLibByteArray;
+    FSet1v0_0, FSet1v0_192, FSet1v0_256, FSet1v0_448, FSet1v9_0, FSet1v9_192,
+      FSet1v9_256, FSet1v9_448, FSet6v0_0, FSet6v0_65472, FSet6v0_65536,
+      FSet6v1_0, FSet6v1_65472, FSet6v1_65536, FChaCha12_set1v0_0,
+      FChaCha12_set1v0_192, FChaCha12_set1v0_256, FChaCha12_set1v0_448,
+      FChaCha8_set1v0_0, FChaCha8_set1v0_192, FChaCha8_set1v0_256,
+      FChaCha8_set1v0_448: String;
+
+    procedure Mismatch(const name, expected: String;
+      found: TCryptoLibByteArray);
+    procedure DoChaChaTest1(rounds: Int32; const parameters: ICipherParameters;
+      const v0, v192, v256, v448: String);
+
+    procedure DoChaChaTest2(const parameters: ICipherParameters;
+      const v0, v65472, v65536: String);
+
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+  published
+
+    procedure TestDoChaChaTest1;
+    procedure TestDoChaChaTest2;
+    procedure TestReInitBug;
+
+  end;
+
+implementation
+
+{ TTestChaCha }
+
+procedure TTestChaCha.SetUp;
+begin
+  inherited;
+  FZeroes := THex.Decode('00000000000000000000000000000000' +
+    '00000000000000000000000000000000' + '00000000000000000000000000000000' +
+    '00000000000000000000000000000000');
+
+  FSet1v0_0 := 'FBB87FBB8395E05DAA3B1D683C422046' +
+    'F913985C2AD9B23CFC06C1D8D04FF213' + 'D44A7A7CDB84929F915420A8A3DC58BF' +
+    '0F7ECB4B1F167BB1A5E6153FDAF4493D';
+
+  FSet1v0_192 := 'D9485D55B8B82D792ED1EEA8E93E9BC1' +
+    'E2834AD0D9B11F3477F6E106A2F6A5F2' + 'EA8244D5B925B8050EAB038F58D4DF57' +
+    '7FAFD1B89359DAE508B2B10CBD6B488E';
+
+  FSet1v0_256 := '08661A35D6F02D3D9ACA8087F421F7C8' +
+    'A42579047D6955D937925BA21396DDD4' + '74B1FC4ACCDCAA33025B4BCE817A4FBF' +
+    '3E5D07D151D7E6FE04934ED466BA4779';
+
+  FSet1v0_448 := 'A7E16DD38BA48CCB130E5BE9740CE359' +
+    'D631E91600F85C8A5D0785A612D1D987' + '90780ACDDC26B69AB106CCF6D866411D' +
+    '10637483DBF08CC5591FD8B3C87A3AE0';
+
+  FSet1v9_0 := 'A276339F99316A913885A0A4BE870F06' +
+    '91E72B00F1B3F2239F714FE81E88E00C' + 'BBE52B4EBBE1EA15894E29658C4CB145' +
+    'E6F89EE4ABB045A78514482CE75AFB7C';
+
+  FSet1v9_192 := '0DFB9BD4F87F68DE54FBC1C6428FDEB0' +
+    '63E997BE8490C9B7A4694025D6EBA2B1' + '5FE429DB82A7CAE6AAB22918E8D00449' +
+    '6FB6291467B5AE81D4E85E81D8795EBB';
+
+  FSet1v9_256 := '546F5BB315E7F71A46E56D4580F90889' +
+    '639A2BA528F757CF3B048738BA141AF3' + 'B31607CB21561BAD94721048930364F4' +
+    'B1227CFEB7CDECBA881FB44903550E68';
+
+  FSet1v9_448 := '6F813586E76691305A0CF048C0D8586D' +
+    'C89460207D8B230CD172398AA33D19E9' + '2D24883C3A9B0BB7CD8C6B2668DB142E' +
+    '37A97948A7A01498A21110297984CD20';
+
+  FSet6v0_0 := '57459975BC46799394788DE80B928387' +
+    '862985A269B9E8E77801DE9D874B3F51' + 'AC4610B9F9BEE8CF8CACD8B5AD0BF17D' +
+    '3DDF23FD7424887EB3F81405BD498CC3';
+
+  FSet6v0_65472 := 'EF9AEC58ACE7DB427DF012B2B91A0C1E' +
+    '8E4759DCE9CDB00A2BD59207357BA06C' + 'E02D327C7719E83D6348A6104B081DB0' +
+    '3908E5186986AE41E3AE95298BB7B713';
+
+  FSet6v0_65536 := '17EF5FF454D85ABBBA280F3A94F1D26E' +
+    '950C7D5B05C4BB3A78326E0DC5731F83' + '84205C32DB867D1B476CE121A0D7074B' +
+    'AA7EE90525D15300F48EC0A6624BD0AF';
+
+  FSet6v1_0 := '92A2508E2C4084567195F2A1005E552B' +
+    '4874EC0504A9CD5E4DAF739AB553D2E7' + '83D79C5BA11E0653BEBB5C116651302E' +
+    '8D381CB728CA627B0B246E83942A2B99';
+
+  FSet6v1_65472 := 'E1974EC3063F7BD0CBA58B1CE34BC874' +
+    '67AAF5759B05EA46682A5D4306E5A76B' + 'D99A448DB8DE73AF97A73F5FBAE2C776' +
+    '35040464524CF14D7F08D4CE1220FD84';
+
+  FSet6v1_65536 := 'BE3436141CFD62D12FF7D852F80C1344' +
+    '81F152AD0235ECF8CA172C55CA8C031B' + '2E785D773A988CA8D4BDA6FAE0E493AA' +
+    '71DCCC4C894D1F106CAC62A9FC0A9607';
+
+  // ChaCha12
+  FChaCha12_set1v0_0 := '36CF0D56E9F7FBF287BC5460D95FBA94' +
+    'AA6CBF17D74E7C784DDCF7E0E882DDAE' + '3B5A58243EF32B79A04575A8E2C2B73D' +
+    'C64A52AA15B9F88305A8F0CA0B5A1A25';
+
+  FChaCha12_set1v0_192 := '83496792AB68FEC75ADB16D3044420A4' +
+    'A00A6E9ADC41C3A63DBBF317A8258C85' + 'A9BC08B4F76B413A4837324AEDF8BC2A' +
+    '67D53C9AB9E1C5BC5F379D48DF9AF730';
+
+  FChaCha12_set1v0_256 := 'BAA28ED593690FD760ADA07C95E3B888' +
+    '4B4B64E488CA7A2D9BDC262243AB9251' + '394C5037E255F8BCCDCD31306C508FFB' +
+    'C9E0161380F7911FCB137D46D9269250';
+
+  FChaCha12_set1v0_448 := 'B7ECFB6AE0B51915762FE1FD03A14D0C' +
+    '9E54DA5DC76EB16EBA5313BC535DE63D' + 'C72D7F9F1874E301E99C8531819F4E37' +
+    '75793F6A5D19C717FA5C78A39EB804A6';
+
+  // ChaCha8
+  FChaCha8_set1v0_0 := 'BEB1E81E0F747E43EE51922B3E87FB38' +
+    'D0163907B4ED49336032AB78B67C2457' + '9FE28F751BD3703E51D876C017FAA435' +
+    '89E63593E03355A7D57B2366F30047C5';
+
+  FChaCha8_set1v0_192 := '33B8B7CA8F8E89F0095ACE75A379C651' +
+    'FD6BDD55703C90672E44C6BAB6AACDD8' + '7C976A87FD264B906E749429284134C2' +
+    '38E3B88CF74A68245B860D119A8BDF43';
+
+  FChaCha8_set1v0_256 := 'F7CA95BF08688BD3BE8A27724210F9DC' +
+    '16F32AF974FBFB09E9F757C577A245AB' + 'F35F824B70A4C02CB4A8D7191FA8A5AD' +
+    '6A84568743844703D353B7F00A8601F4';
+
+  FChaCha8_set1v0_448 := '7B4117E8BFFD595CD8482270B08920FB' +
+    'C9B97794E1809E07BB271BF07C861003' + '4C38DBA6ECA04E5474F399A284CBF6E2' +
+    '7F70142E604D0977797DE5B58B6B25E0';
+
+end;
+
+procedure TTestChaCha.TearDown;
+begin
+  inherited;
+
+end;
+
+procedure TTestChaCha.Mismatch(const name, expected: String;
+  found: TCryptoLibByteArray);
+begin
+  Fail(Format('Mismatch on %s, Expected %s, Found %s.',
+    [name, expected, THex.Encode(found)]));
+end;
+
+procedure TTestChaCha.DoChaChaTest1(rounds: Int32;
+  const parameters: ICipherParameters; const v0, v192, v256, v448: String);
+var
+  chacha: IChaChaEngine;
+  buf: TCryptoLibByteArray;
+  i: Int32;
+begin
+  chacha := TChaChaEngine.Create(rounds);
+  chacha.Init(true, parameters);
+  System.SetLength(buf, 64);
+  i := 0;
+  while i <> 7 do
+  begin
+    chacha.ProcessBytes(FZeroes, 0, 64, buf, 0);
+    case i of
+      0:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v0))) then
+          begin
+            Mismatch(Format('v0/%d', [rounds]), v0, buf);
+          end;
+        end;
+      3:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v192))) then
+          begin
+            Mismatch(Format('v192/%d', [rounds]), v192, buf);
+          end;
+        end;
+      4:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v256))) then
+          begin
+            Mismatch(Format('v256/%d', [rounds]), v256, buf);
+          end;
+        end
+    else
+      begin
+        // ignore
+      end;
+    end;
+    System.Inc(i);
+  end;
+
+  i := 0;
+  while i <> 64 do
+  begin
+    buf[i] := chacha.ReturnByte(FZeroes[i]);
+    System.Inc(i);
+  end;
+
+  if not(TArrayUtils.AreEqual(buf, THex.Decode(v448))) then
+  begin
+    Mismatch(Format('v448/%d', [rounds]), v448, buf);
+  end;
+end;
+
+procedure TTestChaCha.DoChaChaTest2(const parameters: ICipherParameters;
+  const v0, v65472, v65536: String);
+var
+  chacha: IChaChaEngine;
+  buf: TCryptoLibByteArray;
+  i: Int32;
+begin
+  chacha := TChaChaEngine.Create();
+  chacha.Init(true, parameters);
+  System.SetLength(buf, 64);
+  i := 0;
+  while i <> 1025 do
+  begin
+    chacha.ProcessBytes(FZeroes, 0, 64, buf, 0);
+    case i of
+      0:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v0))) then
+          begin
+            Mismatch('v0', v0, buf);
+          end;
+        end;
+      1023:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v65472))) then
+          begin
+            Mismatch('v65472', v65472, buf);
+          end;
+        end;
+      1024:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v65536))) then
+          begin
+            Mismatch('v65536', v65536, buf);
+          end;
+        end
+    else
+      begin
+        // ignore
+      end;
+    end;
+    System.Inc(i);
+  end;
+
+end;
+
+procedure TTestChaCha.TestDoChaChaTest1;
+begin
+  DoChaChaTest1(20, TParametersWithIV.Create
+    (TKeyParameter.Create(THex.Decode('80000000000000000000000000000000'))
+    as IKeyParameter, THex.Decode('0000000000000000')) as IParametersWithIV,
+    FSet1v0_0, FSet1v0_192, FSet1v0_256, FSet1v0_448);
+  DoChaChaTest1(20, TParametersWithIV.Create
+    (TKeyParameter.Create(THex.Decode('00400000000000000000000000000000'))
+    as IKeyParameter, THex.Decode('0000000000000000')) as IParametersWithIV,
+    FSet1v9_0, FSet1v9_192, FSet1v9_256, FSet1v9_448);
+
+  DoChaChaTest1(12, TParametersWithIV.Create
+    (TKeyParameter.Create(THex.Decode('80000000000000000000000000000000'))
+    as IKeyParameter, THex.Decode('0000000000000000')), FChaCha12_set1v0_0,
+    FChaCha12_set1v0_192, FChaCha12_set1v0_256, FChaCha12_set1v0_448);
+  DoChaChaTest1(8, TParametersWithIV.Create
+    (TKeyParameter.Create(THex.Decode('80000000000000000000000000000000'))
+    as IKeyParameter, THex.Decode('0000000000000000')) as IParametersWithIV,
+    FChaCha8_set1v0_0, FChaCha8_set1v0_192, FChaCha8_set1v0_256,
+    FChaCha8_set1v0_448);
+
+end;
+
+procedure TTestChaCha.TestDoChaChaTest2;
+begin
+  DoChaChaTest2(TParametersWithIV.Create(TKeyParameter.Create
+    (THex.Decode
+    ('0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D'))
+    as IKeyParameter, THex.Decode('0D74DB42A91077DE')) as IParametersWithIV,
+    FSet6v0_0, FSet6v0_65472, FSet6v0_65536);
+  DoChaChaTest2(TParametersWithIV.Create(TKeyParameter.Create
+    (THex.Decode
+    ('0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12'))
+    as IKeyParameter, THex.Decode('167DE44BB21980E7')) as IParametersWithIV,
+    FSet6v1_0, FSet6v1_65472, FSet6v1_65536);
+end;
+
+procedure TTestChaCha.TestReInitBug;
+var
+  key: IKeyParameter;
+  parameters: IParametersWithIV;
+  chacha: IChaChaEngine;
+begin
+  key := TKeyParameter.Create(THex.Decode('80000000000000000000000000000000'));
+  parameters := TParametersWithIV.Create(key, THex.Decode('0000000000000000'));
+
+  chacha := TChaChaEngine.Create();
+
+  chacha.Init(true, parameters);
+  try
+    chacha.Init(true, key);
+    Fail('ChaCha should throw exception if no IV in Init');
+
+  except
+    on e: EArgumentCryptoLibException do
+    begin
+      // expected
+    end;
+
+  end;
+end;
+
+initialization
+
+// Register any test cases with the test runner
+
+{$IFDEF FPC}
+  RegisterTest(TTestChaCha);
+{$ELSE}
+  RegisterTest(TTestChaCha.Suite);
+{$ENDIF FPC}
+
+end.

+ 376 - 0
CryptoLib.Tests/src/Crypto/Salsa20Tests.pas

@@ -0,0 +1,376 @@
+{ *********************************************************************************** }
+{ *                              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 Salsa20Tests;
+
+interface
+
+{$IFDEF FPC}
+{$MODE DELPHI}
+{$ENDIF FPC}
+
+uses
+  SysUtils,
+{$IFDEF FPC}
+  fpcunit,
+  testregistry,
+{$ELSE}
+  TestFramework,
+{$ENDIF FPC}
+  ClpSalsa20Engine,
+  ClpISalsa20Engine,
+  ClpICipherParameters,
+  ClpKeyParameter,
+  ClpIKeyParameter,
+  ClpParametersWithIV,
+  ClpIParametersWithIV,
+  ClpEncoders,
+  ClpArrayUtils,
+  ClpCryptoLibTypes;
+
+type
+
+  TCryptoLibTestCase = class abstract(TTestCase)
+
+  end;
+
+type
+
+  TTestSalsa20 = class(TCryptoLibTestCase)
+  private
+  var
+    FZeroes: TCryptoLibByteArray;
+    FSet1v0_0, FSet1v0_192, FSet1v0_256, FSet1v0_448, FSet1v9_0, FSet1v9_192,
+      FSet1v9_256, FSet1v9_448, FSet6v0_0, FSet6v0_65472, FSet6v0_65536,
+      FSet6v1_0, FSet6v1_65472, FSet6v1_65536, FSalsa12_set1v0_0,
+      FSalsa12_set1v0_192, FSalsa12_set1v0_256, FSalsa12_set1v0_448,
+      FSalsa8_set1v0_0, FSalsa8_set1v0_192, FSalsa8_set1v0_256,
+      FSalsa8_set1v0_448: String;
+
+    procedure Mismatch(const name, expected: String;
+      found: TCryptoLibByteArray);
+    procedure DoSalsa20Test1(rounds: Int32; const parameters: ICipherParameters;
+      const v0, v192, v256, v448: String);
+
+    procedure DoSalsa20Test2(const parameters: ICipherParameters;
+      const v0, v65472, v65536: String);
+
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+  published
+
+    procedure TestSalsa20Test1;
+    procedure TestSalsa20Test2;
+    procedure TestReInitBug;
+
+  end;
+
+implementation
+
+{ TTestSalsa20 }
+
+procedure TTestSalsa20.SetUp;
+begin
+  inherited;
+  FZeroes := THex.Decode('00000000000000000000000000000000' +
+    '00000000000000000000000000000000' + '00000000000000000000000000000000' +
+    '00000000000000000000000000000000');
+
+  FSet1v0_0 := '4DFA5E481DA23EA09A31022050859936' +
+    'DA52FCEE218005164F267CB65F5CFD7F' + '2B4F97E0FF16924A52DF269515110A07' +
+    'F9E460BC65EF95DA58F740B7D1DBB0AA';
+
+  FSet1v0_192 := 'DA9C1581F429E0A00F7D67E23B730676' +
+    '783B262E8EB43A25F55FB90B3E753AEF' + '8C6713EC66C51881111593CCB3E8CB8F' +
+    '8DE124080501EEEB389C4BCB6977CF95';
+
+  FSet1v0_256 := '7D5789631EB4554400E1E025935DFA7B' +
+    '3E9039D61BDC58A8697D36815BF1985C' + 'EFDF7AE112E5BB81E37ECF0616CE7147' +
+    'FC08A93A367E08631F23C03B00A8DA2F';
+
+  FSet1v0_448 := 'B375703739DACED4DD4059FD71C3C47F' +
+    'C2F9939670FAD4A46066ADCC6A564578' + '3308B90FFB72BE04A6B147CBE38CC0C3' +
+    'B9267C296A92A7C69873F9F263BE9703';
+
+  FSet1v9_0 := '0471076057830FB99202291177FBFE5D' +
+    '38C888944DF8917CAB82788B91B53D1C' + 'FB06D07A304B18BB763F888A61BB6B75' +
+    '5CD58BEC9C4CFB7569CB91862E79C459';
+
+  FSet1v9_192 := 'D1D7E97556426E6CFC21312AE3811425' +
+    '9E5A6FB10DACBD88E4354B0472556935' + '2B6DA5ACAFACD5E266F9575C2ED8E6F2' +
+    'EFE4B4D36114C3A623DD49F4794F865B';
+
+  FSet1v9_256 := 'AF06FAA82C73291231E1BD916A773DE1' +
+    '52FD2126C40A10C3A6EB40F22834B8CC' + '68BD5C6DBD7FC1EC8F34165C517C0B63' +
+    '9DB0C60506D3606906B8463AA0D0EC2F';
+
+  FSet1v9_448 := 'AB3216F1216379EFD5EC589510B8FD35' +
+    '014D0AA0B613040BAE63ECAB90A9AF79' + '661F8DA2F853A5204B0F8E72E9D9EB4D' +
+    'BA5A4690E73A4D25F61EE7295215140C';
+
+  FSet6v0_0 := 'F5FAD53F79F9DF58C4AEA0D0ED9A9601' +
+    'F278112CA7180D565B420A48019670EA' + 'F24CE493A86263F677B46ACE1924773D' +
+    '2BB25571E1AA8593758FC382B1280B71';
+
+  FSet6v0_65472 := 'B70C50139C63332EF6E77AC54338A407' +
+    '9B82BEC9F9A403DFEA821B83F7860791' + '650EF1B2489D0590B1DE772EEDA4E3BC' +
+    'D60FA7CE9CD623D9D2FD5758B8653E70';
+
+  FSet6v0_65536 := '81582C65D7562B80AEC2F1A673A9D01C' +
+    '9F892A23D4919F6AB47B9154E08E699B' + '4117D7C666477B60F8391481682F5D95' +
+    'D96623DBC489D88DAA6956B9F0646B6E';
+
+  FSet6v1_0 := '3944F6DC9F85B128083879FDF190F7DE' +
+    'E4053A07BC09896D51D0690BD4DA4AC1' + '062F1E47D3D0716F80A9B4D85E6D6085' +
+    'EE06947601C85F1A27A2F76E45A6AA87';
+
+  FSet6v1_65472 := '36E03B4B54B0B2E04D069E690082C8C5' +
+    '92DF56E633F5D8C7682A02A65ECD1371' + '8CA4352AACCB0DA20ED6BBBA62E177F2' +
+    '10E3560E63BB822C4158CAA806A88C82';
+
+  FSet6v1_65536 := '1B779E7A917C8C26039FFB23CF0EF8E0' +
+    '8A1A13B43ACDD9402CF5DF38501098DF' + 'C945A6CC69A6A17367BC03431A86B3ED' +
+    '04B0245B56379BF997E25800AD837D7D';
+
+  // Salsa20/12
+
+  FSalsa12_set1v0_0 := 'FC207DBFC76C5E1774961E7A5AAD0906' +
+    '9B2225AC1CE0FE7A0CE77003E7E5BDF8' + 'B31AF821000813E6C56B8C1771D6EE70' +
+    '39B2FBD0A68E8AD70A3944B677937897';
+
+  FSalsa12_set1v0_192 := '4B62A4881FA1AF9560586510D5527ED4' +
+    '8A51ECAFA4DECEEBBDDC10E9918D44AB' + '26B10C0A31ED242F146C72940C6E9C37' +
+    '53F641DA84E9F68B4F9E76B6C48CA5AC';
+
+  FSalsa12_set1v0_256 := 'F52383D9DEFB20810325F7AEC9EADE34' +
+    'D9D883FEE37E05F74BF40875B2D0BE79' + 'ED8886E5BFF556CEA8D1D9E86B1F68A9' +
+    '64598C34F177F8163E271B8D2FEB5996';
+
+  FSalsa12_set1v0_448 := 'A52ED8C37014B10EC0AA8E05B5CEEE12' +
+    '3A1017557FB3B15C53E6C5EA8300BF74' + '264A73B5315DC821AD2CAB0F3BB2F152' +
+    'BDAEA3AEE97BA04B8E72A7B40DCC6BA4';
+
+  // Salsa20/8
+
+  FSalsa8_set1v0_0 := 'A9C9F888AB552A2D1BBFF9F36BEBEB33' +
+    '7A8B4B107C75B63BAE26CB9A235BBA9D' + '784F38BEFC3ADF4CD3E266687EA7B9F0' +
+    '9BA650AE81EAC6063AE31FF12218DDC5';
+
+  FSalsa8_set1v0_192 := 'BB5B6BB2CC8B8A0222DCCC1753ED4AEB' +
+    '23377ACCBD5D4C0B69A8A03BB115EF71' + '871BC10559080ACA7C68F0DEF32A80DD' +
+    'BAF497259BB76A3853A7183B51CC4B9F';
+
+  FSalsa8_set1v0_256 := '4436CDC0BE39559F5E5A6B79FBDB2CAE' +
+    '4782910F27FFC2391E05CFC78D601AD8' + 'CD7D87B074169361D997D1BED9729C0D' +
+    'EB23418E0646B7997C06AA84E7640CE3';
+
+  FSalsa8_set1v0_448 := 'BEE85903BEA506B05FC04795836FAAAC' +
+    '7F93F785D473EB762576D96B4A65FFE4' + '63B34AAE696777FC6351B67C3753B89B' +
+    'A6B197BD655D1D9CA86E067F4D770220';
+
+end;
+
+procedure TTestSalsa20.TearDown;
+begin
+  inherited;
+
+end;
+
+procedure TTestSalsa20.Mismatch(const name, expected: String;
+  found: TCryptoLibByteArray);
+begin
+  Fail(Format('Mismatch on %s, Expected %s, Found %s.',
+    [name, expected, THex.Encode(found)]));
+end;
+
+procedure TTestSalsa20.DoSalsa20Test1(rounds: Int32;
+  const parameters: ICipherParameters; const v0, v192, v256, v448: String);
+var
+  salsa: ISalsa20Engine;
+  buf: TCryptoLibByteArray;
+  i: Int32;
+begin
+  salsa := TSalsa20Engine.Create(rounds);
+  salsa.Init(true, parameters);
+  System.SetLength(buf, 64);
+  i := 0;
+  while i <> 7 do
+  begin
+    salsa.ProcessBytes(FZeroes, 0, 64, buf, 0);
+    case i of
+      0:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v0))) then
+          begin
+            Mismatch(Format('v0/%d', [rounds]), v0, buf);
+          end;
+        end;
+      3:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v192))) then
+          begin
+            Mismatch(Format('v192/%d', [rounds]), v192, buf);
+          end;
+        end;
+      4:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v256))) then
+          begin
+            Mismatch(Format('v256/%d', [rounds]), v256, buf);
+          end;
+        end
+    else
+      begin
+        // ignore
+      end;
+    end;
+    System.Inc(i);
+  end;
+
+  i := 0;
+  while i <> 64 do
+  begin
+    buf[i] := salsa.ReturnByte(FZeroes[i]);
+    System.Inc(i);
+  end;
+
+  if not(TArrayUtils.AreEqual(buf, THex.Decode(v448))) then
+  begin
+    Mismatch(Format('v448/%d', [rounds]), v448, buf);
+  end;
+end;
+
+procedure TTestSalsa20.DoSalsa20Test2(const parameters: ICipherParameters;
+  const v0, v65472, v65536: String);
+var
+  salsa: ISalsa20Engine;
+  buf: TCryptoLibByteArray;
+  i: Int32;
+begin
+  salsa := TSalsa20Engine.Create();
+  salsa.Init(true, parameters);
+  System.SetLength(buf, 64);
+  i := 0;
+  while i <> 1025 do
+  begin
+    salsa.ProcessBytes(FZeroes, 0, 64, buf, 0);
+    case i of
+      0:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v0))) then
+          begin
+            Mismatch('v0', v0, buf);
+          end;
+        end;
+      1023:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v65472))) then
+          begin
+            Mismatch('v65472', v65472, buf);
+          end;
+        end;
+      1024:
+        begin
+          if not(TArrayUtils.AreEqual(buf, THex.Decode(v65536))) then
+          begin
+            Mismatch('v65536', v65536, buf);
+          end;
+        end
+    else
+      begin
+        // ignore
+      end;
+    end;
+    System.Inc(i);
+  end;
+
+end;
+
+procedure TTestSalsa20.TestSalsa20Test1;
+begin
+  DoSalsa20Test1(20, TParametersWithIV.Create
+    (TKeyParameter.Create(THex.Decode('80000000000000000000000000000000'))
+    as IKeyParameter, THex.Decode('0000000000000000')) as IParametersWithIV,
+    FSet1v0_0, FSet1v0_192, FSet1v0_256, FSet1v0_448);
+  DoSalsa20Test1(20, TParametersWithIV.Create
+    (TKeyParameter.Create(THex.Decode('00400000000000000000000000000000'))
+    as IKeyParameter, THex.Decode('0000000000000000')) as IParametersWithIV,
+    FSet1v9_0, FSet1v9_192, FSet1v9_256, FSet1v9_448);
+
+  DoSalsa20Test1(12, TParametersWithIV.Create
+    (TKeyParameter.Create(THex.Decode('80000000000000000000000000000000'))
+    as IKeyParameter, THex.Decode('0000000000000000')), FSalsa12_set1v0_0,
+    FSalsa12_set1v0_192, FSalsa12_set1v0_256, FSalsa12_set1v0_448);
+  DoSalsa20Test1(8, TParametersWithIV.Create
+    (TKeyParameter.Create(THex.Decode('80000000000000000000000000000000'))
+    as IKeyParameter, THex.Decode('0000000000000000')) as IParametersWithIV,
+    FSalsa8_set1v0_0, FSalsa8_set1v0_192, FSalsa8_set1v0_256,
+    FSalsa8_set1v0_448);
+
+end;
+
+procedure TTestSalsa20.TestSalsa20Test2;
+begin
+  DoSalsa20Test2(TParametersWithIV.Create
+    (TKeyParameter.Create(THex.Decode
+    ('0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D'))
+    as IKeyParameter, THex.Decode('0D74DB42A91077DE')) as IParametersWithIV,
+    FSet6v0_0, FSet6v0_65472, FSet6v0_65536);
+  DoSalsa20Test2(TParametersWithIV.Create
+    (TKeyParameter.Create(THex.Decode
+    ('0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12'))
+    as IKeyParameter, THex.Decode('167DE44BB21980E7')) as IParametersWithIV,
+    FSet6v1_0, FSet6v1_65472, FSet6v1_65536);
+end;
+
+procedure TTestSalsa20.TestReInitBug;
+var
+  key: IKeyParameter;
+  parameters: IParametersWithIV;
+  salsa: ISalsa20Engine;
+begin
+  key := TKeyParameter.Create(THex.Decode('80000000000000000000000000000000'));
+  parameters := TParametersWithIV.Create(key, THex.Decode('0000000000000000'));
+
+  salsa := TSalsa20Engine.Create();
+
+  salsa.Init(true, parameters);
+  try
+    salsa.Init(true, key);
+    Fail('Salsa20 should throw exception if no IV in Init');
+
+  except
+    on e: EArgumentCryptoLibException do
+    begin
+      // expected
+    end;
+
+  end;
+end;
+
+initialization
+
+// Register any test cases with the test runner
+
+{$IFDEF FPC}
+  RegisterTest(TTestSalsa20);
+{$ELSE}
+  RegisterTest(TTestSalsa20.Suite);
+{$ENDIF FPC}
+
+end.

+ 243 - 0
CryptoLib.Tests/src/Crypto/StreamCipherResetTests.pas

@@ -0,0 +1,243 @@
+{ *********************************************************************************** }
+{ *                              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 StreamCipherResetTests;
+
+interface
+
+{$IFDEF FPC}
+{$MODE DELPHI}
+{$ENDIF FPC}
+
+uses
+  SysUtils,
+{$IFDEF FPC}
+  fpcunit,
+  testregistry,
+{$ELSE}
+  TestFramework,
+{$ENDIF FPC}
+  ClpSalsa20Engine,
+  ClpISalsa20Engine,
+  ClpXSalsa20Engine,
+  ClpIXSalsa20Engine,
+  ClpChaChaEngine,
+  ClpIChaChaEngine,
+  ClpIStreamCipher,
+  ClpICipherParameters,
+  ClpKeyParameter,
+  ClpIKeyParameter,
+  ClpParametersWithIV,
+  ClpIParametersWithIV,
+  ClpSecureRandom,
+  ClpISecureRandom,
+  ClpEncoders,
+  ClpArrayUtils,
+  ClpCryptoLibTypes;
+
+type
+
+  TCryptoLibTestCase = class abstract(TTestCase)
+
+  end;
+
+type
+{$SCOPEDENUMS ON}
+  TCipherEngine = (Salsa20Engine, XSalsa20Engine, ChaChaEngine);
+{$SCOPEDENUMS OFF}
+
+type
+
+  /// <summary>
+  /// Test whether block ciphers implement reset contract on init,
+  /// encrypt/decrypt and reset.
+  /// </summary>
+  TTestStreamCipherReset = class(TCryptoLibTestCase)
+  private
+  var
+    FSecureRandom: ISecureRandom;
+
+    procedure DoCheckReset(const cipher: IStreamCipher;
+      const cipherParams: ICipherParameters; encrypt: Boolean;
+      const pretext, posttext: TCryptoLibByteArray);
+
+    function DoMake(CipherEngine: TCipherEngine): IStreamCipher;
+
+    function DoRandom(size: Int32): TCryptoLibByteArray;
+    procedure DoTestReset(CipherEngine: TCipherEngine;
+      KeyLen, IVLen: Int32); overload;
+    procedure DoTestReset(const cipher1, cipher2: IStreamCipher;
+      const cipherParams: ICipherParameters); overload;
+
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+  published
+
+    procedure TestReset;
+
+  end;
+
+implementation
+
+{ TTestStreamCipherReset }
+
+procedure TTestStreamCipherReset.DoCheckReset(const cipher: IStreamCipher;
+  const cipherParams: ICipherParameters; encrypt: Boolean;
+  const pretext, posttext: TCryptoLibByteArray);
+var
+  output: TCryptoLibByteArray;
+begin
+  // Do initial run
+  System.SetLength(output, System.Length(posttext));
+  cipher.ProcessBytes(pretext, 0, System.Length(pretext), output, 0);
+
+  // Check encrypt resets cipher
+  cipher.Init(encrypt, cipherParams);
+  try
+    cipher.ProcessBytes(pretext, 0, System.Length(pretext), output, 0);
+  except
+    on e: Exception do
+    begin
+      Fail(Format('%s init did not reset: %s', [cipher.AlgorithmName,
+        e.Message]));
+    end;
+
+  end;
+
+  if not(TArrayUtils.AreEqual(output, posttext)) then
+  begin
+    Fail(Format('%s init did not reset. Expected %s But Got %s',
+      [cipher.AlgorithmName, THex.Encode(posttext), THex.Encode(output)]));
+  end;
+
+  // Check reset resets data
+  cipher.Reset();
+
+  try
+    cipher.ProcessBytes(pretext, 0, System.Length(pretext), output, 0);
+  except
+    on e: Exception do
+    begin
+      Fail(Format('%s reset did not reset: ', [cipher.AlgorithmName,
+        e.Message]));
+    end;
+
+  end;
+
+  if not(TArrayUtils.AreEqual(output, posttext)) then
+  begin
+    Fail(Format('%s init did not reset.', [cipher.AlgorithmName]));
+  end;
+
+  //
+  // try
+  // {
+  // cipher.ProcessBytes(pretext, 0, pretext.Length, output, 0);
+  // }
+  // catch (Exception e)
+  // {
+  // Fail(cipher.AlgorithmName + " reset did not reset: " + e.Message);
+  // }
+  // if (!Arrays.AreEqual(output, posttext))
+  // {
+  // Fail(cipher.AlgorithmName + " reset did not reset.");
+  // }
+end;
+
+function TTestStreamCipherReset.DoMake(CipherEngine: TCipherEngine)
+  : IStreamCipher;
+begin
+  case CipherEngine of
+    TCipherEngine.Salsa20Engine:
+      Result := TSalsa20Engine.Create() as ISalsa20Engine;
+    TCipherEngine.XSalsa20Engine:
+      Result := TXSalsa20Engine.Create() as IXSalsa20Engine;
+    TCipherEngine.ChaChaEngine:
+      Result := TChaChaEngine.Create() as IChaChaEngine
+  else
+    begin
+      raise Exception.Create('Unsupported Cipher Engine');
+    end;
+  end;
+end;
+
+function TTestStreamCipherReset.DoRandom(size: Int32): TCryptoLibByteArray;
+begin
+  Result := TSecureRandom.GetNextBytes(FSecureRandom, size);
+end;
+
+procedure TTestStreamCipherReset.DoTestReset(CipherEngine: TCipherEngine;
+  KeyLen, IVLen: Int32);
+begin
+  DoTestReset(DoMake(CipherEngine), DoMake(CipherEngine),
+    TParametersWithIV.Create(TKeyParameter.Create(DoRandom(KeyLen))
+    as IKeyParameter, DoRandom(IVLen)) as IParametersWithIV);
+end;
+
+procedure TTestStreamCipherReset.DoTestReset(const cipher1,
+  cipher2: IStreamCipher; const cipherParams: ICipherParameters);
+var
+  plaintext, ciphertext: TCryptoLibByteArray;
+begin
+  cipher1.Init(true, cipherParams);
+  System.SetLength(plaintext, 1023);
+  System.SetLength(ciphertext, System.Length(plaintext));
+
+  // Establish baseline answer
+  cipher1.ProcessBytes(plaintext, 0, System.Length(plaintext), ciphertext, 0);
+
+  // Test encryption resets
+  DoCheckReset(cipher1, cipherParams, true, plaintext, ciphertext);
+
+  // Test decryption resets with fresh instance
+  cipher2.Init(false, cipherParams);
+  DoCheckReset(cipher2, cipherParams, false, ciphertext, plaintext);
+end;
+
+procedure TTestStreamCipherReset.SetUp;
+begin
+  inherited;
+  FSecureRandom := TSecureRandom.Create();
+end;
+
+procedure TTestStreamCipherReset.TearDown;
+begin
+  inherited;
+
+end;
+
+procedure TTestStreamCipherReset.TestReset;
+begin
+  DoTestReset(TCipherEngine.Salsa20Engine, 32, 8);
+  DoTestReset(TCipherEngine.Salsa20Engine, 16, 8);
+  DoTestReset(TCipherEngine.XSalsa20Engine, 32, 24);
+  DoTestReset(TCipherEngine.ChaChaEngine, 32, 8);
+  DoTestReset(TCipherEngine.ChaChaEngine, 16, 8);
+end;
+
+initialization
+
+// Register any test cases with the test runner
+
+{$IFDEF FPC}
+  RegisterTest(TTestStreamCipherReset);
+{$ELSE}
+  RegisterTest(TTestStreamCipherReset.Suite);
+{$ENDIF FPC}
+
+end.

+ 162 - 0
CryptoLib.Tests/src/Crypto/XSalsa20Tests.pas

@@ -0,0 +1,162 @@
+{ *********************************************************************************** }
+{ *                              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 XSalsa20Tests;
+
+interface
+
+{$IFDEF FPC}
+{$MODE DELPHI}
+{$ENDIF FPC}
+
+uses
+  SysUtils,
+{$IFDEF FPC}
+  fpcunit,
+  testregistry,
+{$ELSE}
+  TestFramework,
+{$ENDIF FPC}
+  ClpXSalsa20Engine,
+  ClpIXSalsa20Engine,
+  ClpKeyParameter,
+  ClpIKeyParameter,
+  ClpParametersWithIV,
+  ClpIParametersWithIV,
+  ClpEncoders,
+  ClpArrayUtils,
+  ClpCryptoLibTypes;
+
+type
+
+  TCryptoLibTestCase = class abstract(TTestCase)
+
+  end;
+
+type
+
+  TTestXSalsa20 = class(TCryptoLibTestCase)
+
+  private
+  var
+    FTestVectors: TCryptoLibGenericArray<TCryptoLibStringArray>;
+
+    procedure DoXSalsa20Test(number: Int32;
+      const ATestVectorParams: TCryptoLibStringArray);
+
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+  published
+
+    procedure TestXSalsa20Test();
+
+  end;
+
+implementation
+
+{ TTestXSalsa20 }
+
+procedure TTestXSalsa20.DoXSalsa20Test(number: Int32;
+  const ATestVectorParams: TCryptoLibStringArray);
+var
+  engine: IXSalsa20Engine;
+var
+  LPlainText, LCipherText, LOutput, LKey, LIV: TCryptoLibByteArray;
+begin
+  LPlainText := THex.Decode(ATestVectorParams[2]);
+  System.SetLength(LOutput, System.Length(LPlainText));
+  LKey := THex.Decode(ATestVectorParams[0]);
+  LIV := THex.Decode(ATestVectorParams[1]);
+  LCipherText := THex.Decode(ATestVectorParams[3]);
+
+  engine := TXSalsa20Engine.Create();
+  engine.Init(false, TParametersWithIV.Create(TKeyParameter.Create(LKey)
+    as IKeyParameter, LIV) as IParametersWithIV);
+
+  engine.ProcessBytes(LPlainText, 0, System.Length(LPlainText), LOutput, 0);
+
+  if not(TArrayUtils.AreEqual(LCipherText, LOutput)) then
+  begin
+    Fail(Format('Mismatch on %d, Expected %s but found %s',
+      [number, THex.Encode(LCipherText), THex.Encode(LOutput)]));
+  end;
+
+end;
+
+procedure TTestXSalsa20.SetUp;
+begin
+  inherited;
+  // Test cases generated by naclcrypto-20090308, as used by cryptopp
+  FTestVectors := TCryptoLibGenericArray<TCryptoLibStringArray>.Create
+    (TCryptoLibStringArray.Create
+    ('A6A7251C1E72916D11C2CB214D3C252539121D8E234E652D651FA4C8CFF88030',
+    '9E645A74E9E0A60D8243ACD9177AB51A1BEB8D5A2F5D700C',
+    '093C5E5585579625337BD3AB619D615760D8C5B224A85B1D0EFE0EB8A7EE163ABB0376529FCC09BAB506C6'
+    + '18E13CE777D82C3AE9D1A6F972D4160287CBFE60BF2130FC0A6FF6049D0A5C8A82F429231F008082E845D7E189D37F9ED2B464E6B9'
+    + '19E6523A8C1210BD52A02A4C3FE406D3085F5068D1909EEECA6369ABC981A42E87FE665583F0AB85AE71F6F84F528E6B397AF86F6917D9754B7320DBDC2FEA81496F2732F532AC78C4E9C6CFB18F8E9BDF74622EB126141416776971A84F94D156BEAF67AECBF2AD412E76E66E'
+    + '8FAD7633F5B6D7F3D64B5C6C69CE29003C6024465AE3B89BE78E915D88B4B5621D',
+    'B2AF688E7D8FC4B508C05CC39DD583D6714322C64D7F3E63147AEDE2D9534934B04FF6F337B031815CD094BDBC6D7A92077DCE709412286822EF0737EE47F6B7FF'
+    + 'A22F9D53F11DD2B0A3BB9FC01D9A88F9D53C26E9365C2C3C063BC4840BFC812E4B80463E69D179530B25C158F543191CFF993106511AA036043BBC75866AB7E34AFC57E2CCE4934A5FAAE6EABE4F2217'
+    + '70183DD060467827C27A354159A081275A291F69D946D6FE28ED0B9CE08206CF484925A51B9498DBDE178DDD3AE91A8581B91682D860F840782F6EEA49DBB9BD721'
+    + '501D2C67122DEA3B7283848C5F13E0C0DE876BD227A856E4DE593A3'),
+
+    TCryptoLibStringArray.Create
+    ('D5C7F6797B7E7E9C1D7FD2610B2ABF2BC5A7885FB3FF78092FB3ABE8986D35E2',
+    '744E17312B27969D826444640E9C4A378AE334F185369C95',
+    '7758298C628EB3A4B6963C5445EF66971222BE5D1A4AD839715D1188071739B77CC6E05D5410F963A64167629757',
+    '27B8CFE81416A76301FD1EEC6A4D99675069B2DA2776C360DB1BDFEA7C0AA613913E10F7A60FEC04D11E65F2D64E'),
+
+    TCryptoLibStringArray.Create
+    ('6799D76E5FFB5B4920BC2768BAFD3F8C16554E65EFCF9A16F4683A7A06927C11',
+    '61AB951921E54FF06D9B77F313A4E49DF7A057D5FD627989', '472766', '8FD7DF'),
+
+    TCryptoLibStringArray.Create
+    ('AD1A5C47688874E6663A0F3FA16FA7EFB7ECADC175C468E5432914BDB480FFC6',
+    'E489EED440F1AAE1FAC8FB7A9825635454F8F8F1F52E2FCC',
+    'AA6C1E53580F03A9ABB73BFDADEDFECADA4C6B0EBE020EF10DB745E54BA861CAF65F0E40DFC520203BB54D29E0A8F78F16B3F1AA525D6BFA33C54726E59988CFBEC78056',
+    '02FE84CE81E178E7AABDD3BA925A766C3C24756EEFAE33942AF75E8B464556B5997E616F3F2DFC7FCE91848AFD79912D9FB55201B5813A5A074D2C0D4292C1FD441807C5')
+    );
+end;
+
+procedure TTestXSalsa20.TearDown;
+begin
+  inherited;
+
+end;
+
+procedure TTestXSalsa20.TestXSalsa20Test;
+var
+  LIdx: Int32;
+begin
+  for LIdx := System.Low(FTestVectors) to System.High(FTestVectors) do
+  begin
+    DoXSalsa20Test(LIdx, FTestVectors[LIdx]);
+  end;
+end;
+
+initialization
+
+// Register any test cases with the test runner
+
+{$IFDEF FPC}
+  RegisterTest(TTestXSalsa20);
+{$ELSE}
+  RegisterTest(TTestXSalsa20.Suite);
+{$ENDIF FPC}
+
+end.

+ 1 - 1
CryptoLib/src/Crypto/ClpBufferedCipherBase.pas

@@ -56,6 +56,7 @@ type
 
 
   strict protected
   strict protected
 
 
+    function GetAlgorithmName: String; virtual; abstract;
     function GetBufferSize: Int32; inline;
     function GetBufferSize: Int32; inline;
     procedure SetBufferSize(value: Int32); inline;
     procedure SetBufferSize(value: Int32); inline;
     function GetOnProgress: TBufferedCipherProgressEvent; inline;
     function GetOnProgress: TBufferedCipherProgressEvent; inline;
@@ -122,7 +123,6 @@ type
 
 
     procedure Reset(); virtual; abstract;
     procedure Reset(); virtual; abstract;
 
 
-    function GetAlgorithmName: String; virtual; abstract;
     property AlgorithmName: String read GetAlgorithmName;
     property AlgorithmName: String read GetAlgorithmName;
 
 
     /// <summary>
     /// <summary>

+ 195 - 0
CryptoLib/src/Crypto/ClpBufferedStreamCipher.pas

@@ -0,0 +1,195 @@
+{ *********************************************************************************** }
+{ *                              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 ClpBufferedStreamCipher;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpIStreamCipher,
+  ClpICipherParameters,
+  ClpIParametersWithRandom,
+  ClpIBufferedStreamCipher,
+  ClpBufferedCipherBase,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SCipherNil = 'Cipher Instance Cannot be Nil';
+
+type
+  TBufferedStreamCipher = class(TBufferedCipherBase, IBufferedStreamCipher)
+
+  strict private
+  var
+    FCipher: IStreamCipher;
+
+  strict protected
+    function GetAlgorithmName: String; override;
+
+  public
+    constructor Create(const cipher: IStreamCipher);
+
+    procedure Init(forEncryption: Boolean;
+      const parameters: ICipherParameters); override;
+
+    function GetBlockSize(): Int32; override;
+
+    function GetOutputSize(inputLen: Int32): Int32; override;
+
+    function GetUpdateOutputSize(inputLen: Int32): Int32; override;
+
+    function ProcessByte(input: Byte): TCryptoLibByteArray; overload; override;
+    function ProcessByte(input: Byte; const output: TCryptoLibByteArray;
+      outOff: Int32): Int32; overload; override;
+
+    function ProcessBytes(const input: TCryptoLibByteArray;
+      inOff, Length: Int32): TCryptoLibByteArray; overload; override;
+    function ProcessBytes(const input: TCryptoLibByteArray;
+      inOff, Length: Int32; const output: TCryptoLibByteArray; outOff: Int32)
+      : Int32; overload; override;
+
+    function DoFinal(): TCryptoLibByteArray; overload; override;
+    function DoFinal(const input: TCryptoLibByteArray; inOff, Length: Int32)
+      : TCryptoLibByteArray; overload; override;
+
+    procedure Reset(); override;
+
+    property AlgorithmName: String read GetAlgorithmName;
+
+  end;
+
+implementation
+
+{ TBufferedStreamCipher }
+
+constructor TBufferedStreamCipher.Create(const cipher: IStreamCipher);
+begin
+  Inherited Create();
+  if (cipher = Nil) then
+  begin
+    raise EArgumentNilCryptoLibException.CreateRes(@SCipherNil);
+  end;
+
+  FCipher := cipher;
+end;
+
+function TBufferedStreamCipher.GetAlgorithmName: String;
+begin
+  result := FCipher.AlgorithmName;
+end;
+
+function TBufferedStreamCipher.GetBlockSize: Int32;
+begin
+  result := 0;
+end;
+
+function TBufferedStreamCipher.GetOutputSize(inputLen: Int32): Int32;
+begin
+  result := inputLen;
+end;
+
+function TBufferedStreamCipher.GetUpdateOutputSize(inputLen: Int32): Int32;
+begin
+  result := inputLen;
+end;
+
+procedure TBufferedStreamCipher.Init(forEncryption: Boolean;
+  const parameters: ICipherParameters);
+var
+  LParameters: ICipherParameters;
+begin
+  LParameters := parameters;
+  if Supports(LParameters, IParametersWithRandom) then
+  begin
+    LParameters := (LParameters as IParametersWithRandom).parameters;
+  end;
+  FCipher.Init(forEncryption, LParameters);
+end;
+
+function TBufferedStreamCipher.ProcessByte(input: Byte;
+  const output: TCryptoLibByteArray; outOff: Int32): Int32;
+begin
+  if (outOff >= System.Length(output)) then
+  begin
+    raise EDataLengthCryptoLibException.CreateRes(@SOutputBufferTooSmall);
+  end;
+  output[outOff] := FCipher.ReturnByte(input);
+  result := 1;
+end;
+
+function TBufferedStreamCipher.ProcessByte(input: Byte): TCryptoLibByteArray;
+begin
+  result := TCryptoLibByteArray.Create(FCipher.ReturnByte(input));
+end;
+
+function TBufferedStreamCipher.ProcessBytes(const input: TCryptoLibByteArray;
+  inOff, Length: Int32; const output: TCryptoLibByteArray;
+  outOff: Int32): Int32;
+begin
+  if (Length < 1) then
+  begin
+    result := 0;
+    Exit;
+  end;
+
+  if (Length > 0) then
+  begin
+    FCipher.ProcessBytes(input, inOff, Length, output, outOff);
+  end;
+
+  result := Length;
+end;
+
+function TBufferedStreamCipher.ProcessBytes(const input: TCryptoLibByteArray;
+  inOff, Length: Int32): TCryptoLibByteArray;
+begin
+  if (Length < 1) then
+  begin
+    result := Nil;
+    Exit;
+  end;
+  System.SetLength(result, Length);
+  FCipher.ProcessBytes(input, inOff, Length, result, 0);
+end;
+
+function TBufferedStreamCipher.DoFinal: TCryptoLibByteArray;
+begin
+  Reset();
+  result := EmptyBuffer;
+end;
+
+function TBufferedStreamCipher.DoFinal(const input: TCryptoLibByteArray;
+  inOff, Length: Int32): TCryptoLibByteArray;
+begin
+  if (Length < 1) then
+  begin
+    result := EmptyBuffer;
+    Exit;
+  end;
+  result := ProcessBytes(input, inOff, Length);
+  Reset();
+end;
+
+procedure TBufferedStreamCipher.Reset;
+begin
+  FCipher.Reset();
+end;
+
+end.

+ 263 - 0
CryptoLib/src/Crypto/Engines/ClpChaChaEngine.pas

@@ -0,0 +1,263 @@
+{ *********************************************************************************** }
+{ *                              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 ClpChaChaEngine;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpIChaChaEngine,
+  ClpSalsa20Engine,
+  ClpConverters,
+  ClpCryptoLibTypes;
+
+type
+
+  /// <summary>
+  /// Implementation of Daniel J. Bernstein's ChaCha stream cipher.
+  /// </summary>
+  TChaChaEngine = class sealed(TSalsa20Engine, IChaChaEngine)
+
+  strict private
+    /// <summary>
+    /// ChaCha function.
+    /// </summary>
+    /// <param name="rounds">The number of ChaCha rounds to execute</param>
+    /// <param name="input">The input words.</param>
+    /// <param name="x">The ChaCha state to modify.</param>
+    class procedure ChaChaCore(rounds: Int32;
+      const input, x: TCryptoLibUInt32Array); static;
+
+  strict protected
+    function GetAlgorithmName: String; override;
+
+    procedure AdvanceCounter(); override;
+    procedure ResetCounter(); override;
+    procedure SetKey(const keyBytes, ivBytes: TCryptoLibByteArray); override;
+    procedure GenerateKeyStream(const output: TCryptoLibByteArray); override;
+
+  public
+    /// <summary>
+    /// Creates a 20 rounds ChaCha engine.
+    /// </summary>
+    constructor Create(); overload;
+    /// <summary>
+    /// Creates a ChaCha engine with a specific number of rounds.
+    /// </summary>
+    /// <param name="rounds">the number of rounds (must be an even number).</param>
+    constructor Create(rounds: Int32); overload;
+
+  end;
+
+implementation
+
+{ TChaChaEngine }
+
+procedure TChaChaEngine.AdvanceCounter;
+begin
+  System.Inc(FEngineState[12]);
+  if (FEngineState[12] = 0) then
+  begin
+    System.Inc(FEngineState[13]);
+  end;
+end;
+
+class procedure TChaChaEngine.ChaChaCore(rounds: Int32;
+  const input, x: TCryptoLibUInt32Array);
+var
+  x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, x12, x13, x14,
+    x15: UInt32;
+  Idx: Int32;
+begin
+  if (System.Length(input) <> 16) then
+  begin
+    raise EArgumentCryptoLibException.Create('');
+  end;
+  if (System.Length(x) <> 16) then
+  begin
+    raise EArgumentCryptoLibException.Create('');
+  end;
+  if ((rounds mod 2) <> 0) then
+  begin
+    raise EArgumentCryptoLibException.CreateRes(@SRoundsMustbeEven);
+  end;
+
+  x00 := input[0];
+  x01 := input[1];
+  x02 := input[2];
+  x03 := input[3];
+  x04 := input[4];
+  x05 := input[5];
+  x06 := input[6];
+  x07 := input[7];
+  x08 := input[8];
+  x09 := input[9];
+  x10 := input[10];
+  x11 := input[11];
+  x12 := input[12];
+  x13 := input[13];
+  x14 := input[14];
+  x15 := input[15];
+
+  Idx := rounds;
+  while Idx > 0 do
+  begin
+
+    x00 := x00 + x04;
+    x12 := R(x12 xor x00, 16);
+    x08 := x08 + x12;
+    x04 := R(x04 xor x08, 12);
+    x00 := x00 + x04;
+    x12 := R(x12 xor x00, 8);
+    x08 := x08 + x12;
+    x04 := R(x04 xor x08, 7);
+    x01 := x01 + x05;
+    x13 := R(x13 xor x01, 16);
+    x09 := x09 + x13;
+    x05 := R(x05 xor x09, 12);
+    x01 := x01 + x05;
+    x13 := R(x13 xor x01, 8);
+    x09 := x09 + x13;
+    x05 := R(x05 xor x09, 7);
+    x02 := x02 + x06;
+    x14 := R(x14 xor x02, 16);
+    x10 := x10 + x14;
+    x06 := R(x06 xor x10, 12);
+    x02 := x02 + x06;
+    x14 := R(x14 xor x02, 8);
+    x10 := x10 + x14;
+    x06 := R(x06 xor x10, 7);
+    x03 := x03 + x07;
+    x15 := R(x15 xor x03, 16);
+    x11 := x11 + x15;
+    x07 := R(x07 xor x11, 12);
+    x03 := x03 + x07;
+    x15 := R(x15 xor x03, 8);
+    x11 := x11 + x15;
+    x07 := R(x07 xor x11, 7);
+    x00 := x00 + x05;
+    x15 := R(x15 xor x00, 16);
+    x10 := x10 + x15;
+    x05 := R(x05 xor x10, 12);
+    x00 := x00 + x05;
+    x15 := R(x15 xor x00, 8);
+    x10 := x10 + x15;
+    x05 := R(x05 xor x10, 7);
+    x01 := x01 + x06;
+    x12 := R(x12 xor x01, 16);
+    x11 := x11 + x12;
+    x06 := R(x06 xor x11, 12);
+    x01 := x01 + x06;
+    x12 := R(x12 xor x01, 8);
+    x11 := x11 + x12;
+    x06 := R(x06 xor x11, 7);
+    x02 := x02 + x07;
+    x13 := R(x13 xor x02, 16);
+    x08 := x08 + x13;
+    x07 := R(x07 xor x08, 12);
+    x02 := x02 + x07;
+    x13 := R(x13 xor x02, 8);
+    x08 := x08 + x13;
+    x07 := R(x07 xor x08, 7);
+    x03 := x03 + x04;
+    x14 := R(x14 xor x03, 16);
+    x09 := x09 + x14;
+    x04 := R(x04 xor x09, 12);
+    x03 := x03 + x04;
+    x14 := R(x14 xor x03, 8);
+    x09 := x09 + x14;
+    x04 := R(x04 xor x09, 7);
+
+    System.Dec(Idx, 2);
+  end;
+
+  x[0] := x00 + input[0];
+  x[1] := x01 + input[1];
+  x[2] := x02 + input[2];
+  x[3] := x03 + input[3];
+  x[4] := x04 + input[4];
+  x[5] := x05 + input[5];
+  x[6] := x06 + input[6];
+  x[7] := x07 + input[7];
+  x[8] := x08 + input[8];
+  x[9] := x09 + input[9];
+  x[10] := x10 + input[10];
+  x[11] := x11 + input[11];
+  x[12] := x12 + input[12];
+  x[13] := x13 + input[13];
+  x[14] := x14 + input[14];
+  x[15] := x15 + input[15];
+
+end;
+
+constructor TChaChaEngine.Create;
+begin
+  Inherited Create();
+end;
+
+constructor TChaChaEngine.Create(rounds: Int32);
+begin
+  Inherited Create(rounds);
+end;
+
+procedure TChaChaEngine.GenerateKeyStream(const output: TCryptoLibByteArray);
+begin
+  ChaChaCore(FRounds, FEngineState, Fx);
+  TConverters.le32_copy(PCardinal(Fx), 0, PByte(output), 0,
+    System.Length(Fx) * System.SizeOf(UInt32));
+end;
+
+function TChaChaEngine.GetAlgorithmName: String;
+begin
+  result := Format('ChaCha%d', [FRounds]);
+end;
+
+procedure TChaChaEngine.ResetCounter;
+begin
+  FEngineState[12] := 0;
+  FEngineState[13] := 0;
+end;
+
+procedure TChaChaEngine.SetKey(const keyBytes, ivBytes: TCryptoLibByteArray);
+begin
+  if (keyBytes <> Nil) then
+  begin
+    if not(Byte(System.Length(keyBytes)) in [16, 32]) then
+    begin
+      raise EArgumentCryptoLibException.CreateResFmt(@SInvalidKeySize,
+        [AlgorithmName]);
+    end;
+
+    PackTauOrSigma(System.Length(keyBytes), FEngineState, 0);
+
+    // Key
+    TConverters.le32_copy(PByte(keyBytes), 0, PCardinal(FEngineState),
+      4 * System.SizeOf(UInt32), 4 * System.SizeOf(UInt32));
+    TConverters.le32_copy(PByte(keyBytes), (System.Length(keyBytes) - 16) *
+      System.SizeOf(Byte), PCardinal(FEngineState), 8 * System.SizeOf(UInt32),
+      4 * System.SizeOf(UInt32));
+  end;
+
+  // IV
+  TConverters.le32_copy(PByte(ivBytes), 0, PCardinal(FEngineState),
+    14 * System.SizeOf(UInt32), 2 * System.SizeOf(UInt32));
+end;
+
+end.

+ 502 - 0
CryptoLib/src/Crypto/Engines/ClpSalsa20Engine.pas

@@ -0,0 +1,502 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSalsa20Engine;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpBits,
+  ClpCheck,
+  ClpISalsa20Engine,
+  ClpIKeyParameter,
+  ClpICipherParameters,
+  ClpParametersWithIV,
+  ClpIParametersWithIV,
+  ClpConverters,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SInvalidRound = '"rounds" Must be a Positive, Even Number';
+  SInvalidKeySize = '%s Requires 128 bit or 256 bit key';
+  SMaxByteExceeded = '2^70 Byte Limit per IV; Change IV';
+  SMaxByteExceededTwo = '2^70 byte limit per IV would be exceeded; Change IV';
+  SEngineNotInitialized = '%s not Initialized';
+  SInputBuffertooShort = 'Input Buffer too Short';
+  SOutputBuffertooShort = 'Output Buffer too Short';
+  SRoundsMustbeEven = 'Number of Rounds Must be Even';
+{$IFNDEF _FIXINSIGHT_}
+  SIVRequired = '%s Init Requires an IV, "parameters"';
+  SInvalidIV = '%s Requires exactly %d bytes of IV';
+  SInitError =
+    '%s Init Parameters must Contain a KeyParameter (or null for Re-Init)';
+  SKeyParameterNullForFirstInit =
+    'KeyParameter can not be null for First Initialisation';
+{$ENDIF}
+
+type
+
+  /// <summary>
+  /// Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005
+  /// </summary>
+  TSalsa20Engine = class(TInterfacedObject, ISalsa20Engine)
+
+  strict private
+  const
+    DEFAULT_ROUNDS = Int32(20);
+    STATE_SIZE = Int32(16); // 16, 32 bit ints = 64 bytes
+    // representation of 'expand 16-byte k' + 'expand 32-byte k' as an array of UInt32
+    TAU_SIGMA: array [0 .. 7] of UInt32 = (1634760805, 824206446, 2036477238,
+      1797285236, 1634760805, 857760878, 2036477234, 1797285236);
+
+  var
+    FIndex: Int32;
+    // internal counter
+    FCW0, FCW1, FCW2: UInt32;
+    FKeyStream: TCryptoLibByteArray;
+    FInitialised: Boolean;
+
+    procedure ResetLimitCounter(); inline;
+    function LimitExceeded(): Boolean; overload; inline;
+    // this relies on the fact len will always be positive.
+    function LimitExceeded(len: UInt32): Boolean; overload; inline;
+
+  strict protected
+  var
+    FRounds: Int32;
+    FEngineState, Fx: TCryptoLibUInt32Array;
+
+    function GetAlgorithmName: String; virtual;
+    function GetNonceSize: Int32; virtual;
+    property NonceSize: Int32 read GetNonceSize;
+
+    procedure AdvanceCounter(); virtual;
+    procedure ResetCounter(); virtual;
+    procedure SetKey(const keyBytes, ivBytes: TCryptoLibByteArray); virtual;
+    procedure GenerateKeyStream(const output: TCryptoLibByteArray); virtual;
+
+    /// <summary>
+    /// Rotate left
+    /// </summary>
+    /// <param name="x">
+    /// value to rotate
+    /// </param>
+    /// <param name="y">
+    /// amount to rotate x
+    /// </param>
+    /// <returns>
+    /// rotated x
+    /// </returns>
+    class function R(x: UInt32; y: Int32): UInt32; static; inline;
+    class procedure PackTauOrSigma(keyLength: Int32;
+      const state: TCryptoLibUInt32Array; stateOffset: Int32); static;
+    class procedure SalsaCore(rounds: Int32;
+      const input, x: TCryptoLibUInt32Array); static;
+
+  public
+    /// <summary>
+    /// Creates a 20 round Salsa20 engine.
+    /// </summary>
+    constructor Create(); overload;
+    /// <summary>
+    /// Creates a Salsa20 engine with a specific number of rounds.
+    /// </summary>
+    /// <param name="rounds">the number of rounds (must be an even number).</param>
+    constructor Create(rounds: Int32); overload;
+
+{$IFNDEF _FIXINSIGHT_}
+    procedure Init(forEncryption: Boolean;
+      const parameters: ICipherParameters); virtual;
+{$ENDIF}
+    function ReturnByte(input: Byte): Byte; virtual;
+
+    procedure ProcessBytes(const inBytes: TCryptoLibByteArray;
+      inOff, len: Int32; const outBytes: TCryptoLibByteArray;
+      outOff: Int32); virtual;
+
+    procedure Reset(); virtual;
+
+    property AlgorithmName: String read GetAlgorithmName;
+
+  end;
+
+implementation
+
+{ TSalsa20Engine }
+
+constructor TSalsa20Engine.Create;
+begin
+  Create(DEFAULT_ROUNDS);
+end;
+
+procedure TSalsa20Engine.AdvanceCounter;
+begin
+  System.Inc(FEngineState[8]);
+  if (FEngineState[8] = 0) then
+  begin
+    System.Inc(FEngineState[9]);
+  end;
+end;
+
+constructor TSalsa20Engine.Create(rounds: Int32);
+begin
+  Inherited Create();
+  if ((rounds <= 0) or ((rounds and 1) <> 0)) then
+  begin
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidRound);
+  end;
+  FRounds := rounds;
+  FIndex := 0;
+  FInitialised := false;
+  System.SetLength(FEngineState, STATE_SIZE); // state
+  System.SetLength(Fx, STATE_SIZE); // internal buffer
+  System.SetLength(FKeyStream, STATE_SIZE * 4); // expanded state, 64 bytes
+end;
+
+procedure TSalsa20Engine.GenerateKeyStream(const output: TCryptoLibByteArray);
+begin
+  SalsaCore(FRounds, FEngineState, Fx);
+  TConverters.le32_copy(PCardinal(Fx), 0, PByte(output), 0,
+    System.Length(Fx) * System.SizeOf(UInt32));
+end;
+
+function TSalsa20Engine.GetAlgorithmName: String;
+begin
+  result := 'Salsa20';
+  if (FRounds <> DEFAULT_ROUNDS) then
+  begin
+    result := Format('%s/%d', [result, FRounds]);
+  end;
+end;
+
+function TSalsa20Engine.GetNonceSize: Int32;
+begin
+  result := 8;
+end;
+
+{$IFNDEF _FIXINSIGHT_}
+
+procedure TSalsa20Engine.Init(forEncryption: Boolean;
+  const parameters: ICipherParameters);
+var
+  ivParams: IParametersWithIV;
+  iv: TCryptoLibByteArray;
+  keyParam: ICipherParameters;
+begin
+  (*
+    * Salsa20 encryption and decryption is completely
+    * symmetrical, so the 'forEncryption' is
+    * irrelevant. (Like 90% of stream ciphers)
+  *)
+
+  if not Supports(parameters, IParametersWithIV, ivParams) then
+  begin
+    raise EArgumentCryptoLibException.CreateResFmt(@SIVRequired,
+      [AlgorithmName]);
+  end;
+
+  iv := ivParams.GetIV();
+  if ((iv = Nil) or (System.Length(iv) <> NonceSize)) then
+  begin
+    raise EArgumentCryptoLibException.CreateResFmt(@SInvalidIV,
+      [AlgorithmName, NonceSize]);
+  end;
+
+  keyParam := ivParams.parameters;
+  if (keyParam = Nil) then
+  begin
+    if (not FInitialised) then
+    begin
+      raise EArgumentCryptoLibException.CreateResFmt
+        (@SKeyParameterNullForFirstInit, [AlgorithmName]);
+    end;
+
+    SetKey(Nil, iv);
+  end
+  else if Supports(keyParam, IKeyParameter) then
+  begin
+    SetKey((keyParam as IKeyParameter).GetKey(), iv);
+  end
+  else
+  begin
+    raise EArgumentCryptoLibException.CreateResFmt(@SInitError,
+      [AlgorithmName]);
+  end;
+
+  Reset();
+  FInitialised := true;
+end;
+{$ENDIF}
+
+function TSalsa20Engine.LimitExceeded: Boolean;
+begin
+  System.Inc(FCW0);
+  if (FCW0 = 0) then
+  begin
+    System.Inc(FCW1);
+    if (FCW1 = 0) then
+    begin
+      System.Inc(FCW2);
+      result := (FCW2 and $20) <> 0; // 2^(32 + 32 + 6)
+      Exit;
+    end;
+  end;
+
+  result := false;
+end;
+
+function TSalsa20Engine.LimitExceeded(len: UInt32): Boolean;
+var
+  Old: UInt32;
+begin
+  Old := FCW0;
+  System.Inc(FCW0, len);
+  if (FCW0 < Old) then
+  begin
+    System.Inc(FCW1);
+    if (FCW1 = 0) then
+    begin
+      System.Inc(FCW2);
+      result := (FCW2 and $20) <> 0; // 2^(32 + 32 + 6)
+      Exit;
+    end;
+  end;
+
+  result := false;
+end;
+
+class procedure TSalsa20Engine.PackTauOrSigma(keyLength: Int32;
+  const state: TCryptoLibUInt32Array; stateOffset: Int32);
+var
+  tsOff: Int32;
+begin
+  tsOff := (keyLength - 16) div 4;
+  state[stateOffset] := TAU_SIGMA[tsOff];
+  state[stateOffset + 1] := TAU_SIGMA[tsOff + 1];
+  state[stateOffset + 2] := TAU_SIGMA[tsOff + 2];
+  state[stateOffset + 3] := TAU_SIGMA[tsOff + 3];
+end;
+
+procedure TSalsa20Engine.ProcessBytes(const inBytes: TCryptoLibByteArray;
+  inOff, len: Int32; const outBytes: TCryptoLibByteArray; outOff: Int32);
+var
+  Idx: Int32;
+begin
+  if (not FInitialised) then
+  begin
+    raise EInvalidOperationCryptoLibException.CreateResFmt
+      (@SEngineNotInitialized, [AlgorithmName]);
+  end;
+
+  TCheck.DataLength(inBytes, inOff, len, SInputBuffertooShort);
+  TCheck.OutputLength(outBytes, outOff, len, SOutputBuffertooShort);
+
+  if (LimitExceeded(UInt32(len))) then
+  begin
+    raise EMaxBytesExceededCryptoLibException.CreateRes(@SMaxByteExceededTwo);
+  end;
+
+  for Idx := 0 to System.Pred(len) do
+  begin
+    if (FIndex = 0) then
+    begin
+      GenerateKeyStream(FKeyStream);
+      AdvanceCounter();
+    end;
+    outBytes[Idx + outOff] := Byte(FKeyStream[FIndex] xor inBytes[Idx + inOff]);
+    FIndex := (FIndex + 1) and 63;
+  end;
+end;
+
+class function TSalsa20Engine.R(x: UInt32; y: Int32): UInt32;
+begin
+  result := TBits.RotateLeft32(x, y);
+end;
+
+procedure TSalsa20Engine.ResetCounter;
+begin
+  FEngineState[8] := 0;
+  FEngineState[9] := 0;
+end;
+
+procedure TSalsa20Engine.ResetLimitCounter;
+begin
+  FCW0 := 0;
+  FCW1 := 0;
+  FCW2 := 0;
+end;
+
+procedure TSalsa20Engine.Reset;
+begin
+  FIndex := 0;
+  ResetLimitCounter();
+  ResetCounter();
+end;
+
+function TSalsa20Engine.ReturnByte(input: Byte): Byte;
+var
+  output: Byte;
+begin
+  if (LimitExceeded()) then
+  begin
+    raise EMaxBytesExceededCryptoLibException.CreateRes(@SMaxByteExceeded);
+  end;
+
+  if (FIndex = 0) then
+  begin
+    GenerateKeyStream(FKeyStream);
+    AdvanceCounter();
+  end;
+
+  output := Byte(FKeyStream[FIndex] xor input);
+  FIndex := (FIndex + 1) and 63;
+
+  result := output;
+end;
+
+class procedure TSalsa20Engine.SalsaCore(rounds: Int32;
+  const input, x: TCryptoLibUInt32Array);
+var
+  x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, x12, x13, x14,
+    x15: UInt32;
+  Idx: Int32;
+begin
+  if (System.Length(input) <> 16) then
+  begin
+    raise EArgumentCryptoLibException.Create('');
+  end;
+  if (System.Length(x) <> 16) then
+  begin
+    raise EArgumentCryptoLibException.Create('');
+  end;
+  if ((rounds mod 2) <> 0) then
+  begin
+    raise EArgumentCryptoLibException.CreateRes(@SRoundsMustbeEven);
+  end;
+
+  x00 := input[0];
+  x01 := input[1];
+  x02 := input[2];
+  x03 := input[3];
+  x04 := input[4];
+  x05 := input[5];
+  x06 := input[6];
+  x07 := input[7];
+  x08 := input[8];
+  x09 := input[9];
+  x10 := input[10];
+  x11 := input[11];
+  x12 := input[12];
+  x13 := input[13];
+  x14 := input[14];
+  x15 := input[15];
+
+  Idx := rounds;
+  while Idx > 0 do
+  begin
+
+    x04 := x04 xor (R((x00 + x12), 7));
+    x08 := x08 xor (R((x04 + x00), 9));
+    x12 := x12 xor (R((x08 + x04), 13));
+    x00 := x00 xor (R((x12 + x08), 18));
+    x09 := x09 xor (R((x05 + x01), 7));
+    x13 := x13 xor (R((x09 + x05), 9));
+    x01 := x01 xor (R((x13 + x09), 13));
+    x05 := x05 xor (R((x01 + x13), 18));
+    x14 := x14 xor (R((x10 + x06), 7));
+    x02 := x02 xor (R((x14 + x10), 9));
+    x06 := x06 xor (R((x02 + x14), 13));
+    x10 := x10 xor (R((x06 + x02), 18));
+    x03 := x03 xor (R((x15 + x11), 7));
+    x07 := x07 xor (R((x03 + x15), 9));
+    x11 := x11 xor (R((x07 + x03), 13));
+    x15 := x15 xor (R((x11 + x07), 18));
+
+    x01 := x01 xor (R((x00 + x03), 7));
+    x02 := x02 xor (R((x01 + x00), 9));
+    x03 := x03 xor (R((x02 + x01), 13));
+    x00 := x00 xor (R((x03 + x02), 18));
+    x06 := x06 xor (R((x05 + x04), 7));
+    x07 := x07 xor (R((x06 + x05), 9));
+    x04 := x04 xor (R((x07 + x06), 13));
+    x05 := x05 xor (R((x04 + x07), 18));
+    x11 := x11 xor (R((x10 + x09), 7));
+    x08 := x08 xor (R((x11 + x10), 9));
+    x09 := x09 xor (R((x08 + x11), 13));
+    x10 := x10 xor (R((x09 + x08), 18));
+    x12 := x12 xor (R((x15 + x14), 7));
+    x13 := x13 xor (R((x12 + x15), 9));
+    x14 := x14 xor (R((x13 + x12), 13));
+    x15 := x15 xor (R((x14 + x13), 18));
+
+    System.Dec(Idx, 2);
+  end;
+
+  x[0] := x00 + input[0];
+  x[1] := x01 + input[1];
+  x[2] := x02 + input[2];
+  x[3] := x03 + input[3];
+  x[4] := x04 + input[4];
+  x[5] := x05 + input[5];
+  x[6] := x06 + input[6];
+  x[7] := x07 + input[7];
+  x[8] := x08 + input[8];
+  x[9] := x09 + input[9];
+  x[10] := x10 + input[10];
+  x[11] := x11 + input[11];
+  x[12] := x12 + input[12];
+  x[13] := x13 + input[13];
+  x[14] := x14 + input[14];
+  x[15] := x15 + input[15];
+
+end;
+
+procedure TSalsa20Engine.SetKey(const keyBytes, ivBytes: TCryptoLibByteArray);
+var
+  tsOff: Int32;
+begin
+  if (keyBytes <> Nil) then
+  begin
+    if not(Byte(System.Length(keyBytes)) in [16, 32]) then
+    begin
+      raise EArgumentCryptoLibException.CreateResFmt(@SInvalidKeySize,
+        [AlgorithmName]);
+    end;
+
+    tsOff := (System.Length(keyBytes) - 16) div 4;
+    FEngineState[0] := TAU_SIGMA[tsOff];
+    FEngineState[5] := TAU_SIGMA[tsOff + 1];
+    FEngineState[10] := TAU_SIGMA[tsOff + 2];
+    FEngineState[15] := TAU_SIGMA[tsOff + 3];
+
+    // Key
+    TConverters.le32_copy(PByte(keyBytes), 0, PCardinal(FEngineState),
+      1 * System.SizeOf(UInt32), 4 * System.SizeOf(UInt32));
+    TConverters.le32_copy(PByte(keyBytes), (System.Length(keyBytes) - 16) *
+      System.SizeOf(Byte), PCardinal(FEngineState), 11 * System.SizeOf(UInt32),
+      4 * System.SizeOf(UInt32));
+  end;
+
+  // IV
+  TConverters.le32_copy(PByte(ivBytes), 0, PCardinal(FEngineState),
+    6 * System.SizeOf(UInt32), 2 * System.SizeOf(UInt32));
+end;
+
+end.

+ 114 - 0
CryptoLib/src/Crypto/Engines/ClpXSalsa20Engine.pas

@@ -0,0 +1,114 @@
+{ *********************************************************************************** }
+{ *                              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 ClpXSalsa20Engine;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpSalsa20Engine,
+  ClpIXSalsa20Engine,
+  ClpConverters,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SNullKeyReInit = '%s Doesn''t Support Re-Init with Null Key';
+  SInvalidKeySize = '%s Requires a 256 bit Key';
+
+type
+  /// <summary>
+  /// Implementation of Daniel J. Bernstein's XSalsa20 stream cipher - Salsa20 with an extended nonce.
+  /// </summary>
+  /// <remarks>
+  /// XSalsa20 requires a 256 bit key, and a 192 bit nonce.
+  /// </remarks>
+  TXSalsa20Engine = class sealed(TSalsa20Engine, IXSalsa20Engine)
+
+  strict protected
+    function GetAlgorithmName: String; override;
+    function GetNonceSize: Int32; override;
+    /// <summary>
+    /// XSalsa20 key generation: process 256 bit input key and 128 bits of the input nonce
+    /// using a core Salsa20 function without input addition to produce 256 bit working key
+    /// and use that with the remaining 64 bits of nonce to initialize a standard Salsa20 engine state.
+    /// </summary>
+    procedure SetKey(const keyBytes, ivBytes: TCryptoLibByteArray); override;
+
+  end;
+
+implementation
+
+{ TXSalsa20Engine }
+
+function TXSalsa20Engine.GetAlgorithmName: String;
+begin
+  result := 'XSalsa20';
+end;
+
+function TXSalsa20Engine.GetNonceSize: Int32;
+begin
+  result := 24;
+end;
+
+procedure TXSalsa20Engine.SetKey(const keyBytes, ivBytes: TCryptoLibByteArray);
+var
+  hsalsa20Out: TCryptoLibUInt32Array;
+begin
+  if (keyBytes = Nil) then
+  begin
+    raise EArgumentCryptoLibException.CreateResFmt(@SNullKeyReInit,
+      [AlgorithmName]);
+  end;
+
+  if (System.Length(keyBytes) <> 32) then
+  begin
+    raise EArgumentCryptoLibException.CreateResFmt(@SInvalidKeySize,
+      [AlgorithmName]);
+  end;
+
+  // Set key for HSalsa20
+  Inherited SetKey(keyBytes, ivBytes);
+
+  // Pack next 64 bits of IV into engine state instead of counter
+  TConverters.le32_copy(PByte(ivBytes), 8 * System.SizeOf(Byte),
+    PCardinal(FEngineState), 8 * System.SizeOf(UInt32),
+    2 * System.SizeOf(UInt32));
+
+  // Process engine state to generate Salsa20 key
+  System.SetLength(hsalsa20Out, System.Length(FEngineState));
+  SalsaCore(20, FEngineState, hsalsa20Out);
+
+  // Set new key, removing addition in last round of salsaCore
+  FEngineState[1] := hsalsa20Out[0] - FEngineState[0];
+  FEngineState[2] := hsalsa20Out[5] - FEngineState[5];
+  FEngineState[3] := hsalsa20Out[10] - FEngineState[10];
+  FEngineState[4] := hsalsa20Out[15] - FEngineState[15];
+
+  FEngineState[11] := hsalsa20Out[6] - FEngineState[6];
+  FEngineState[12] := hsalsa20Out[7] - FEngineState[7];
+  FEngineState[13] := hsalsa20Out[8] - FEngineState[8];
+  FEngineState[14] := hsalsa20Out[9] - FEngineState[9];
+
+  // Last 64 bits of input IV
+  TConverters.le32_copy(PByte(ivBytes), 16 * System.SizeOf(Byte),
+    PCardinal(FEngineState), 6 * System.SizeOf(UInt32),
+    2 * System.SizeOf(UInt32));
+end;
+
+end.

+ 36 - 0
CryptoLib/src/Interfaces/ClpIBufferedStreamCipher.pas

@@ -0,0 +1,36 @@
+{ *********************************************************************************** }
+{ *                              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 ClpIBufferedStreamCipher;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIBufferedCipherBase;
+
+type
+  IBufferedStreamCipher = interface(IBufferedCipherBase)
+
+    ['{F20A1BF7-4AA6-445C-8218-9EA0DF7FC123}']
+
+  end;
+
+implementation
+
+end.

+ 36 - 0
CryptoLib/src/Interfaces/ClpIChaChaEngine.pas

@@ -0,0 +1,36 @@
+{ *********************************************************************************** }
+{ *                              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 ClpIChaChaEngine;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpISalsa20Engine;
+
+type
+
+  IChaChaEngine = interface(ISalsa20Engine)
+    ['{8CD31B82-B157-4A56-B529-E2F1079BADD8}']
+
+  end;
+
+implementation
+
+end.

+ 36 - 0
CryptoLib/src/Interfaces/ClpISalsa20Engine.pas

@@ -0,0 +1,36 @@
+{ *********************************************************************************** }
+{ *                              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 ClpISalsa20Engine;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIStreamCipher;
+
+type
+
+  ISalsa20Engine = interface(IStreamCipher)
+    ['{F60193BE-E5E6-4C7A-9596-5AAF6B8B8E9C}']
+
+  end;
+
+implementation
+
+end.

+ 0 - 10
CryptoLib/src/Interfaces/ClpISignersEncodings.pas

@@ -79,11 +79,6 @@ type
       pos: Int32): TBigInteger;
       pos: Int32): TBigInteger;
     function EncodeValue(const n, x: TBigInteger): IDerInteger;
     function EncodeValue(const n, x: TBigInteger): IDerInteger;
 
 
-    function Decode(const n: TBigInteger; const encoding: TCryptoLibByteArray)
-      : TCryptoLibGenericArray<TBigInteger>;
-
-    function Encode(const n, r, s: TBigInteger): TCryptoLibByteArray;
-
   end;
   end;
 
 
 type
 type
@@ -96,11 +91,6 @@ type
     procedure EncodeValue(const n, x: TBigInteger;
     procedure EncodeValue(const n, x: TBigInteger;
       const buf: TCryptoLibByteArray; off, len: Int32);
       const buf: TCryptoLibByteArray; off, len: Int32);
 
 
-    function Decode(const n: TBigInteger; const encoding: TCryptoLibByteArray)
-      : TCryptoLibGenericArray<TBigInteger>;
-
-    function Encode(const n, r, s: TBigInteger): TCryptoLibByteArray;
-
   end;
   end;
 
 
 type
 type

+ 30 - 14
CryptoLib/src/Interfaces/ClpIStreamCipher.pas

@@ -28,7 +28,7 @@ uses
 type
 type
   /// <remarks>the interface stream ciphers conform to.</remarks>
   /// <remarks>the interface stream ciphers conform to.</remarks>
   IStreamCipher = interface(IInterface)
   IStreamCipher = interface(IInterface)
-   ['{A4366B7A-2BC4-4D92-AEF2-512B621CA746}']
+    ['{A4366B7A-2BC4-4D92-AEF2-512B621CA746}']
 
 
     /// <summary>The name of the algorithm this cipher implements.</summary>
     /// <summary>The name of the algorithm this cipher implements.</summary>
     function GetAlgorithmName: String;
     function GetAlgorithmName: String;
@@ -39,19 +39,35 @@ type
     /// <param name="parameters">The key or other data required by the cipher.</param>
     /// <param name="parameters">The key or other data required by the cipher.</param>
     procedure Init(forEncryption: Boolean; const parameters: ICipherParameters);
     procedure Init(forEncryption: Boolean; const parameters: ICipherParameters);
 
 
-    /// <summary>Indicates whether this cipher can handle partial blocks.</summary>
-    function GetIsPartialBlockOkay: Boolean;
-    property IsPartialBlockOkay: Boolean read GetIsPartialBlockOkay;
-
-    /// <summary>Process a block.</summary>
-    /// <param name="inBuf">The input buffer.</param>
-    /// <param name="inOff">The offset into <paramref>inBuf</paramref> that the input block begins.</param>
-    /// <param name="outBuf">The output buffer.</param>
-    /// <param name="outOff">The offset into <paramref>outBuf</paramref> to write the output block.</param>
-    /// <exception cref="DataLengthException">If input block is wrong size, or outBuf too small.</exception>
-    /// <returns>The number of bytes processed and produced.</returns>
-    function ProcessBlock(inBuf: TCryptoLibByteArray; inOff: Int32;
-      outBuf: TCryptoLibByteArray; outOff: Int32): Int32;
+    /// <summary>encrypt/decrypt a single byte returning the result.</summary>
+    /// <param name="input">the byte to be processed.</param>
+    /// <returns>the result of processing the input byte.</returns>
+    function ReturnByte(input: Byte): Byte;
+
+    /// <summary>
+    /// Process a block of bytes from <c>input</c> putting the result into <c>
+    /// output</c>.
+    /// </summary>
+    /// <param name="inBytes">
+    /// The input byte array.
+    /// </param>
+    /// <param name="inOff">
+    /// The offset into <c>input</c> where the data to be processed starts.
+    /// </param>
+    /// <param name="len">
+    /// The number of bytes to be processed.
+    /// </param>
+    /// <param name="outBytes">
+    /// The output buffer the processed bytes go into.
+    /// </param>
+    /// <param name="outOff">
+    /// The offset into <c>output</c> the processed data starts at.
+    /// </param>
+    /// <exception cref="EDataLengthCryptoLibException">
+    /// If the output buffer is too small.
+    /// </exception>
+    procedure ProcessBytes(const inBytes: TCryptoLibByteArray;
+      inOff, len: Int32; const outBytes: TCryptoLibByteArray; outOff: Int32);
 
 
     /// <summary>
     /// <summary>
     /// Reset the cipher to the same state as it was after the last init (if there was one).
     /// Reset the cipher to the same state as it was after the last init (if there was one).

+ 36 - 0
CryptoLib/src/Interfaces/ClpIXSalsa20Engine.pas

@@ -0,0 +1,36 @@
+{ *********************************************************************************** }
+{ *                              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 ClpIXSalsa20Engine;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpISalsa20Engine;
+
+type
+
+  IXSalsa20Engine = interface(ISalsa20Engine)
+    ['{D95969E8-EAB0-4D2D-8542-40B55925F68D}']
+
+  end;
+
+implementation
+
+end.

+ 35 - 3
CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.lpk

@@ -19,13 +19,13 @@
         </Optimizations>
         </Optimizations>
       </CodeGeneration>
       </CodeGeneration>
     </CompilerOptions>
     </CompilerOptions>
-    <Description Value="CryptoLib4Pascal is a Cryptographic Package for Delphi/FreePascal Compilers that provides at the moment support for creating, signing and verifying DSA, ECDSA, ECNR and ECSchnorr signatures using various curves and hashes, AES, Blowfish, Speck Encryption and Decryption (With various modes and paddings) and ECIES."/>
+    <Description Value="CryptoLib4Pascal is a Cryptographic Package for Delphi/FreePascal Compilers that provides at the moment support for creating, signing and verifying DSA, ECDSA, ECNR and ECSchnorr signatures using various curves and hashes, AES, Blowfish and Speck Block Encryption and Decryption (With various modes and paddings), Salsa20, XSalsa20, ChaCha Stream Ciphers and ECIES."/>
     <License Value="MIT License                          
     <License Value="MIT License                          
 
 
  Acknowledgements: 
  Acknowledgements: 
 Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the development of this library "/>
 Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the development of this library "/>
-    <Version Major="3"/>
-    <Files Count="271">
+    <Version Major="3" Minor="1"/>
+    <Files Count="279">
       <Item1>
       <Item1>
         <Filename Value="..\..\Asn1\ClpOidTokenizer.pas"/>
         <Filename Value="..\..\Asn1\ClpOidTokenizer.pas"/>
         <UnitName Value="ClpOidTokenizer"/>
         <UnitName Value="ClpOidTokenizer"/>
@@ -1112,6 +1112,38 @@ Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the devel
         <Filename Value="..\..\Crypto\Engines\ClpSpeckEngine.pas"/>
         <Filename Value="..\..\Crypto\Engines\ClpSpeckEngine.pas"/>
         <UnitName Value="ClpSpeckEngine"/>
         <UnitName Value="ClpSpeckEngine"/>
       </Item271>
       </Item271>
+      <Item272>
+        <Filename Value="..\..\Interfaces\ClpIBufferedStreamCipher.pas"/>
+        <UnitName Value="ClpIBufferedStreamCipher"/>
+      </Item272>
+      <Item273>
+        <Filename Value="..\..\Interfaces\ClpIChaChaEngine.pas"/>
+        <UnitName Value="ClpIChaChaEngine"/>
+      </Item273>
+      <Item274>
+        <Filename Value="..\..\Interfaces\ClpIXSalsa20Engine.pas"/>
+        <UnitName Value="ClpIXSalsa20Engine"/>
+      </Item274>
+      <Item275>
+        <Filename Value="..\..\Interfaces\ClpISalsa20Engine.pas"/>
+        <UnitName Value="ClpISalsa20Engine"/>
+      </Item275>
+      <Item276>
+        <Filename Value="..\..\Crypto\ClpBufferedStreamCipher.pas"/>
+        <UnitName Value="ClpBufferedStreamCipher"/>
+      </Item276>
+      <Item277>
+        <Filename Value="..\..\Crypto\Engines\ClpSalsa20Engine.pas"/>
+        <UnitName Value="ClpSalsa20Engine"/>
+      </Item277>
+      <Item278>
+        <Filename Value="..\..\Crypto\Engines\ClpXSalsa20Engine.pas"/>
+        <UnitName Value="ClpXSalsa20Engine"/>
+      </Item278>
+      <Item279>
+        <Filename Value="..\..\Crypto\Engines\ClpChaChaEngine.pas"/>
+        <UnitName Value="ClpChaChaEngine"/>
+      </Item279>
     </Files>
     </Files>
     <RequiredPkgs Count="3">
     <RequiredPkgs Count="3">
       <Item1>
       <Item1>

+ 4 - 1
CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.pas

@@ -94,7 +94,10 @@ uses
   ClpIAsn1Objects, ClpBlockCipherModes, ClpECCurveConstants, 
   ClpIAsn1Objects, ClpBlockCipherModes, ClpECCurveConstants, 
   ClpIBlockCipherModes, ClpIPaddingModes, ClpISecP256K1Custom, 
   ClpIBlockCipherModes, ClpIPaddingModes, ClpISecP256K1Custom, 
   ClpISecP256R1Custom, ClpISecP384R1Custom, ClpISecP521R1Custom, 
   ClpISecP256R1Custom, ClpISecP384R1Custom, ClpISecP521R1Custom, 
-  ClpISecT283Custom, ClpPaddingModes, ClpIECC, ClpISpeckEngine, ClpSpeckEngine;
+  ClpISecT283Custom, ClpPaddingModes, ClpIECC, ClpISpeckEngine, 
+  ClpSpeckEngine, ClpIBufferedStreamCipher, ClpIChaChaEngine, 
+  ClpIXSalsa20Engine, ClpISalsa20Engine, ClpBufferedStreamCipher, 
+  ClpSalsa20Engine, ClpXSalsa20Engine, ClpChaChaEngine;
 
 
 implementation
 implementation
 
 

+ 26 - 1
CryptoLib/src/Security/ClpCipherUtilities.pas

@@ -33,16 +33,21 @@ uses
   ClpIBlockCipherModes,
   ClpIBlockCipherModes,
   ClpBufferedBlockCipher,
   ClpBufferedBlockCipher,
   ClpIBufferedBlockCipher,
   ClpIBufferedBlockCipher,
+  ClpBufferedStreamCipher,
+  ClpIBufferedStreamCipher,
   ClpPaddedBufferedBlockCipher,
   ClpPaddedBufferedBlockCipher,
   ClpIPaddedBufferedBlockCipher,
   ClpIPaddedBufferedBlockCipher,
   ClpNistObjectIdentifiers,
   ClpNistObjectIdentifiers,
   ClpIAsn1Objects,
   ClpIAsn1Objects,
   ClpIBufferedCipher,
   ClpIBufferedCipher,
   ClpIBlockCipher,
   ClpIBlockCipher,
+  ClpIStreamCipher,
   ClpAesEngine,
   ClpAesEngine,
   ClpIAesEngine,
   ClpIAesEngine,
   ClpBlowfishEngine,
   ClpBlowfishEngine,
   ClpIBlowfishEngine,
   ClpIBlowfishEngine,
+  ClpSalsa20Engine,
+  ClpISalsa20Engine,
   ClpIBlockCipherPadding;
   ClpIBlockCipherPadding;
 
 
 resourcestring
 resourcestring
@@ -51,6 +56,8 @@ resourcestring
   SUnRecognizedCipher = '"Cipher " %s Not Recognised.';
   SUnRecognizedCipher = '"Cipher " %s Not Recognised.';
   SSICModeWarning =
   SSICModeWarning =
     'Warning: SIC-Mode Can Become a TwoTime-Pad if the Blocksize of the Cipher is Too Small. Use a Cipher With a Block Size of at Least 128 bits (e.g. AES)';
     'Warning: SIC-Mode Can Become a TwoTime-Pad if the Blocksize of the Cipher is Too Small. Use a Cipher With a Block Size of at Least 128 bits (e.g. AES)';
+  SModeAndPaddingNotNeededStreamCipher =
+    'Modes and Paddings Not Used for Stream Ciphers';
 
 
 type
 type
 
 
@@ -63,7 +70,7 @@ type
 
 
   type
   type
 {$SCOPEDENUMS ON}
 {$SCOPEDENUMS ON}
-    TCipherAlgorithm = (AES, BLOWFISH);
+    TCipherAlgorithm = (AES, BLOWFISH, SALSA20);
     TCipherMode = (NONE, CBC, CFB, CTR, ECB, OFB, SIC);
     TCipherMode = (NONE, CBC, CFB, CTR, ECB, OFB, SIC);
     TCipherPadding = (NOPADDING, ISO10126PADDING, ISO10126D2PADDING,
     TCipherPadding = (NOPADDING, ISO10126PADDING, ISO10126D2PADDING,
       ISO10126_2PADDING, ISO7816_4PADDING, ISO9797_1PADDING, PKCS5,
       ISO10126_2PADDING, ISO7816_4PADDING, ISO9797_1PADDING, PKCS5,
@@ -191,6 +198,7 @@ var
   cipherPadding: TCipherPadding;
   cipherPadding: TCipherPadding;
   cipherMode: TCipherMode;
   cipherMode: TCipherMode;
   blockCipher: IBlockCipher;
   blockCipher: IBlockCipher;
+  streamCipher: IStreamCipher;
   padding: IBlockCipherPadding;
   padding: IBlockCipherPadding;
 begin
 begin
   if (algorithm = '') then
   if (algorithm = '') then
@@ -230,6 +238,10 @@ begin
     TCipherAlgorithm.BLOWFISH:
     TCipherAlgorithm.BLOWFISH:
       begin
       begin
         blockCipher := TBlowfishEngine.Create() as IBlowfishEngine;
         blockCipher := TBlowfishEngine.Create() as IBlowfishEngine;
+      end;
+    TCipherAlgorithm.SALSA20:
+      begin
+        streamCipher := TSalsa20Engine.Create() as ISalsa20Engine;
       end
       end
   else
   else
     begin
     begin
@@ -238,6 +250,19 @@ begin
     end;
     end;
   end;
   end;
 
 
+  if (streamCipher <> Nil) then
+  begin
+    if (System.Length(parts) > 1) then
+    begin
+      raise EArgumentCryptoLibException.CreateRes
+        (@SModeAndPaddingNotNeededStreamCipher);
+    end;
+
+    Result := TBufferedStreamCipher.Create(streamCipher)
+      as IBufferedStreamCipher;
+    Exit;
+  end;
+
   padded := true;
   padded := true;
   padding := Nil;
   padding := Nil;
 
 

+ 3 - 1
CryptoLib/src/Security/ClpGeneratorUtilities.pas

@@ -196,6 +196,8 @@ begin
 
 
   AddKgAlgorithm('BLOWFISH', ['1.3.6.1.4.1.3029.1.2']);
   AddKgAlgorithm('BLOWFISH', ['1.3.6.1.4.1.3029.1.2']);
 
 
+  AddKgAlgorithm('SALSA20', []);
+
   //
   //
   // HMac key generators
   // HMac key generators
   //
   //
@@ -244,7 +246,7 @@ begin
   AddKpgAlgorithm('ECDSA', []);
   AddKpgAlgorithm('ECDSA', []);
 
 
   AddDefaultKeySizeEntries(128, ['AES128', 'BLOWFISH', 'HMACMD2', 'HMACMD4',
   AddDefaultKeySizeEntries(128, ['AES128', 'BLOWFISH', 'HMACMD2', 'HMACMD4',
-    'HMACMD5', 'HMACRIPEMD128']);
+    'HMACMD5', 'HMACRIPEMD128', 'SALSA20']);
   AddDefaultKeySizeEntries(160, ['HMACRIPEMD160', 'HMACSHA1']);
   AddDefaultKeySizeEntries(160, ['HMACRIPEMD160', 'HMACSHA1']);
   AddDefaultKeySizeEntries(192, ['AES', 'AES192', 'HMACTIGER']);
   AddDefaultKeySizeEntries(192, ['AES', 'AES192', 'HMACTIGER']);
   AddDefaultKeySizeEntries(224, ['HMACSHA3-224', 'HMACSHA224',
   AddDefaultKeySizeEntries(224, ['HMACSHA3-224', 'HMACSHA224',

+ 1 - 0
CryptoLib/src/Security/ClpParameterUtilities.pas

@@ -131,6 +131,7 @@ begin
     TNistObjectIdentifiers.IdAes256Cfb.ID,
     TNistObjectIdentifiers.IdAes256Cfb.ID,
     TNistObjectIdentifiers.IdAes256Ecb.ID,
     TNistObjectIdentifiers.IdAes256Ecb.ID,
     TNistObjectIdentifiers.IdAes256Ofb.ID]);
     TNistObjectIdentifiers.IdAes256Ofb.ID]);
+  AddAlgorithm('SALSA20', []);
 
 
   AddBasicIVSizeEntries(16, ['AES', 'AES128', 'AES192', 'AES256']);
   AddBasicIVSizeEntries(16, ['AES', 'AES128', 'AES192', 'AES256']);
 
 

+ 1 - 0
CryptoLib/src/Utils/ClpCryptoLibTypes.pas

@@ -55,6 +55,7 @@ type
   ESecurityUtilityCryptoLibException = class(ECryptoLibException);
   ESecurityUtilityCryptoLibException = class(ECryptoLibException);
   EAccessCryptoLibException = class(ECryptoLibException);
   EAccessCryptoLibException = class(ECryptoLibException);
   EDataLengthCryptoLibException = class(ECryptoLibException);
   EDataLengthCryptoLibException = class(ECryptoLibException);
+  EMaxBytesExceededCryptoLibException = class(ECryptoLibException);
   EOutputLengthCryptoLibException = class(ECryptoLibException);
   EOutputLengthCryptoLibException = class(ECryptoLibException);
   EBadBlockCryptoLibException = class(ECryptoLibException);
   EBadBlockCryptoLibException = class(ECryptoLibException);