diff --git a/crypto/Contributors.html b/crypto/Contributors.html
index b37af312f..04ee69d09 100644
--- a/crypto/Contributors.html
+++ b/crypto/Contributors.html
@@ -111,6 +111,12 @@
<li>
<p>Laszlo Magyar <lmagyar1973@gmail.com> - patch to fix problem with SubjectDirectoryAttributes constructor.</p>
</li>
+ <li>
+ <p>Tim Whittington (https://github.com/timw) - ports of ChaCha, GMAC, XSalsa20. Registerised Salsa20 core.</p>
+ </li>
+ <li>
+ <p>Oscar Jacobsson (https://github.com/OscarAyoy) - patch to fix DerEnumerated constructor (including test coverage).</p>
+ </li>
</ul>
</body>
</html>
diff --git a/crypto/License.html b/crypto/License.html
index 7213058e7..8076a183e 100644
--- a/crypto/License.html
+++ b/crypto/License.html
@@ -9,7 +9,7 @@
<h2>The Bouncy Castle Cryptographic C#® API</h2>
<h3>License:</h3>
The Bouncy Castle License<br>
-Copyright (c) 2000-2013 The Legion Of The Bouncy Castle
+Copyright (c) 2000-2013 The Legion of the Bouncy Castle Inc.
(http://www.bouncycastle.org)<br>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), to deal in the
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 76c91ae2b..0b81c9a6c 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -3324,6 +3324,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\engines\ChaChaEngine.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\engines\DESedeEngine.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -3499,6 +3504,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\engines\XSalsa20Engine.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\engines\XTEAEngine.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -3619,6 +3629,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\generators\Poly1305KeyGenerator.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\generators\RSABlindingFactorGenerator.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -3669,6 +3684,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\macs\GMac.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\macs\GOST28147Mac.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -3679,6 +3699,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\macs\Poly1305.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\macs\SipHash.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -9187,6 +9212,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\asn1\test\EnumeratedTest.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\asn1\test\EssCertIDv2UnitTest.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -9567,6 +9597,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\test\ChaChaTest.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\crypto\test\CipherTest.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -9667,6 +9702,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\test\GMacTest.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\crypto\test\OCBTest.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -9802,6 +9842,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\test\Poly1305Test.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\crypto\test\PSSBlindTest.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -10037,6 +10082,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\test\XSalsa20Test.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\crypto\test\XTEATest.cs"
SubType = "Code"
BuildAction = "Compile"
diff --git a/crypto/crypto.mdp b/crypto/crypto.mdp
index d33604eb5..9a8988bb8 100644
--- a/crypto/crypto.mdp
+++ b/crypto/crypto.mdp
@@ -851,6 +851,7 @@
<File subtype="Code" buildaction="Compile" name="test/src/asn1/test/DERUTF8StringTest.cs" />
<File subtype="Code" buildaction="Compile" name="test/src/asn1/test/EncryptedPrivateKeyInfoTest.cs" />
<File subtype="Code" buildaction="Compile" name="test/src/asn1/test/EqualsAndHashCodeTest.cs" />
+ <File subtype="Code" buildaction="Compile" name="test/src/asn1/test/EnumeratedTest.cs" />
<File subtype="Code" buildaction="Compile" name="test/src/asn1/test/GeneralizedTimeTest.cs" />
<File subtype="Code" buildaction="Compile" name="test/src/asn1/test/GenerationTest.cs" />
<File subtype="Code" buildaction="Compile" name="test/src/asn1/test/InputStreamTest.cs" />
@@ -2297,6 +2298,12 @@
<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" />
+ <File subtype="Code" buildaction="Compile" name="src/crypto/macs/GMac.cs" />
+ <File subtype="Code" buildaction="Compile" name="test/src/crypto/test/GMacTest.cs" />
<File subtype="Code" buildaction="Compile" name="src/crypto/macs/Poly1305.cs" />
<File subtype="Code" buildaction="Compile" name="src/crypto/generators/Poly1305KeyGenerator.cs" />
<File subtype="Code" buildaction="Compile" name="test/src/crypto/test/Poly1305Test.cs" />
diff --git a/crypto/src/asn1/DerEnumerated.cs b/crypto/src/asn1/DerEnumerated.cs
index 0e67e6dbe..a62afb301 100644
--- a/crypto/src/asn1/DerEnumerated.cs
+++ b/crypto/src/asn1/DerEnumerated.cs
@@ -64,7 +64,7 @@ namespace Org.BouncyCastle.Asn1
public DerEnumerated(
byte[] bytes)
{
- this.bytes = bytes;
+ this.bytes = Arrays.Clone(bytes);
}
public BigInteger Value
diff --git a/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs b/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
index 0185b2a62..f322ef88f 100644
--- a/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
+++ b/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
Binary files differdiff --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/src/crypto/macs/CMac.cs b/crypto/src/crypto/macs/CMac.cs
index b55a05605..682c12bac 100644
--- a/crypto/src/crypto/macs/CMac.cs
+++ b/crypto/src/crypto/macs/CMac.cs
@@ -107,7 +107,7 @@ namespace Org.BouncyCastle.Crypto.Macs
private static int ShiftLeft(byte[] block, byte[] output)
{
- int i = 16;
+ int i = block.Length;
uint bit = 0;
while (--i >= 0)
{
diff --git a/crypto/src/crypto/macs/GMac.cs b/crypto/src/crypto/macs/GMac.cs
new file mode 100644
index 000000000..eb340ddbc
--- /dev/null
+++ b/crypto/src/crypto/macs/GMac.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /// <summary>
+ /// The GMAC specialisation of Galois/Counter mode (GCM) detailed in NIST Special Publication
+ /// 800-38D.
+ /// </summary>
+ /// <remarks>
+ /// GMac is an invocation of the GCM mode where no data is encrypted (i.e. all input data to the Mac
+ /// is processed as additional authenticated data with the underlying GCM block cipher).
+ /// </remarks>
+ public class GMac
+ : IMac
+ {
+ private readonly GcmBlockCipher cipher;
+ private readonly int macSizeBits;
+
+ /// <summary>
+ /// Creates a GMAC based on the operation of a block cipher in GCM mode.
+ /// </summary>
+ /// <remarks>
+ /// This will produce an authentication code the length of the block size of the cipher.
+ /// </remarks>
+ /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param>
+ public GMac(GcmBlockCipher cipher)
+ : this(cipher, 128)
+ {
+ }
+
+ /// <summary>
+ /// Creates a GMAC based on the operation of a 128 bit block cipher in GCM mode.
+ /// </summary>
+ /// <remarks>
+ /// This will produce an authentication code the length of the block size of the cipher.
+ /// </remarks>
+ /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param>
+ /// <param name="macSizeBits">the mac size to generate, in bits. Must be a multiple of 8, between 96 and 128 (inclusive).</param>
+ public GMac(GcmBlockCipher cipher, int macSizeBits)
+ {
+ this.cipher = cipher;
+ this.macSizeBits = macSizeBits;
+ }
+
+ /// <summary>
+ /// Initialises the GMAC - requires a <see cref="Org.BouncyCastle.Crypto.Parameters.ParametersWithIV"/>
+ /// providing a <see cref="Org.BouncyCastle.Crypto.Parameters.KeyParameter"/> and a nonce.
+ /// </summary>
+ public void Init(ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)parameters;
+
+ byte[] iv = param.GetIV();
+ KeyParameter keyParam = (KeyParameter)param.Parameters;
+
+ // GCM is always operated in encrypt mode to calculate MAC
+ cipher.Init(true, new AeadParameters(keyParam, macSizeBits, iv));
+ }
+ else
+ {
+ throw new ArgumentException("GMAC requires ParametersWithIV");
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.GetUnderlyingCipher().AlgorithmName + "-GMAC"; }
+ }
+
+ public int GetMacSize()
+ {
+ return macSizeBits / 8;
+ }
+
+ public void Update(byte input)
+ {
+ cipher.ProcessAadByte(input);
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ cipher.ProcessAadBytes(input, inOff, len);
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ try
+ {
+ return cipher.DoFinal(output, outOff);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ // Impossible in encrypt mode
+ throw new InvalidOperationException(e.ToString());
+ }
+ }
+
+ public void Reset()
+ {
+ cipher.Reset();
+ }
+ }
+}
diff --git a/crypto/src/crypto/modes/EAXBlockCipher.cs b/crypto/src/crypto/modes/EAXBlockCipher.cs
index bb027b597..5ccc69b66 100644
--- a/crypto/src/crypto/modes/EAXBlockCipher.cs
+++ b/crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -65,6 +65,11 @@ namespace Org.BouncyCastle.Crypto.Modes
get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; }
}
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
public virtual int GetBlockSize()
{
return cipher.GetBlockSize();
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index 95fe6f7ec..74b895e7b 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -69,6 +69,11 @@ namespace Org.BouncyCastle.Crypto.Modes
get { return cipher.AlgorithmName + "/GCM"; }
}
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
public virtual int GetBlockSize()
{
return BlockSize;
diff --git a/crypto/src/crypto/modes/IAeadBlockCipher.cs b/crypto/src/crypto/modes/IAeadBlockCipher.cs
index 06bc50488..52c4ff428 100644
--- a/crypto/src/crypto/modes/IAeadBlockCipher.cs
+++ b/crypto/src/crypto/modes/IAeadBlockCipher.cs
@@ -11,6 +11,9 @@ namespace Org.BouncyCastle.Crypto.Modes
/// <summary>The name of the algorithm this cipher implements.</summary>
string AlgorithmName { get; }
+ /// <summary>The block cipher underlying this algorithm.</summary>
+ IBlockCipher GetUnderlyingCipher();
+
/// <summary>Initialise the cipher.</summary>
/// <remarks>Parameter can either be an AeadParameters or a ParametersWithIV object.</remarks>
/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
diff --git a/crypto/test/src/asn1/test/EnumeratedTest.cs b/crypto/test/src/asn1/test/EnumeratedTest.cs
new file mode 100644
index 000000000..29e90326b
--- /dev/null
+++ b/crypto/test/src/asn1/test/EnumeratedTest.cs
@@ -0,0 +1,115 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+ /// <summary>
+ /// Tests used to verify correct decoding of the ENUMERATED type.
+ /// </summary>
+ [TestFixture]
+ public class EnumeratedTest
+ {
+ /// <summary>
+ /// Test vector used to test decoding of multiple items.
+ /// </summary>
+ /// <remarks>This sample uses an ENUMERATED and a BOOLEAN.</remarks>
+ private static readonly byte[] MultipleSingleByteItems = Hex.Decode("30060a01010101ff");
+
+ /// <summary>
+ /// Test vector used to test decoding of multiple items.
+ /// </summary>
+ /// <remarks>This sample uses two ENUMERATEDs.</remarks>
+ private static readonly byte[] MultipleDoubleByteItems = Hex.Decode("30080a0201010a020202");
+
+ /// <summary>
+ /// Test vector used to test decoding of multiple items.
+ /// </summary>
+ /// <remarks>This sample uses an ENUMERATED and an OBJECT IDENTIFIER.</remarks>
+ private static readonly byte[] MultipleTripleByteItems = Hex.Decode("300a0a0301010106032b0601");
+
+ /// <summary>
+ /// Makes sure multiple identically sized values are parsed correctly.
+ /// </summary>
+ [Test]
+ public void TestReadingMultipleSingleByteItems()
+ {
+ Asn1Object obj = Asn1Object.FromByteArray(MultipleSingleByteItems);
+
+ Assert.IsTrue(obj is DerSequence, "Null ASN.1 SEQUENCE");
+
+ DerSequence sequence = (DerSequence)obj;
+
+ Assert.AreEqual(2, sequence.Count, "2 items expected");
+
+ DerEnumerated enumerated = sequence[0] as DerEnumerated;
+
+ Assert.IsNotNull(enumerated, "ENUMERATED expected");
+
+ Assert.AreEqual(1, enumerated.Value.IntValue, "Unexpected ENUMERATED value");
+
+ DerBoolean boolean = sequence[1] as DerBoolean;
+
+ Assert.IsNotNull(boolean, "BOOLEAN expected");
+
+ Assert.IsTrue(boolean.IsTrue, "Unexpected BOOLEAN value");
+ }
+
+ /// <summary>
+ /// Makes sure multiple identically sized values are parsed correctly.
+ /// </summary>
+ [Test]
+ public void TestReadingMultipleDoubleByteItems()
+ {
+ Asn1Object obj = Asn1Object.FromByteArray(MultipleDoubleByteItems);
+
+ Assert.IsTrue(obj is DerSequence, "Null ASN.1 SEQUENCE");
+
+ DerSequence sequence = (DerSequence)obj;
+
+ Assert.AreEqual(2, sequence.Count, "2 items expected");
+
+ DerEnumerated enumerated1 = sequence[0] as DerEnumerated;
+
+ Assert.IsNotNull(enumerated1, "ENUMERATED expected");
+
+ Assert.AreEqual(257, enumerated1.Value.IntValue, "Unexpected ENUMERATED value");
+
+ DerEnumerated enumerated2 = sequence[1] as DerEnumerated;
+
+ Assert.IsNotNull(enumerated2, "ENUMERATED expected");
+
+ Assert.AreEqual(514, enumerated2.Value.IntValue, "Unexpected ENUMERATED value");
+ }
+
+ /// <summary>
+ /// Makes sure multiple identically sized values are parsed correctly.
+ /// </summary>
+ [Test]
+ public void TestReadingMultipleTripleByteItems()
+ {
+ Asn1Object obj = Asn1Object.FromByteArray(MultipleTripleByteItems);
+
+ Assert.IsTrue(obj is DerSequence, "Null ASN.1 SEQUENCE");
+
+ DerSequence sequence = (DerSequence)obj;
+
+ Assert.AreEqual(2, sequence.Count, "2 items expected");
+
+ DerEnumerated enumerated = sequence[0] as DerEnumerated;
+
+ Assert.IsNotNull(enumerated, "ENUMERATED expected");
+
+ Assert.AreEqual(65793, enumerated.Value.IntValue, "Unexpected ENUMERATED value");
+
+ DerObjectIdentifier objectId = sequence[1] as DerObjectIdentifier;
+
+ Assert.IsNotNull(objectId, "OBJECT IDENTIFIER expected");
+
+ Assert.AreEqual("1.3.6.1", objectId.Id, "Unexpected OBJECT IDENTIFIER value");
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/test/ChaChaTest.cs b/crypto/test/src/crypto/test/ChaChaTest.cs
new file mode 100644
index 000000000..0b394c91e
--- /dev/null
+++ b/crypto/test/src/crypto/test/ChaChaTest.cs
@@ -0,0 +1,319 @@
+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.
+ * </p>
+ */
+ [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/GMacTest.cs b/crypto/test/src/crypto/test/GMacTest.cs
new file mode 100644
index 000000000..0f0e84e2a
--- /dev/null
+++ b/crypto/test/src/crypto/test/GMacTest.cs
@@ -0,0 +1,184 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+ /**
+ * Test vectors for AES-GMAC, extracted from <a
+ * href="http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip">NIST CAVP GCM test
+ * vectors</a>.
+ *
+ */
+ [TestFixture]
+ public class GMacTest
+ : SimpleTest
+ {
+ private class TestCase
+ {
+ private byte[] key;
+ private byte[] iv;
+ private byte[] ad;
+ private byte[] tag;
+ private string name;
+
+ internal TestCase(string name, string key, string iv, string ad, string tag)
+ {
+ this.name = name;
+ this.key = Hex.Decode(key);
+ this.iv = Hex.Decode(iv);
+ this.ad = Hex.Decode(ad);
+ this.tag = Hex.Decode(tag);
+ }
+
+ public string getName()
+ {
+ return name;
+ }
+
+ public byte[] getKey()
+ {
+ return key;
+ }
+
+ public byte[] getIv()
+ {
+ return iv;
+ }
+
+ public byte[] getAd()
+ {
+ return ad;
+ }
+
+ public byte[] getTag()
+ {
+ return tag;
+ }
+ }
+
+ private TestCase[] TEST_VECTORS = new TestCase[] {
+ // Count = 0, from each of the PTlen = 0 test vector sequences
+ new TestCase("128/96/0/128", "11754cd72aec309bf52f7687212e8957", "3c819d9a9bed087615030b65", "",
+ "250327c674aaf477aef2675748cf6971"),
+ new TestCase("128/96/0/120", "272f16edb81a7abbea887357a58c1917", "794ec588176c703d3d2a7a07", "",
+ "b6e6f197168f5049aeda32dafbdaeb"),
+ new TestCase("128/96/0/112", "81b6844aab6a568c4556a2eb7eae752f", "ce600f59618315a6829bef4d", "",
+ "89b43e9dbc1b4f597dbbc7655bb5"),
+ new TestCase("128/96/0/104", "cde2f9a9b1a004165ef9dc981f18651b", "29512c29566c7322e1e33e8e", "",
+ "2e58ce7dabd107c82759c66a75"),
+ new TestCase("128/96/0/96", "b01e45cc3088aaba9fa43d81d481823f", "5a2c4a66468713456a4bd5e1", "",
+ "014280f944f53c681164b2ff"),
+
+ new TestCase("128/96/128/128", "77be63708971c4e240d1cb79e8d77feb", "e0e00f19fed7ba0136a797f3",
+ "7a43ec1d9c0a5a78a0b16533a6213cab", "209fcc8d3675ed938e9c7166709dd946"),
+ new TestCase("128/96/128/96", "bea48ae4980d27f357611014d4486625", "32bddb5c3aa998a08556454c",
+ "8a50b0b8c7654bced884f7f3afda2ead", "8e0f6d8bf05ffebe6f500eb1"),
+
+ new TestCase("128/96/384/128", "99e3e8793e686e571d8285c564f75e2b", "c2dd0ab868da6aa8ad9c0d23",
+ "b668e42d4e444ca8b23cfdd95a9fedd5178aa521144890b093733cf5cf22526c5917ee476541809ac6867a8c399309fc",
+ "3f4fba100eaf1f34b0baadaae9995d85"),
+ new TestCase("128/96/384/96", "c77acd1b0918e87053cb3e51651e7013", "39ff857a81745d10f718ac00",
+ "407992f82ea23b56875d9a3cb843ceb83fd27cb954f7c5534d58539fe96fb534502a1b38ea4fac134db0a42de4be1137",
+ "2a5dc173285375dc82835876"),
+
+ new TestCase(
+ "128/1024/0/128",
+ "d0f1f4defa1e8c08b4b26d576392027c",
+ "42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac",
+ "", "7ab49b57ddf5f62c427950111c5c4f0d"),
+ new TestCase(
+ "128/1024/384/96",
+ "3cce72d37933394a8cac8a82deada8f0",
+ "aa2f0d676d705d9733c434e481972d4888129cf7ea55c66511b9c0d25a92a174b1e28aa072f27d4de82302828955aadcb817c4907361869bd657b45ff4a6f323871987fcf9413b0702d46667380cd493ed24331a28b9ce5bbfa82d3a6e7679fcce81254ba64abcad14fd18b22c560a9d2c1cd1d3c42dac44c683edf92aced894",
+ "5686b458e9c176f4de8428d9ebd8e12f569d1c7595cf49a4b0654ab194409f86c0dd3fdb8eb18033bb4338c70f0b97d1",
+ "a3a9444b21f330c3df64c8b6"), };
+
+ public override void PerformTest()
+ {
+ for (int i = 0; i < TEST_VECTORS.Length; i++)
+ {
+ TestCase testCase = TEST_VECTORS[i];
+
+ IMac mac = new GMac(new GcmBlockCipher(new AesFastEngine()), testCase.getTag().Length * 8);
+ ICipherParameters key = new KeyParameter(testCase.getKey());
+ mac.Init(new ParametersWithIV(key, testCase.getIv()));
+
+ testSingleByte(mac, testCase);
+ testMultibyte(mac, testCase);
+ }
+
+ // Invalid mac size
+ testInvalidMacSize(97);
+ testInvalidMacSize(136);
+ testInvalidMacSize(88);
+ testInvalidMacSize(64);
+ }
+
+ private void testInvalidMacSize(int size)
+ {
+ try
+ {
+ GMac mac = new GMac(new GcmBlockCipher(new AesFastEngine()), size);
+ mac.Init(new ParametersWithIV(null, new byte[16]));
+ Fail("Expected failure for illegal mac size " + size);
+ }
+ catch (ArgumentException)
+ {
+ }
+ }
+
+ private void testMultibyte(IMac mac, TestCase testCase)
+ {
+ mac.BlockUpdate(testCase.getAd(), 0, testCase.getAd().Length);
+ checkMac(mac, testCase);
+ }
+
+ private void testSingleByte(IMac mac, TestCase testCase)
+ {
+ byte[] ad = testCase.getAd();
+ for (int i = 0; i < ad.Length; i++)
+ {
+ mac.Update(ad[i]);
+ }
+ checkMac(mac, testCase);
+ }
+
+ private void checkMac(IMac mac, TestCase testCase)
+ {
+ byte[] generatedMac = new byte[mac.GetMacSize()];
+ mac.DoFinal(generatedMac, 0);
+ if (!AreEqual(testCase.getTag(), generatedMac))
+ {
+ Fail("Failed " + testCase.getName() + " - expected " + Hex.ToHexString(testCase.getTag()) + " got "
+ + Hex.ToHexString(generatedMac));
+ }
+ }
+
+ public override string Name
+ {
+ get { return "GMac"; }
+ }
+
+ public static void Main(
+ string[] args)
+ {
+ RunTest(new GMacTest());
+ }
+
+ [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 a43ee76cc..0ac3624d8 100644
--- a/crypto/test/src/crypto/test/RegressionTest.cs
+++ b/crypto/test/src/crypto/test/RegressionTest.cs
@@ -94,10 +94,13 @@ 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(),
+ new GMacTest(),
new HCFamilyTest(),
new HCFamilyVecTest(),
new IsaacTest(),
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);
+ }
+ }
+}
|