diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2013-11-01 18:46:29 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2013-11-01 18:46:29 +0700 |
commit | c1203484971419bc08b1ae937ee439aef9161b4d (patch) | |
tree | 8120ae47d99573e9ccbe988445a68279218449c3 /crypto | |
parent | added obligatory Inc. (diff) | |
parent | Use xmldoc for documentation of Salsa20/XSalsa20/ChaCha (diff) | |
download | BouncyCastle.NET-ed25519-c1203484971419bc08b1ae937ee439aef9161b4d.tar.xz |
Merge branch 'feature/latin-dances' of git://github.com/timw/bc-csharp
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/crypto.mdp | 4 | ||||
-rw-r--r-- | crypto/src/crypto/engines/ChaChaEngine.cs | 189 | ||||
-rw-r--r-- | crypto/src/crypto/engines/Salsa20Engine.cs | 277 | ||||
-rw-r--r-- | crypto/src/crypto/engines/XSalsa20Engine.cs | 71 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/ChaChaTest.cs | 318 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/RegressionTest.cs | 4 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/Salsa20Test.cs | 69 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/XSalsa20Test.cs | 183 |
8 files changed, 1006 insertions, 109 deletions
diff --git a/crypto/crypto.mdp b/crypto/crypto.mdp index 8152a40a9..483491488 100644 --- a/crypto/crypto.mdp +++ b/crypto/crypto.mdp @@ -2297,6 +2297,10 @@ <File subtype="Code" buildaction="Compile" name="src/bcpg/sig/RevocationReason.cs" /> <File subtype="Code" buildaction="Compile" name="src/bcpg/sig/RevocationReasonTags.cs" /> <File subtype="Code" buildaction="Compile" name="src/bcpg/sig/RevocationKeyTags.cs" /> + <File subtype="Code" buildaction="Compile" name="src/crypto/engines/ChaChaEngine.cs" /> + <File subtype="Code" buildaction="Compile" name="src/crypto/engines/XSalsa20Engine.cs" /> + <File subtype="Code" buildaction="Compile" name="test/src/crypto/test/ChaChaTest.cs" /> + <File subtype="Code" buildaction="Compile" name="test/src/crypto/test/XSalsa20Test.cs" /> </Contents> <References> <ProjectReference type="Assembly" localcopy="True" refto="test/lib/nunit.core.dll" /> diff --git a/crypto/src/crypto/engines/ChaChaEngine.cs b/crypto/src/crypto/engines/ChaChaEngine.cs new file mode 100644 index 000000000..f4a7b8fe1 --- /dev/null +++ b/crypto/src/crypto/engines/ChaChaEngine.cs @@ -0,0 +1,189 @@ +using System; +using Org.BouncyCastle.Crypto.Utilities; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /// <summary> + /// Implementation of Daniel J. Bernstein's ChaCha stream cipher. + /// </summary> + public class ChaChaEngine + : Salsa20Engine + { + + /// <summary> + /// Creates a 20 rounds ChaCha engine. + /// </summary> + public ChaChaEngine() + { + } + + /// <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> + public ChaChaEngine(int rounds) + : base(rounds) + { + } + + public override string AlgorithmName + { + get { return "ChaCha" + rounds; } + } + + protected override void AdvanceCounter() + { + if (++engineState[12] == 0) + { + ++engineState[13]; + } + } + + protected override void ResetCounter() + { + engineState[12] = engineState[13] = 0; + } + + 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; + } + + 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); + + 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; + + // IV + engineState[14] = Pack.LE_To_UInt32(ivBytes, 0); + engineState[15] = Pack.LE_To_UInt32(ivBytes, 4); + } + + protected override void GenerateKeyStream(byte[] output) + { + ChachaCore(rounds, engineState, x); + Pack.UInt32_To_LE(x, output, 0); + } + + /// <summary> + /// ChacCha 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) { + throw new ArgumentException(); + } + if (x.Length != 16) { + throw new ArgumentException(); + } + if (rounds % 2 != 0) { + throw new ArgumentException("Number of rounds must be even"); + } + + uint x00 = input[ 0]; + uint x01 = input[ 1]; + uint x02 = input[ 2]; + uint x03 = input[ 3]; + uint x04 = input[ 4]; + uint x05 = input[ 5]; + uint x06 = input[ 6]; + uint x07 = input[ 7]; + uint x08 = input[ 8]; + uint x09 = input[ 9]; + uint x10 = input[10]; + uint x11 = input[11]; + uint x12 = input[12]; + uint x13 = input[13]; + uint x14 = input[14]; + uint x15 = input[15]; + + for (int i = rounds; i > 0; i -= 2) + { + x00 += x04; x12 = R(x12 ^ x00, 16); + x08 += x12; x04 = R(x04 ^ x08, 12); + x00 += x04; x12 = R(x12 ^ x00, 8); + x08 += x12; x04 = R(x04 ^ x08, 7); + x01 += x05; x13 = R(x13 ^ x01, 16); + x09 += x13; x05 = R(x05 ^ x09, 12); + x01 += x05; x13 = R(x13 ^ x01, 8); + x09 += x13; x05 = R(x05 ^ x09, 7); + x02 += x06; x14 = R(x14 ^ x02, 16); + x10 += x14; x06 = R(x06 ^ x10, 12); + x02 += x06; x14 = R(x14 ^ x02, 8); + x10 += x14; x06 = R(x06 ^ x10, 7); + x03 += x07; x15 = R(x15 ^ x03, 16); + x11 += x15; x07 = R(x07 ^ x11, 12); + x03 += x07; x15 = R(x15 ^ x03, 8); + x11 += x15; x07 = R(x07 ^ x11, 7); + x00 += x05; x15 = R(x15 ^ x00, 16); + x10 += x15; x05 = R(x05 ^ x10, 12); + x00 += x05; x15 = R(x15 ^ x00, 8); + x10 += x15; x05 = R(x05 ^ x10, 7); + x01 += x06; x12 = R(x12 ^ x01, 16); + x11 += x12; x06 = R(x06 ^ x11, 12); + x01 += x06; x12 = R(x12 ^ x01, 8); + x11 += x12; x06 = R(x06 ^ x11, 7); + x02 += x07; x13 = R(x13 ^ x02, 16); + x08 += x13; x07 = R(x07 ^ x08, 12); + x02 += x07; x13 = R(x13 ^ x02, 8); + x08 += x13; x07 = R(x07 ^ x08, 7); + x03 += x04; x14 = R(x14 ^ x03, 16); + x09 += x14; x04 = R(x04 ^ x09, 12); + x03 += x04; x14 = R(x14 ^ x03, 8); + x09 += x14; x04 = R(x04 ^ x09, 7); + + } + + 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]; + } + + } + +} + diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs index 7d68deab1..81884d603 100644 --- a/crypto/src/crypto/engines/Salsa20Engine.cs +++ b/crypto/src/crypto/engines/Salsa20Engine.cs @@ -7,44 +7,60 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Engines { - /** - * Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005 - */ + /// <summary> + /// Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005 + /// </summary> public class Salsa20Engine : IStreamCipher { + public static readonly int DEFAULT_ROUNDS = 20; + /** Constants */ private const int StateSize = 16; // 16, 32 bit ints = 64 bytes - private readonly static byte[] + protected readonly static byte[] sigma = Strings.ToAsciiByteArray("expand 32-byte k"), tau = Strings.ToAsciiByteArray("expand 16-byte k"); + protected int rounds; + /* * variables to hold the state of the engine * during encryption and decryption */ - private int index = 0; - private uint[] engineState = new uint[StateSize]; // state - private uint[] x = new uint[StateSize]; // internal buffer - private byte[] keyStream = new byte[StateSize * 4], // expanded state, 64 bytes - workingKey = null, - workingIV = null; - private bool initialised = false; + private int index = 0; + internal uint[] engineState = new uint[StateSize]; // state + internal uint[] x = new uint[StateSize]; // internal buffer + private byte[] keyStream = new byte[StateSize * 4]; // expanded state, 64 bytes + private bool initialised = false; /* * internal counter */ private uint cW0, cW1, cW2; - /** - * initialise a Salsa20 cipher. - * - * @param forEncryption whether or not we are for encryption. - * @param params the parameters required to set up the cipher. - * @exception ArgumentException if the params argument is - * inappropriate. - */ + /// <summary> + /// Creates a 20 round Salsa20 engine. + /// </summary> + public Salsa20Engine() + : this(DEFAULT_ROUNDS) + { + } + + /// <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> + public Salsa20Engine(int rounds) + { + if (rounds <= 0 || (rounds & 1) != 0) + { + throw new ArgumentException("'rounds' must be a positive, even number"); + } + + this.rounds = rounds; + } + public void Init( bool forEncryption, ICipherParameters parameters) @@ -58,27 +74,38 @@ namespace Org.BouncyCastle.Crypto.Engines ParametersWithIV ivParams = parameters as ParametersWithIV; if (ivParams == null) - throw new ArgumentException("Salsa20 Init requires an IV", "parameters"); + throw new ArgumentException(AlgorithmName + " Init requires an IV", "parameters"); byte[] iv = ivParams.GetIV(); - if (iv == null || iv.Length != 8) - throw new ArgumentException("Salsa20 requires exactly 8 bytes of IV"); + 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("Salsa20 Init requires a key", "parameters"); + throw new ArgumentException(AlgorithmName + " Init requires a key", "parameters"); - workingKey = key.GetKey(); - workingIV = iv; + SetKey(key.GetKey(), iv); + Reset(); + initialised = true; + } - SetKey(workingKey, workingIV); + protected virtual int NonceSize + { + get { return 8; } } - public string AlgorithmName + public virtual string AlgorithmName { - get { return "Salsa20"; } + get { + string name = "Salsa20"; + if (rounds != DEFAULT_ROUNDS) + { + name += "/" + rounds; + } + return name; + } } public byte ReturnByte( @@ -92,11 +119,7 @@ namespace Org.BouncyCastle.Crypto.Engines if (index == 0) { GenerateKeyStream(keyStream); - - if (++engineState[8] == 0) - { - ++engineState[9]; - } + AdvanceCounter(); } byte output = (byte)(keyStream[index] ^ input); @@ -105,6 +128,14 @@ namespace Org.BouncyCastle.Crypto.Engines return output; } + protected virtual void AdvanceCounter() + { + if (++engineState[8] == 0) + { + ++engineState[9]; + } + } + public void ProcessBytes( byte[] inBytes, int inOff, @@ -137,11 +168,7 @@ namespace Org.BouncyCastle.Crypto.Engines if (index == 0) { GenerateKeyStream(keyStream); - - if (++engineState[8] == 0) - { - ++engineState[9]; - } + AdvanceCounter(); } outBytes[i+outOff] = (byte)(keyStream[index]^inBytes[i+inOff]); index = (index + 1) & 63; @@ -150,28 +177,32 @@ namespace Org.BouncyCastle.Crypto.Engines public void Reset() { - SetKey(workingKey, workingIV); + index = 0; + ResetLimitCounter(); + ResetCounter(); } - // Private implementation + protected virtual void ResetCounter() + { + engineState[8] = engineState[9] = 0; + } - private void SetKey(byte[] keyBytes, byte[] ivBytes) + protected virtual void SetKey(byte[] keyBytes, byte[] ivBytes) { - workingKey = keyBytes; - workingIV = ivBytes; + if ((keyBytes.Length != 16) && (keyBytes.Length != 32)) { + throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key"); + } - index = 0; - ResetCounter(); int offset = 0; byte[] constants; // Key - engineState[1] = Pack.LE_To_UInt32(workingKey, 0); - engineState[2] = Pack.LE_To_UInt32(workingKey, 4); - engineState[3] = Pack.LE_To_UInt32(workingKey, 8); - engineState[4] = Pack.LE_To_UInt32(workingKey, 12); + 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 (workingKey.Length == 32) + if (keyBytes.Length == 32) { constants = sigma; offset = 16; @@ -181,83 +212,125 @@ namespace Org.BouncyCastle.Crypto.Engines constants = tau; } - engineState[11] = Pack.LE_To_UInt32(workingKey, offset); - engineState[12] = Pack.LE_To_UInt32(workingKey, offset + 4); - engineState[13] = Pack.LE_To_UInt32(workingKey, offset + 8); - engineState[14] = Pack.LE_To_UInt32(workingKey, offset + 12); + 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(workingIV, 0); - engineState[7] = Pack.LE_To_UInt32(workingIV, 4); - engineState[8] = engineState[9] = 0; - - initialised = true; + engineState[6] = Pack.LE_To_UInt32(ivBytes, 0); + engineState[7] = Pack.LE_To_UInt32(ivBytes, 4); + ResetCounter(); } - private void GenerateKeyStream(byte[] output) + protected virtual void GenerateKeyStream(byte[] output) { - SalsaCore(20, engineState, x); + SalsaCore(rounds, engineState, x); Pack.UInt32_To_LE(x, output, 0); } - internal static void SalsaCore(int rounds, uint[] state, uint[] x) + internal static void SalsaCore(int rounds, uint[] input, uint[] x) { - // TODO Exception if rounds odd? + if (input.Length != 16) { + throw new ArgumentException(); + } + if (x.Length != 16) { + throw new ArgumentException(); + } + if (rounds % 2 != 0) { + throw new ArgumentException("Number of rounds must be even"); + } - Array.Copy(state, 0, x, 0, state.Length); + uint x00 = input[ 0]; + uint x01 = input[ 1]; + uint x02 = input[ 2]; + uint x03 = input[ 3]; + uint x04 = input[ 4]; + uint x05 = input[ 5]; + uint x06 = input[ 6]; + uint x07 = input[ 7]; + uint x08 = input[ 8]; + uint x09 = input[ 9]; + uint x10 = input[10]; + uint x11 = input[11]; + uint x12 = input[12]; + uint x13 = input[13]; + uint x14 = input[14]; + uint x15 = input[15]; for (int i = rounds; i > 0; i -= 2) { - x[ 4] ^= R((x[ 0]+x[12]), 7); - x[ 8] ^= R((x[ 4]+x[ 0]), 9); - x[12] ^= R((x[ 8]+x[ 4]),13); - x[ 0] ^= R((x[12]+x[ 8]),18); - x[ 9] ^= R((x[ 5]+x[ 1]), 7); - x[13] ^= R((x[ 9]+x[ 5]), 9); - x[ 1] ^= R((x[13]+x[ 9]),13); - x[ 5] ^= R((x[ 1]+x[13]),18); - x[14] ^= R((x[10]+x[ 6]), 7); - x[ 2] ^= R((x[14]+x[10]), 9); - x[ 6] ^= R((x[ 2]+x[14]),13); - x[10] ^= R((x[ 6]+x[ 2]),18); - x[ 3] ^= R((x[15]+x[11]), 7); - x[ 7] ^= R((x[ 3]+x[15]), 9); - x[11] ^= R((x[ 7]+x[ 3]),13); - x[15] ^= R((x[11]+x[ 7]),18); - x[ 1] ^= R((x[ 0]+x[ 3]), 7); - x[ 2] ^= R((x[ 1]+x[ 0]), 9); - x[ 3] ^= R((x[ 2]+x[ 1]),13); - x[ 0] ^= R((x[ 3]+x[ 2]),18); - x[ 6] ^= R((x[ 5]+x[ 4]), 7); - x[ 7] ^= R((x[ 6]+x[ 5]), 9); - x[ 4] ^= R((x[ 7]+x[ 6]),13); - x[ 5] ^= R((x[ 4]+x[ 7]),18); - x[11] ^= R((x[10]+x[ 9]), 7); - x[ 8] ^= R((x[11]+x[10]), 9); - x[ 9] ^= R((x[ 8]+x[11]),13); - x[10] ^= R((x[ 9]+x[ 8]),18); - x[12] ^= R((x[15]+x[14]), 7); - x[13] ^= R((x[12]+x[15]), 9); - x[14] ^= R((x[13]+x[12]),13); - x[15] ^= R((x[14]+x[13]),18); + x04 ^= R((x00+x12), 7); + x08 ^= R((x04+x00), 9); + x12 ^= R((x08+x04),13); + x00 ^= R((x12+x08),18); + x09 ^= R((x05+x01), 7); + x13 ^= R((x09+x05), 9); + x01 ^= R((x13+x09),13); + x05 ^= R((x01+x13),18); + x14 ^= R((x10+x06), 7); + x02 ^= R((x14+x10), 9); + x06 ^= R((x02+x14),13); + x10 ^= R((x06+x02),18); + x03 ^= R((x15+x11), 7); + x07 ^= R((x03+x15), 9); + x11 ^= R((x07+x03),13); + x15 ^= R((x11+x07),18); + + x01 ^= R((x00+x03), 7); + x02 ^= R((x01+x00), 9); + x03 ^= R((x02+x01),13); + x00 ^= R((x03+x02),18); + x06 ^= R((x05+x04), 7); + x07 ^= R((x06+x05), 9); + x04 ^= R((x07+x06),13); + x05 ^= R((x04+x07),18); + x11 ^= R((x10+x09), 7); + x08 ^= R((x11+x10), 9); + x09 ^= R((x08+x11),13); + x10 ^= R((x09+x08),18); + x12 ^= R((x15+x14), 7); + x13 ^= R((x12+x15), 9); + x14 ^= R((x13+x12),13); + x15 ^= R((x14+x13),18); } - for (int i = 0; i < StateSize; ++i) - { - x[i] += state[i]; - } + 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]; } - private static uint R(uint x, int y) + /** + * Rotate left + * + * @param x value to rotate + * @param y amount to rotate x + * + * @return rotated x + */ + internal static uint R(uint x, int y) { return (x << y) | (x >> (32 - y)); } - private void ResetCounter() + private void ResetLimitCounter() { cW0 = 0; cW1 = 0; diff --git a/crypto/src/crypto/engines/XSalsa20Engine.cs b/crypto/src/crypto/engines/XSalsa20Engine.cs new file mode 100644 index 000000000..fc6630905 --- /dev/null +++ b/crypto/src/crypto/engines/XSalsa20Engine.cs @@ -0,0 +1,71 @@ +using System; + +using Org.BouncyCastle.Crypto.Utilities; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /// <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> + public class XSalsa20Engine + : Salsa20Engine + { + + public override string AlgorithmName + { + get { return "XSalsa20"; } + } + + protected override int NonceSize + { + get { return 24; } + } + + /// <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> + protected override void SetKey(byte[] keyBytes, byte[] ivBytes) + { + if (keyBytes.Length != 32) + { + throw new ArgumentException(AlgorithmName + " requires a 256 bit key"); + } + + // 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); + + // Process engine state to generate Salsa20 key + uint[] hsalsa20Out = new uint[engineState.Length]; + SalsaCore(20, engineState, hsalsa20Out); + + // Set new key, removing addition in last round of salsaCore + engineState[1] = hsalsa20Out[0] - engineState[0]; + engineState[2] = hsalsa20Out[5] - engineState[5]; + engineState[3] = hsalsa20Out[10] - engineState[10]; + engineState[4] = hsalsa20Out[15] - engineState[15]; + + engineState[11] = hsalsa20Out[6] - engineState[6]; + engineState[12] = hsalsa20Out[7] - engineState[7]; + engineState[13] = hsalsa20Out[8] - engineState[8]; + 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(); + } + + } +} + diff --git a/crypto/test/src/crypto/test/ChaChaTest.cs b/crypto/test/src/crypto/test/ChaChaTest.cs new file mode 100644 index 000000000..fea88ca85 --- /dev/null +++ b/crypto/test/src/crypto/test/ChaChaTest.cs @@ -0,0 +1,318 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + /** + * ChaCha Test + * <p> + * Test cases generated using ref version of ChaCha20 in estreambench-20080905. + */ + [TestFixture] + public class ChaChaTest + : SimpleTest + { + private static readonly byte[] zeroes = Hex.Decode( + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"); + + private static readonly string set1v0_0 = + "FBB87FBB8395E05DAA3B1D683C422046" + + "F913985C2AD9B23CFC06C1D8D04FF213" + + "D44A7A7CDB84929F915420A8A3DC58BF" + + "0F7ECB4B1F167BB1A5E6153FDAF4493D"; + + private static readonly string set1v0_192 = + "D9485D55B8B82D792ED1EEA8E93E9BC1" + + "E2834AD0D9B11F3477F6E106A2F6A5F2" + + "EA8244D5B925B8050EAB038F58D4DF57" + + "7FAFD1B89359DAE508B2B10CBD6B488E"; + + private static readonly string set1v0_256 = + "08661A35D6F02D3D9ACA8087F421F7C8" + + "A42579047D6955D937925BA21396DDD4" + + "74B1FC4ACCDCAA33025B4BCE817A4FBF" + + "3E5D07D151D7E6FE04934ED466BA4779"; + + private static readonly string set1v0_448 = + "A7E16DD38BA48CCB130E5BE9740CE359" + + "D631E91600F85C8A5D0785A612D1D987" + + "90780ACDDC26B69AB106CCF6D866411D" + + "10637483DBF08CC5591FD8B3C87A3AE0"; + + private static readonly string set1v9_0 = + "A276339F99316A913885A0A4BE870F06" + + "91E72B00F1B3F2239F714FE81E88E00C" + + "BBE52B4EBBE1EA15894E29658C4CB145" + + "E6F89EE4ABB045A78514482CE75AFB7C"; + + private static readonly string set1v9_192 = + "0DFB9BD4F87F68DE54FBC1C6428FDEB0" + + "63E997BE8490C9B7A4694025D6EBA2B1" + + "5FE429DB82A7CAE6AAB22918E8D00449" + + "6FB6291467B5AE81D4E85E81D8795EBB"; + + private static readonly string set1v9_256 = + "546F5BB315E7F71A46E56D4580F90889" + + "639A2BA528F757CF3B048738BA141AF3" + + "B31607CB21561BAD94721048930364F4" + + "B1227CFEB7CDECBA881FB44903550E68"; + + private static readonly string set1v9_448 = + "6F813586E76691305A0CF048C0D8586D" + + "C89460207D8B230CD172398AA33D19E9" + + "2D24883C3A9B0BB7CD8C6B2668DB142E" + + "37A97948A7A01498A21110297984CD20"; + + private static readonly string set6v0_0 = + "57459975BC46799394788DE80B928387" + + "862985A269B9E8E77801DE9D874B3F51" + + "AC4610B9F9BEE8CF8CACD8B5AD0BF17D" + + "3DDF23FD7424887EB3F81405BD498CC3"; + + private static readonly string set6v0_65472 = + "EF9AEC58ACE7DB427DF012B2B91A0C1E" + + "8E4759DCE9CDB00A2BD59207357BA06C" + + "E02D327C7719E83D6348A6104B081DB0" + + "3908E5186986AE41E3AE95298BB7B713"; + + private static readonly string set6v0_65536 = + "17EF5FF454D85ABBBA280F3A94F1D26E" + + "950C7D5B05C4BB3A78326E0DC5731F83" + + "84205C32DB867D1B476CE121A0D7074B" + + "AA7EE90525D15300F48EC0A6624BD0AF"; + + private static readonly string set6v1_0 = + "92A2508E2C4084567195F2A1005E552B" + + "4874EC0504A9CD5E4DAF739AB553D2E7" + + "83D79C5BA11E0653BEBB5C116651302E" + + "8D381CB728CA627B0B246E83942A2B99"; + + private static readonly string set6v1_65472 = + "E1974EC3063F7BD0CBA58B1CE34BC874" + + "67AAF5759B05EA46682A5D4306E5A76B" + + "D99A448DB8DE73AF97A73F5FBAE2C776" + + "35040464524CF14D7F08D4CE1220FD84"; + + private static readonly string set6v1_65536 = + "BE3436141CFD62D12FF7D852F80C1344" + + "81F152AD0235ECF8CA172C55CA8C031B" + + "2E785D773A988CA8D4BDA6FAE0E493AA" + + "71DCCC4C894D1F106CAC62A9FC0A9607"; + + // ChaCha12 + private static readonly string chacha12_set1v0_0 = + "36CF0D56E9F7FBF287BC5460D95FBA94" + + "AA6CBF17D74E7C784DDCF7E0E882DDAE" + + "3B5A58243EF32B79A04575A8E2C2B73D" + + "C64A52AA15B9F88305A8F0CA0B5A1A25"; + + private static readonly string chacha12_set1v0_192 = + "83496792AB68FEC75ADB16D3044420A4" + + "A00A6E9ADC41C3A63DBBF317A8258C85" + + "A9BC08B4F76B413A4837324AEDF8BC2A" + + "67D53C9AB9E1C5BC5F379D48DF9AF730"; + + private static readonly string chacha12_set1v0_256 = + "BAA28ED593690FD760ADA07C95E3B888" + + "4B4B64E488CA7A2D9BDC262243AB9251" + + "394C5037E255F8BCCDCD31306C508FFB" + + "C9E0161380F7911FCB137D46D9269250"; + + private static readonly string chacha12_set1v0_448 = + "B7ECFB6AE0B51915762FE1FD03A14D0C" + + "9E54DA5DC76EB16EBA5313BC535DE63D" + + "C72D7F9F1874E301E99C8531819F4E37" + + "75793F6A5D19C717FA5C78A39EB804A6"; + + // ChaCha8 + private static readonly string chacha8_set1v0_0 = + "BEB1E81E0F747E43EE51922B3E87FB38" + + "D0163907B4ED49336032AB78B67C2457" + + "9FE28F751BD3703E51D876C017FAA435" + + "89E63593E03355A7D57B2366F30047C5"; + + private static readonly string chacha8_set1v0_192 = + "33B8B7CA8F8E89F0095ACE75A379C651" + + "FD6BDD55703C90672E44C6BAB6AACDD8" + + "7C976A87FD264B906E749429284134C2" + + "38E3B88CF74A68245B860D119A8BDF43"; + + private static readonly string chacha8_set1v0_256 = + "F7CA95BF08688BD3BE8A27724210F9DC" + + "16F32AF974FBFB09E9F757C577A245AB" + + "F35F824B70A4C02CB4A8D7191FA8A5AD" + + "6A84568743844703D353B7F00A8601F4"; + + private static readonly string chacha8_set1v0_448 = + "7B4117E8BFFD595CD8482270B08920FB" + + "C9B97794E1809E07BB271BF07C861003" + + "4C38DBA6ECA04E5474F399A284CBF6E2" + + "7F70142E604D0977797DE5B58B6B25E0"; + + public override string Name + { + get { return "ChaCha"; } + } + + public override void PerformTest() + { + chachaTest1(20, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")), + set1v0_0, set1v0_192, set1v0_256, set1v0_448); + chachaTest1(20, new ParametersWithIV(new KeyParameter(Hex.Decode("00400000000000000000000000000000")), Hex.Decode("0000000000000000")), + set1v9_0, set1v9_192, set1v9_256, set1v9_448); + chachaTest1(12, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")), + chacha12_set1v0_0, chacha12_set1v0_192, chacha12_set1v0_256, chacha12_set1v0_448); + chachaTest1(8, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")), + chacha8_set1v0_0, chacha8_set1v0_192, chacha8_set1v0_256, chacha8_set1v0_448); + chachaTest2(new ParametersWithIV(new KeyParameter(Hex.Decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.Decode("0D74DB42A91077DE")), + set6v0_0, set6v0_65472, set6v0_65536); + chachaTest2(new ParametersWithIV(new KeyParameter(Hex.Decode("0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12")), Hex.Decode("167DE44BB21980E7")), + set6v1_0, set6v1_65472, set6v1_65536); + reinitBug(); + } + + private void chachaTest1( + int rounds, + ICipherParameters parameters, + string v0, + string v192, + string v256, + string v448) + { + IStreamCipher salsa = new ChaChaEngine(rounds); + byte[] buf = new byte[64]; + + salsa.Init(true, parameters); + + for (int i = 0; i != 7; i++) + { + salsa.ProcessBytes(zeroes, 0, 64, buf, 0); + switch (i) + { + case 0: + if (!AreEqual(buf, Hex.Decode(v0))) + { + mismatch("v0/" + rounds, v0, buf); + } + break; + case 3: + if (!AreEqual(buf, Hex.Decode(v192))) + { + mismatch("v192/" + rounds, v192, buf); + } + break; + case 4: + if (!AreEqual(buf, Hex.Decode(v256))) + { + mismatch("v256/" + rounds, v256, buf); + } + break; + default: + // ignore + break; + } + } + + for (int i = 0; i != 64; i++) + { + buf[i] = salsa.ReturnByte(zeroes[i]); + } + + if (!AreEqual(buf, Hex.Decode(v448))) + { + mismatch("v448", v448, buf); + } + } + + private void chachaTest2( + ICipherParameters parameters, + string v0, + string v65472, + string v65536) + { + IStreamCipher salsa = new ChaChaEngine(); + byte[] buf = new byte[64]; + + salsa.Init(true, parameters); + + for (int i = 0; i != 1025; i++) + { + salsa.ProcessBytes(zeroes, 0, 64, buf, 0); + switch (i) + { + case 0: + if (!AreEqual(buf, Hex.Decode(v0))) + { + mismatch("v0", v0, buf); + } + break; + case 1023: + if (!AreEqual(buf, Hex.Decode(v65472))) + { + mismatch("v65472", v65472, buf); + } + break; + case 1024: + if (!AreEqual(buf, Hex.Decode(v65536))) + { + mismatch("v65536", v65536, buf); + } + break; + default: + // ignore + break; + } + } + } + + private void mismatch( + string name, + string expected, + byte[] found) + { + Fail("mismatch on " + name, expected, Hex.ToHexString(found)); + } + + private void reinitBug() + { + KeyParameter key = new KeyParameter(Hex.Decode("80000000000000000000000000000000")); + ParametersWithIV parameters = new ParametersWithIV(key, Hex.Decode("0000000000000000")); + + IStreamCipher chacha = new ChaChaEngine(); + + chacha.Init(true, parameters); + + try + { + chacha.Init(true, key); + Fail("ChaCha should throw exception if no IV in Init"); + } + catch (ArgumentException) + { + } + } + + public static void Main( + string[] args) + { + RunTest(new ChaChaTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs index 687e9ee4f..3a21f3656 100644 --- a/crypto/test/src/crypto/test/RegressionTest.cs +++ b/crypto/test/src/crypto/test/RegressionTest.cs @@ -94,7 +94,9 @@ namespace Org.BouncyCastle.Crypto.Tests new Rfc3211WrapTest(), new SeedTest(), new NaccacheSternTest(), - new Salsa20Test(), + new Salsa20Test(), + new XSalsa20Test(), + new ChaChaTest(), new CMacTest(), new EaxTest(), new GcmTest(), diff --git a/crypto/test/src/crypto/test/Salsa20Test.cs b/crypto/test/src/crypto/test/Salsa20Test.cs index 9e7549ae7..b4dc1ef2b 100644 --- a/crypto/test/src/crypto/test/Salsa20Test.cs +++ b/crypto/test/src/crypto/test/Salsa20Test.cs @@ -106,6 +106,58 @@ namespace Org.BouncyCastle.Crypto.Tests + "C945A6CC69A6A17367BC03431A86B3ED" + "04B0245B56379BF997E25800AD837D7D"; + // Salsa20/12 + + private static readonly string salsa12_set1v0_0 = + "FC207DBFC76C5E1774961E7A5AAD0906" + + "9B2225AC1CE0FE7A0CE77003E7E5BDF8" + + "B31AF821000813E6C56B8C1771D6EE70" + + "39B2FBD0A68E8AD70A3944B677937897"; + + private static readonly string salsa12_set1v0_192 = + "4B62A4881FA1AF9560586510D5527ED4" + + "8A51ECAFA4DECEEBBDDC10E9918D44AB" + + "26B10C0A31ED242F146C72940C6E9C37" + + "53F641DA84E9F68B4F9E76B6C48CA5AC"; + + private static readonly string salsa12_set1v0_256 = + "F52383D9DEFB20810325F7AEC9EADE34" + + "D9D883FEE37E05F74BF40875B2D0BE79" + + "ED8886E5BFF556CEA8D1D9E86B1F68A9" + + "64598C34F177F8163E271B8D2FEB5996"; + + private static readonly string salsa12_set1v0_448 = + "A52ED8C37014B10EC0AA8E05B5CEEE12" + + "3A1017557FB3B15C53E6C5EA8300BF74" + + "264A73B5315DC821AD2CAB0F3BB2F152" + + "BDAEA3AEE97BA04B8E72A7B40DCC6BA4"; + + // Salsa20/8 + + private static readonly string salsa8_set1v0_0 = + "A9C9F888AB552A2D1BBFF9F36BEBEB33" + + "7A8B4B107C75B63BAE26CB9A235BBA9D" + + "784F38BEFC3ADF4CD3E266687EA7B9F0" + + "9BA650AE81EAC6063AE31FF12218DDC5"; + + private static readonly string salsa8_set1v0_192 = + "BB5B6BB2CC8B8A0222DCCC1753ED4AEB" + + "23377ACCBD5D4C0B69A8A03BB115EF71" + + "871BC10559080ACA7C68F0DEF32A80DD" + + "BAF497259BB76A3853A7183B51CC4B9F"; + + private static readonly string salsa8_set1v0_256 = + "4436CDC0BE39559F5E5A6B79FBDB2CAE" + + "4782910F27FFC2391E05CFC78D601AD8" + + "CD7D87B074169361D997D1BED9729C0D" + + "EB23418E0646B7997C06AA84E7640CE3"; + + private static readonly string salsa8_set1v0_448 = + "BEE85903BEA506B05FC04795836FAAAC" + + "7F93F785D473EB762576D96B4A65FFE4" + + "63B34AAE696777FC6351B67C3753B89B" + + "A6B197BD655D1D9CA86E067F4D770220"; + public override string Name { get { return "Salsa20"; } @@ -113,10 +165,14 @@ namespace Org.BouncyCastle.Crypto.Tests public override void PerformTest() { - salsa20Test1(new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")), + salsa20Test1(20, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")), set1v0_0, set1v0_192, set1v0_256, set1v0_448); - salsa20Test1(new ParametersWithIV(new KeyParameter(Hex.Decode("00400000000000000000000000000000")), Hex.Decode("0000000000000000")), + salsa20Test1(20, new ParametersWithIV(new KeyParameter(Hex.Decode("00400000000000000000000000000000")), Hex.Decode("0000000000000000")), set1v9_0, set1v9_192, set1v9_256, set1v9_448); + salsa20Test1(12, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")), + salsa12_set1v0_0, salsa12_set1v0_192, salsa12_set1v0_256, salsa12_set1v0_448); + salsa20Test1(8, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")), + salsa8_set1v0_0, salsa8_set1v0_192, salsa8_set1v0_256, salsa8_set1v0_448); salsa20Test2(new ParametersWithIV(new KeyParameter(Hex.Decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.Decode("0D74DB42A91077DE")), set6v0_0, set6v0_65472, set6v0_65536); salsa20Test2(new ParametersWithIV(new KeyParameter(Hex.Decode("0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12")), Hex.Decode("167DE44BB21980E7")), @@ -125,13 +181,14 @@ namespace Org.BouncyCastle.Crypto.Tests } private void salsa20Test1( + int rounds, ICipherParameters parameters, string v0, string v192, string v256, string v448) { - IStreamCipher salsa = new Salsa20Engine(); + IStreamCipher salsa = new Salsa20Engine(rounds); byte[] buf = new byte[64]; salsa.Init(true, parameters); @@ -144,19 +201,19 @@ namespace Org.BouncyCastle.Crypto.Tests case 0: if (!AreEqual(buf, Hex.Decode(v0))) { - mismatch("v0", v0, buf); + mismatch("v0/" + rounds, v0, buf); } break; case 3: if (!AreEqual(buf, Hex.Decode(v192))) { - mismatch("v192", v192, buf); + mismatch("v192/" + rounds, v192, buf); } break; case 4: if (!AreEqual(buf, Hex.Decode(v256))) { - mismatch("v256", v256, buf); + mismatch("v256/" + rounds, v256, buf); } break; default: diff --git a/crypto/test/src/crypto/test/XSalsa20Test.cs b/crypto/test/src/crypto/test/XSalsa20Test.cs new file mode 100644 index 000000000..74ed04e88 --- /dev/null +++ b/crypto/test/src/crypto/test/XSalsa20Test.cs @@ -0,0 +1,183 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + /** + * XSalsa20 Test + */ + [TestFixture] + public class XSalsa20Test + : SimpleTest + { + private class TestCase + { + + private byte[] key; + private byte[] iv; + private byte[] plaintext; + private byte[] ciphertext; + + public TestCase(String key, string iv, string plaintext, string ciphertext) + { + this.key = Hex.Decode(key); + this.iv = Hex.Decode(iv); + this.plaintext = Hex.Decode(plaintext); + this.ciphertext = Hex.Decode(ciphertext); + } + + public byte[] Key + { + get { return key; } + } + + public byte[] Iv + { + get { return iv; } + } + + public byte[] Plaintext + { + get { return plaintext; } + } + + public byte[] Ciphertext + { + get { return ciphertext; } + } + } + + // Test cases generated by naclcrypto-20090308, as used by cryptopp + private static readonly TestCase[] TEST_CASES = new TestCase[] { + new TestCase( + "a6a7251c1e72916d11c2cb214d3c252539121d8e234e652d651fa4c8cff88030", + "9e645a74e9e0a60d8243acd9177ab51a1beb8d5a2f5d700c", + "093c5e5585579625337bd3ab619d615760d8c5b224a85b1d0efe0eb8a7ee163abb0376529fcc09bab506c618e13ce777d82c3ae9d1a6f972d4160287cbfe60bf2130fc0a6ff6049d0a5c8a82f429231f008082e845d7e189d37f9ed2b464e6b919e6523a8c1210bd52a02a4c3fe406d3085f5068d1909eeeca6369abc981a42e87fe665583f0ab85ae71f6f84f528e6b397af86f6917d9754b7320dbdc2fea81496f2732f532ac78c4e9c6cfb18f8e9bdf74622eb126141416776971a84f94d156beaf67aecbf2ad412e76e66e8fad7633f5b6d7f3d64b5c6c69ce29003c6024465ae3b89be78e915d88b4b5621d", + "b2af688e7d8fc4b508c05cc39dd583d6714322c64d7f3e63147aede2d9534934b04ff6f337b031815cd094bdbc6d7a92077dce709412286822ef0737ee47f6b7ffa22f9d53f11dd2b0a3bb9fc01d9a88f9d53c26e9365c2c3c063bc4840bfc812e4b80463e69d179530b25c158f543191cff993106511aa036043bbc75866ab7e34afc57e2cce4934a5faae6eabe4f221770183dd060467827c27a354159a081275a291f69d946d6fe28ed0b9ce08206cf484925a51b9498dbde178ddd3ae91a8581b91682d860f840782f6eea49dbb9bd721501d2c67122dea3b7283848c5f13e0c0de876bd227a856e4de593a3"), + new TestCase( + "9e1da239d155f52ad37f75c7368a536668b051952923ad44f57e75ab588e475a", + "af06f17859dffa799891c4288f6635b5c5a45eee9017fd72", + "feac9d54fc8c115ae247d9a7e919dd76cfcbc72d32cae4944860817cbdfb8c04e6b1df76a16517cd33ccf1acda9206389e9e318f5966c093cfb3ec2d9ee2de856437ed581f552f26ac2907609df8c613b9e33d44bfc21ff79153e9ef81a9d66cc317857f752cc175fd8891fefebb7d041e6517c3162d197e2112837d3bc4104312ad35b75ea686e7c70d4ec04746b52ff09c421451459fb59f", + "2c261a2f4e61a62e1b27689916bf03453fcbc97bb2af6f329391ef063b5a219bf984d07d70f602d85f6db61474e9d9f5a2deecb4fcd90184d16f3b5b5e168ee03ea8c93f3933a22bc3d1a5ae8c2d8b02757c87c073409052a2a8a41e7f487e041f9a49a0997b540e18621cad3a24f0a56d9b19227929057ab3ba950f6274b121f193e32e06e5388781a1cb57317c0ba6305e910961d01002f0"), + new TestCase("d5c7f6797b7e7e9c1d7fd2610b2abf2bc5a7885fb3ff78092fb3abe8986d35e2", + "744e17312b27969d826444640e9c4a378ae334f185369c95", + "7758298c628eb3a4b6963c5445ef66971222be5d1a4ad839715d1188071739b77cc6e05d5410f963a64167629757", + "27b8cfe81416a76301fd1eec6a4d99675069b2da2776c360db1bdfea7c0aa613913e10f7a60fec04d11e65f2d64e"), + new TestCase( + "737d7811ce96472efed12258b78122f11deaec8759ccbd71eac6bbefa627785c", + "6fb2ee3dda6dbd12f1274f126701ec75c35c86607adb3edd", + "501325fb2645264864df11faa17bbd58312b77cad3d94ac8fb8542f0eb653ad73d7fce932bb874cb89ac39fc47f8267cf0f0c209f204b2d8578a3bdf461cb6a271a468bebaccd9685014ccbc9a73618c6a5e778a21cc8416c60ad24ddc417a130d53eda6dfbfe47d09170a7be1a708b7b5f3ad464310be36d9a2a95dc39e83d38667e842eb6411e8a23712297b165f690c2d7ca1b1346e3c1fccf5cafd4f8be0", + "6724c372d2e9074da5e27a6c54b2d703dc1d4c9b1f8d90f00c122e692ace7700eadca942544507f1375b6581d5a8fb39981c1c0e6e1ff2140b082e9ec016fce141d5199647d43b0b68bfd0fea5e00f468962c7384dd6129aea6a3fdfe75abb210ed5607cef8fa0e152833d5ac37d52e557b91098a322e76a45bbbcf4899e790618aa3f4c2e5e0fc3de93269a577d77a5502e8ea02f717b1dd2df1ec69d8b61ca"), + new TestCase( + "760158da09f89bbab2c99e6997f9523a95fcef10239bcca2573b7105f6898d34", + "43636b2cc346fc8b7c85a19bf507bdc3dafe953b88c69dba", + "d30a6d42dff49f0ed039a306bae9dec8d9e88366cc19e8c3642fd58fa0794ebf8029d949730339b0823a51f0f49f0d2c71f1051c1e0e2c86941f172789cdb1b0107413e70f982ff9761877bb526ef1c3eb1106a948d60ef21bd35d32cfd64f89b79ed63ecc5cca56246af736766f285d8e6b0da9cb1cd21020223ffacc5a32", + "c815b6b79b64f9369aec8dce8c753df8a50f2bc97c70ce2f014db33a65ac5816bac9e30ac08bdded308c65cb87e28e2e71b677dc25c5a6499c1553555daf1f55270a56959dffa0c66f24e0af00951ec4bb59ccc3a6c5f52e0981647e53e439313a52c40fa7004c855b6e6eb25b212a138e843a9ba46edb2a039ee82a263abe"), + new TestCase( + "27ba7e81e7edd4e71be53c07ce8e633138f287e155c7fa9e84c4ad804b7fa1b9", + "ea05f4ebcd2fb6b000da0612861ba54ff5c176fb601391aa", + "e09ff5d2cb050d69b2d42494bde5825238c756d6991d99d7a20d1ef0b83c371c89872690b2fc11d5369f4fc4971b6d3d6c078aef9b0f05c0e61ab89c025168054defeb03fef633858700c58b1262ce011300012673e893e44901dc18eee3105699c44c805897bdaf776af1833162a21a", + "a23e7ef93c5d0667c96d9e404dcbe6be62026fa98f7a3ff9ba5d458643a16a1cef7272dc6097a9b52f35983557c77a11b314b4f7d5dc2cca15ee47616f861873cbfed1d32372171a61e38e447f3cf362b3abbb2ed4170d89dcb28187b7bfd206a3e026f084a7e0ed63d319de6bc9afc0"), + new TestCase("6799d76e5ffb5b4920bc2768bafd3f8c16554e65efcf9a16f4683a7a06927c11", + "61ab951921e54ff06d9b77f313a4e49df7a057d5fd627989", "472766", "8fd7df"), + new TestCase( + "f68238c08365bb293d26980a606488d09c2f109edafa0bbae9937b5cc219a49c", + "5190b51e9b708624820b5abdf4e40fad1fb950ad1adc2d26", + "47ec6b1f73c4b7ff5274a0bfd7f45f864812c85a12fbcb3c2cf8a3e90cf66ccf2eacb521e748363c77f52eb426ae57a0c6c78f75af71284569e79d1a92f949a9d69c4efc0b69902f1e36d7562765543e2d3942d9f6ff5948d8a312cff72c1afd9ea3088aff7640bfd265f7a9946e606abc77bcedae6bddc75a0dba0bd917d73e3bd1268f727e0096345da1ed25cf553ea7a98fea6b6f285732de37431561ee1b3064887fbcbd71935e02", + "36160e88d3500529ba4edba17bc24d8cfaca9a0680b3b1fc97cf03f3675b7ac301c883a68c071bc54acdd3b63af4a2d72f985e51f9d60a4c7fd481af10b2fc75e252fdee7ea6b6453190617dcc6e2fe1cd56585fc2f0b0e97c5c3f8ad7eb4f31bc4890c03882aac24cc53acc1982296526690a220271c2f6e326750d3fbda5d5b63512c831f67830f59ac49aae330b3e0e02c9ea0091d19841f1b0e13d69c9fbfe8a12d6f30bb734d9d2"), + new TestCase( + "45b2bd0de4ed9293ec3e26c4840faaf64b7d619d51e9d7a2c7e36c83d584c3df", + "546c8c5d6be8f90952cab3f36d7c1957baaa7a59abe3d7e5", + "5007c8cd5b3c40e17d7fe423a87ae0ced86bec1c39dc07a25772f3e96dabd56cd3fd7319f6c9654925f2d87087a700e1b130da796895d1c9b9acd62b266144067d373ed51e787498b03c52faad16bb3826fa511b0ed2a19a8663f5ba2d6ea7c38e7212e9697d91486c49d8a000b9a1935d6a7ff7ef23e720a45855481440463b4ac8c4f6e7062adc1f1e1e25d3d65a31812f58a71160", + "8eacfba568898b10c0957a7d44100685e8763a71a69a8d16bc7b3f88085bb9a2f09642e4d09a9f0ad09d0aad66b22610c8bd02ff6679bb92c2c026a216bf425c6be35fb8dae7ff0c72b0efd6a18037c70eed0ca90062a49a3c97fdc90a8f9c2ea536bfdc41918a7582c9927fae47efaa3dc87967b7887dee1bf071734c7665901d9105dae2fdf66b4918e51d8f4a48c60d19fbfbbcba"), + new TestCase( + "fe559c9a282beb40814d016d6bfcb2c0c0d8bf077b1110b8703a3ce39d70e0e1", + "b076200cc7011259805e18b304092754002723ebec5d6200", + "6db65b9ec8b114a944137c821fd606be75478d928366d5284096cdef782fcff7e8f59cb8ffcda979757902c5ffa6bc477ceaa4cb5d5ea76f94d91e833f823a6bc78f1055dfa6a97bea8965c1cde67a668e001257334a585727d9e0f7c1a06e88d3d25a4e6d9096c968bf138e116a3ebeffd4bb4808adb1fd698164ba0a35c709a47f16f1f4435a2345a9194a00b95abd51851d505809a6077da9baca5831afff31578c487ee68f2767974a98a7e803aac788da98319c4ea8eaa3d394855651f484cef543f537e35158ee29", + "4dce9c8f97a028051b0727f34e1b9ef21f06f0760f36e71713204027902090ba2bb6b13436ee778d9f50530efbd7a32b0d41443f58ccaee781c7b716d3a96fdec0e3764ed7959f34c3941278591ea033b5cbadc0f1916032e9bebbd1a8395b83fb63b1454bd775bd20b3a2a96f951246ac14daf68166ba62f6cbff8bd121ac9498ff8852fd2be975df52b5daef3829d18eda42e715022dcbf930d0a789ee6a146c2c7088c35773c63c06b4af4559856ac199ced86863e4294707825337c5857970eb7fddeb263781309011"), + new TestCase( + "0ae10012d7e56614b03dcc89b14bae9242ffe630f3d7e35ce8bbb97bbc2c92c3", + "f96b025d6cf46a8a12ac2af1e2aef1fb83590adadaa5c5ea", + "ea0f354e96f12bc72bbaa3d12b4a8ed879b042f0689878f46b651cc4116d6f78409b11430b3aaa30b2076891e8e1fa528f2fd169ed93dc9f84e24409eec2101daf4d057be2492d11de640cbd7b355ad29fb70400fffd7cd6d425abeeb732a0eaa4330af4c656252c4173deab653eb85c58462d7ab0f35fd12b613d29d473d330310dc323d3c66348bbdbb68a326324657cae7b77a9e34358f2cec50c85609e73056856796e3be8d62b6e2fe9f953", + "e8abd48924b54e5b80866be7d4ebe5cf4274cafff08b39cb2d40a8f0b472398aedc776e0793812fbf1f60078635d2ed86b15efcdba60411ee23b07233592a44ec31b1013ce8964236675f8f183aef885e864f2a72edf4215b5338fa2b54653dfa1a8c55ce5d95cc605b9b311527f2e3463ffbec78a9d1d65dabad2f338769c9f43f133a791a11c7eca9af0b771a4ac32963dc8f631a2c11217ac6e1b9430c1aae1ceebe22703f429998a8fb8c641"), + new TestCase( + "082c539bc5b20f97d767cd3f229eda80b2adc4fe49c86329b5cd6250a9877450", + "845543502e8b64912d8f2c8d9fffb3c69365686587c08d0c", + "a96bb7e910281a6dfad7c8a9c370674f0ceec1ad8d4f0de32f9ae4a23ed329e3d6bc708f876640a229153ac0e7281a8188dd77695138f01cda5f41d5215fd5c6bdd46d982cb73b1efe2997970a9fdbdb1e768d7e5db712068d8ba1af6067b5753495e23e6e1963af012f9c7ce450bf2de619d3d59542fb55f3", + "835da74fc6de08cbda277a7966a07c8dcd627e7b17adde6d930b6581e3124b8baad096f693991fedb1572930601fc7709541839b8e3ffd5f033d2060d999c6c6e3048276613e648000acb5212cc632a916afce290e20ebdf612d08a6aa4c79a74b070d3f872a861f8dc6bb07614db515d363349d3a8e3336a3"), + new TestCase("3d02bff3375d403027356b94f514203737ee9a85d2052db3e4e5a217c259d18a", + "74216c95031895f48c1dba651555ebfa3ca326a755237025", + "0d4b0f54fd09ae39baa5fa4baccf2e6682e61b257e01f42b8f", + "16c4006c28365190411eb1593814cf15e74c22238f210afc3d"), + new TestCase( + "ad1a5c47688874e6663a0f3fa16fa7efb7ecadc175c468e5432914bdb480ffc6", + "e489eed440f1aae1fac8fb7a9825635454f8f8f1f52e2fcc", + "aa6c1e53580f03a9abb73bfdadedfecada4c6b0ebe020ef10db745e54ba861caf65f0e40dfc520203bb54d29e0a8f78f16b3f1aa525d6bfa33c54726e59988cfbec78056", + "02fe84ce81e178e7aabdd3ba925a766c3c24756eefae33942af75e8b464556b5997e616f3f2dfc7fce91848afd79912d9fb55201b5813a5a074d2c0d4292c1fd441807c5"), + new TestCase( + "053a02bedd6368c1fb8afc7a1b199f7f7ea2220c9a4b642a6850091c9d20ab9c", + "c713eea5c26dad75ad3f52451e003a9cb0d649f917c89dde", + "8f0a8a164760426567e388840276de3f95cb5e3fadc6ed3f3e4fe8bc169d9388804dcb94b6587dbb66cb0bd5f87b8e98b52af37ba290629b858e0e2aa7378047a26602", + "516710e59843e6fbd4f25d0d8ca0ec0d47d39d125e9dad987e0518d49107014cb0ae405e30c2eb3794750bca142ce95e290cf95abe15e822823e2e7d3ab21bc8fbd445"), + new TestCase( + "5b14ab0fbed4c58952548a6cb1e0000cf4481421f41288ea0aa84add9f7deb96", + "54bf52b911231b952ba1a6af8e45b1c5a29d97e2abad7c83", + "37fb44a675978b560ff9a4a87011d6f3ad2d37a2c3815b45a3c0e6d1b1d8b1784cd468927c2ee39e1dccd4765e1c3d676a335be1ccd6900a45f5d41a317648315d8a8c24adc64eb285f6aeba05b9029586353d303f17a807658b9ff790474e1737bd5fdc604aeff8dfcaf1427dcc3aacbb0256badcd183ed75a2dc52452f87d3c1ed2aa583472b0ab91cda20614e9b6fdbda3b49b098c95823cc72d8e5b717f2314b0324e9ce", + "ae6deb5d6ce43d4b09d0e6b1c0e9f46157bcd8ab50eaa3197ff9fa2bf7af649eb52c68544fd3adfe6b1eb316f1f23538d470c30dbfec7e57b60cbcd096c782e7736b669199c8253e70214cf2a098fda8eac5da79a9496a3aae754d03b17c6d70d1027f42bf7f95ce3d1d9c338854e158fcc803e4d6262fb639521e47116ef78a7a437ca9427ba645cd646832feab822a208278e45e93e118d780b988d65397eddfd7a819526e"), + new TestCase( + "d74636e3413a88d85f322ca80fb0bd650bd0bf0134e2329160b69609cd58a4b0", + "efb606aa1d9d9f0f465eaa7f8165f1ac09f5cb46fecf2a57", + "f85471b75f6ec81abac2799ec09e98e280b2ffd64ca285e5a0109cfb31ffab2d617b2c2952a2a8a788fc0da2af7f530758f74f1ab56391ab5ff2adbcc5be2d6c7f49fbe8118104c6ff9a23c6dfe52f57954e6a69dcee5db06f514f4a0a572a9a8525d961dae72269b987189d465df6107119c7fa790853e063cba0fab7800ca932e258880fd74c33c784675bedad0e7c09e9cc4d63dd5e9713d5d4a0196e6b562226ac31b4f57c04f90a181973737ddc7e80f364112a9fbb435ebdbcabf7d490ce52", + "b2b795fe6c1d4c83c1327e015a67d4465fd8e32813575cbab263e20ef05864d2dc17e0e4eb81436adfe9f638dcc1c8d78f6b0306baf938e5d2ab0b3e05e735cc6fff2d6e02e3d60484bea7c7a8e13e23197fea7b04d47d48f4a4e5944174539492800d3ef51e2ee5e4c8a0bdf050c2dd3dd74fce5e7e5c37364f7547a11480a3063b9a0a157b15b10a5a954de2731ced055aa2e2767f0891d4329c426f3808ee867bed0dc75b5922b7cfb895700fda016105a4c7b7f0bb90f029f6bbcb04ac36ac16") }; + + public override string Name + { + get { return "XSalsa20"; } + } + + public override void PerformTest() + { + for (int i = 0; i < TEST_CASES.Length; i++) + { + performTest(i, TEST_CASES[i]); + } + } + + private void performTest(int number, TestCase testCase) + { + byte[] plaintext = testCase.Plaintext; + byte[] output = new byte[plaintext.Length]; + + XSalsa20Engine engine = new XSalsa20Engine(); + engine.Init(false, new ParametersWithIV(new KeyParameter(testCase.Key), testCase.Iv)); + + engine.ProcessBytes(testCase.Plaintext, 0, testCase.Plaintext.Length, output, 0); + + if (!Arrays.AreEqual(testCase.Ciphertext, output)) + { + Fail("mismatch on " + number, Hex.ToHexString(testCase.Ciphertext), Hex.ToHexString(output)); + } + } + + public static void Main( + string[] args) + { + RunTest(new XSalsa20Test()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} |