diff --git a/crypto/src/crypto/engines/ChaChaEngine.cs b/crypto/src/crypto/engines/ChaChaEngine.cs
index 46b59ed2e..8720504cd 100644
--- a/crypto/src/crypto/engines/ChaChaEngine.cs
+++ b/crypto/src/crypto/engines/ChaChaEngine.cs
@@ -1,4 +1,5 @@
using System;
+
using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
@@ -9,7 +10,6 @@ namespace Org.BouncyCastle.Crypto.Engines
public class ChaChaEngine
: Salsa20Engine
{
-
/// <summary>
/// Creates a 20 rounds ChaCha engine.
/// </summary>
@@ -46,45 +46,20 @@ namespace Org.BouncyCastle.Crypto.Engines
protected override void SetKey(byte[] keyBytes, byte[] ivBytes)
{
- if ((keyBytes.Length != 16) && (keyBytes.Length != 32))
- {
- throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key");
- }
-
- int offset = 0;
- byte[] constants;
-
- // Key
- engineState[4] = Pack.LE_To_UInt32(keyBytes, 0);
- engineState[5] = Pack.LE_To_UInt32(keyBytes, 4);
- engineState[6] = Pack.LE_To_UInt32(keyBytes, 8);
- engineState[7] = Pack.LE_To_UInt32(keyBytes, 12);
-
- if (keyBytes.Length == 32)
- {
- constants = sigma;
- offset = 16;
- } else
- {
- constants = tau;
- }
+ if (keyBytes != null)
+ {
+ if ((keyBytes.Length != 16) && (keyBytes.Length != 32))
+ throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key");
- engineState[8] = Pack.LE_To_UInt32(keyBytes, offset);
- engineState[9] = Pack.LE_To_UInt32(keyBytes, offset + 4);
- engineState[10] = Pack.LE_To_UInt32(keyBytes, offset + 8);
- engineState[11] = Pack.LE_To_UInt32(keyBytes, offset + 12);
+ PackTauOrSigma(keyBytes.Length, engineState, 0);
- engineState[0] = Pack.LE_To_UInt32(constants, 0);
- engineState[1] = Pack.LE_To_UInt32(constants, 4);
- engineState[2] = Pack.LE_To_UInt32(constants, 8);
- engineState[3] = Pack.LE_To_UInt32(constants, 12);
-
- // Counter
- engineState[12] = engineState[13] = 0;
+ // Key
+ Pack.LE_To_UInt32(keyBytes, 0, engineState, 4, 4);
+ Pack.LE_To_UInt32(keyBytes, keyBytes.Length - 16, engineState, 8, 4);
+ }
- // IV
- engineState[14] = Pack.LE_To_UInt32(ivBytes, 0);
- engineState[15] = Pack.LE_To_UInt32(ivBytes, 4);
+ // IV
+ Pack.LE_To_UInt32(ivBytes, 0, engineState, 14, 2);
}
protected override void GenerateKeyStream(byte[] output)
@@ -94,24 +69,21 @@ namespace Org.BouncyCastle.Crypto.Engines
}
/// <summary>
- /// ChacCha function.
+ /// 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>
internal static void ChachaCore(int rounds, uint[] input, uint[] x)
{
- if (input.Length != 16) {
+ if (input.Length != 16)
throw new ArgumentException();
- }
- if (x.Length != 16) {
+ if (x.Length != 16)
throw new ArgumentException();
- }
- if (rounds % 2 != 0) {
+ if (rounds % 2 != 0)
throw new ArgumentException("Number of rounds must be even");
- }
- uint x00 = input[ 0];
+ uint x00 = input[ 0];
uint x01 = input[ 1];
uint x02 = input[ 2];
uint x03 = input[ 3];
@@ -183,4 +155,3 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
}
-
diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs
index 9b27dc7b4..182eacd71 100644
--- a/crypto/src/crypto/engines/Salsa20Engine.cs
+++ b/crypto/src/crypto/engines/Salsa20Engine.cs
@@ -18,7 +18,19 @@ namespace Org.BouncyCastle.Crypto.Engines
/** Constants */
private const int StateSize = 16; // 16, 32 bit ints = 64 bytes
- protected readonly static byte[]
+ private readonly static uint[] TAU_SIGMA = Pack.LE_To_UInt32(Strings.ToAsciiByteArray("expand 16-byte k" + "expand 32-byte k"), 0, 8);
+
+ internal void PackTauOrSigma(int keyLength, uint[] state, int stateOffset)
+ {
+ int tsOff = (keyLength - 16) / 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];
+ }
+
+ [Obsolete]
+ protected readonly static byte[]
sigma = Strings.ToAsciiByteArray("expand 32-byte k"),
tau = Strings.ToAsciiByteArray("expand 16-byte k");
@@ -72,22 +84,31 @@ namespace Org.BouncyCastle.Crypto.Engines
*/
ParametersWithIV ivParams = parameters as ParametersWithIV;
-
if (ivParams == null)
throw new ArgumentException(AlgorithmName + " Init requires an IV", "parameters");
byte[] iv = ivParams.GetIV();
-
if (iv == null || iv.Length != NonceSize)
throw new ArgumentException(AlgorithmName + " requires exactly " + NonceSize + " bytes of IV");
- KeyParameter key = ivParams.Parameters as KeyParameter;
-
- if (key == null)
- throw new ArgumentException(AlgorithmName + " Init requires a key", "parameters");
-
- SetKey(key.GetKey(), iv);
- Reset();
+ ICipherParameters keyParam = ivParams.Parameters;
+ if (keyParam == null)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " KeyParameter can not be null for first initialisation");
+
+ SetKey(null, iv);
+ }
+ else if (keyParam is KeyParameter)
+ {
+ SetKey(((KeyParameter)keyParam).GetKey(), iv);
+ }
+ else
+ {
+ throw new ArgumentException(AlgorithmName + " Init parameters must contain a KeyParameter (or null for re-init)");
+ }
+
+ Reset();
initialised = true;
}
@@ -98,7 +119,8 @@ namespace Org.BouncyCastle.Crypto.Engines
public virtual string AlgorithmName
{
- get {
+ get
+ {
string name = "Salsa20";
if (rounds != DEFAULT_ROUNDS)
{
@@ -178,45 +200,27 @@ namespace Org.BouncyCastle.Crypto.Engines
protected virtual void SetKey(byte[] keyBytes, byte[] ivBytes)
{
- if ((keyBytes.Length != 16) && (keyBytes.Length != 32)) {
- throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key");
- }
-
- int offset = 0;
- byte[] constants;
-
- // Key
- engineState[1] = Pack.LE_To_UInt32(keyBytes, 0);
- engineState[2] = Pack.LE_To_UInt32(keyBytes, 4);
- engineState[3] = Pack.LE_To_UInt32(keyBytes, 8);
- engineState[4] = Pack.LE_To_UInt32(keyBytes, 12);
-
- if (keyBytes.Length == 32)
- {
- constants = sigma;
- offset = 16;
- }
- else
- {
- constants = tau;
- }
-
- engineState[11] = Pack.LE_To_UInt32(keyBytes, offset);
- engineState[12] = Pack.LE_To_UInt32(keyBytes, offset + 4);
- engineState[13] = Pack.LE_To_UInt32(keyBytes, offset + 8);
- engineState[14] = Pack.LE_To_UInt32(keyBytes, offset + 12);
- engineState[0] = Pack.LE_To_UInt32(constants, 0);
- engineState[5] = Pack.LE_To_UInt32(constants, 4);
- engineState[10] = Pack.LE_To_UInt32(constants, 8);
- engineState[15] = Pack.LE_To_UInt32(constants, 12);
-
- // IV
- engineState[6] = Pack.LE_To_UInt32(ivBytes, 0);
- engineState[7] = Pack.LE_To_UInt32(ivBytes, 4);
- ResetCounter();
- }
-
- protected virtual void GenerateKeyStream(byte[] output)
+ if (keyBytes != null)
+ {
+ if ((keyBytes.Length != 16) && (keyBytes.Length != 32))
+ throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key");
+
+ int tsOff = (keyBytes.Length - 16) / 4;
+ engineState[0] = TAU_SIGMA[tsOff];
+ engineState[5] = TAU_SIGMA[tsOff + 1];
+ engineState[10] = TAU_SIGMA[tsOff + 2];
+ engineState[15] = TAU_SIGMA[tsOff + 3];
+
+ // Key
+ Pack.LE_To_UInt32(keyBytes, 0, engineState, 1, 4);
+ Pack.LE_To_UInt32(keyBytes, keyBytes.Length - 16, engineState, 11, 4);
+ }
+
+ // IV
+ Pack.LE_To_UInt32(ivBytes, 0, engineState, 6, 2);
+ }
+
+ protected virtual void GenerateKeyStream(byte[] output)
{
SalsaCore(rounds, engineState, x);
Pack.UInt32_To_LE(x, output, 0);
@@ -224,17 +228,14 @@ namespace Org.BouncyCastle.Crypto.Engines
internal static void SalsaCore(int rounds, uint[] input, uint[] x)
{
- if (input.Length != 16) {
+ if (input.Length != 16)
throw new ArgumentException();
- }
- if (x.Length != 16) {
+ if (x.Length != 16)
throw new ArgumentException();
- }
- if (rounds % 2 != 0) {
+ if (rounds % 2 != 0)
throw new ArgumentException("Number of rounds must be even");
- }
- uint x00 = input[ 0];
+ uint x00 = input[ 0];
uint x01 = input[ 1];
uint x02 = input[ 2];
uint x03 = input[ 3];
diff --git a/crypto/src/crypto/engines/XSalsa20Engine.cs b/crypto/src/crypto/engines/XSalsa20Engine.cs
index 2898b46c8..50c51a82f 100644
--- a/crypto/src/crypto/engines/XSalsa20Engine.cs
+++ b/crypto/src/crypto/engines/XSalsa20Engine.cs
@@ -30,17 +30,17 @@ namespace Org.BouncyCastle.Crypto.Engines
/// </summary>
protected override void SetKey(byte[] keyBytes, byte[] ivBytes)
{
- if (keyBytes.Length != 32)
- {
+ if (keyBytes == null)
+ throw new ArgumentException(AlgorithmName + " doesn't support re-init with null key");
+
+ if (keyBytes.Length != 32)
throw new ArgumentException(AlgorithmName + " requires a 256 bit key");
- }
- // Set key for HSalsa20
+ // Set key for HSalsa20
base.SetKey(keyBytes, ivBytes);
// Pack next 64 bits of IV into engine state instead of counter
- engineState[8] = Pack.LE_To_UInt32(ivBytes, 8);
- engineState[9] = Pack.LE_To_UInt32(ivBytes, 12);
+ Pack.LE_To_UInt32(ivBytes, 8, engineState, 8, 2);
// Process engine state to generate Salsa20 key
uint[] hsalsa20Out = new uint[engineState.Length];
@@ -58,12 +58,7 @@ namespace Org.BouncyCastle.Crypto.Engines
engineState[14] = hsalsa20Out[9] - engineState[9];
// Last 64 bits of input IV
- engineState[6] = Pack.LE_To_UInt32(ivBytes, 16);
- engineState[7] = Pack.LE_To_UInt32(ivBytes, 20);
-
- // Counter reset
- ResetCounter();
+ Pack.LE_To_UInt32(ivBytes, 16, engineState, 6, 2);
}
}
}
-
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index dc00ab450..96f293d72 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -255,6 +255,17 @@ namespace Org.BouncyCastle.Crypto.Utilities
}
}
+ internal static uint[] LE_To_UInt32(byte[] bs, int off, int count)
+ {
+ uint[] ns = new uint[count];
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ ns[i] = LE_To_UInt32(bs, off);
+ off += 4;
+ }
+ return ns;
+ }
+
internal static byte[] UInt64_To_LE(ulong n)
{
byte[] bs = new byte[8];
|