diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2016-01-17 14:02:18 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2016-01-17 14:02:18 +0700 |
commit | 715d196d48d494f7ab2f05c5f8a06bc554d9dbc3 (patch) | |
tree | 1ff49e296ba78946a485a0cd94288959664e3575 | |
parent | Fix re-init bug in HC128/256 engines (diff) | |
download | BouncyCastle.NET-ed25519-715d196d48d494f7ab2f05c5f8a06bc554d9dbc3.tar.xz |
Support for re-init in Salsa family
- simplify SetKey methods - avoid non-private mutable static state (sigma/tau)
-rw-r--r-- | crypto/src/crypto/engines/ChaChaEngine.cs | 63 | ||||
-rw-r--r-- | crypto/src/crypto/engines/Salsa20Engine.cs | 115 | ||||
-rw-r--r-- | crypto/src/crypto/engines/XSalsa20Engine.cs | 19 | ||||
-rw-r--r-- | crypto/src/crypto/util/Pack.cs | 11 |
4 files changed, 93 insertions, 115 deletions
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]; |