diff --git a/crypto/src/crypto/engines/ElephantEngine.cs b/crypto/src/crypto/engines/ElephantEngine.cs
index b0ec4733c..e3d9ca670 100644
--- a/crypto/src/crypto/engines/ElephantEngine.cs
+++ b/crypto/src/crypto/engines/ElephantEngine.cs
@@ -12,7 +12,7 @@ using Org.BouncyCastle.Utilities;
*/
namespace Org.BouncyCastle.Crypto.Engines
{
- public class ElephantEngine : IAeadCipher
+ public class ElephantEngine : IAeadBlockCipher
{
public enum ElephantParameters
{
@@ -20,23 +20,23 @@ namespace Org.BouncyCastle.Crypto.Engines
elephant176,
elephant200
}
-
+ private bool forEncryption;
+ private readonly string algorithmName;
private ElephantParameters parameters;
private int BLOCK_SIZE;
private int nBits;
private int nSBox;
private int nRounds;
private byte lfsrIV;
- private byte[] m;
private byte[] npub;
private byte[] expanded_key;
- private byte[] tag_buffer;
+ private byte[] tag;
private byte CRYPTO_KEYBYTES = 16;
private byte CRYPTO_NPUBBYTES = 12;
private byte CRYPTO_ABYTES;
+ private bool initialised;
private MemoryStream aadData = new MemoryStream();
- private bool encrypted;
- private bool aadFinished;
+ private MemoryStream message = new MemoryStream();
private readonly byte[] sBoxLayer = {
(byte)0xee, (byte)0xed, (byte)0xeb, (byte)0xe0, (byte)0xe2, (byte)0xe1, (byte)0xe4, (byte)0xef, (byte)0xe7, (byte)0xea, (byte)0xe8, (byte)0xe5, (byte)0xe9, (byte)0xec, (byte)0xe3, (byte)0xe6,
@@ -75,6 +75,7 @@ namespace Org.BouncyCastle.Crypto.Engines
nRounds = 80;
lfsrIV = 0x75;
CRYPTO_ABYTES = 8;
+ algorithmName = "Elephant 160 AEAD";
break;
case ElephantParameters.elephant176:
BLOCK_SIZE = 22;
@@ -83,15 +84,19 @@ namespace Org.BouncyCastle.Crypto.Engines
nRounds = 90;
lfsrIV = 0x45;
CRYPTO_ABYTES = 8;
+ algorithmName = "Elephant 176 AEAD";
break;
case ElephantParameters.elephant200:
BLOCK_SIZE = 25;
nRounds = 18;
CRYPTO_ABYTES = 16;
+ algorithmName = "Elephant 200 AEAD";
break;
+ default:
+ throw new ArgumentException("Invalid parameter settings for Elephant");
}
this.parameters = parameters;
- tag_buffer = new byte[BLOCK_SIZE];
+ initialised = false;
reset(false);
}
@@ -157,7 +162,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return x + y * 5;
}
- void KeccakP200Round(byte[] state, int indexRound)
+ private void KeccakP200Round(byte[] state, int indexRound)
{
int x, y;
byte[] tempA = new byte[25];
@@ -215,7 +220,7 @@ namespace Org.BouncyCastle.Crypto.Engines
// State should be BLOCK_SIZE bytes long
// Note: input may be equal to output
- void lfsr_step(byte[] output, byte[] input)
+ private void lfsr_step(byte[] output, byte[] input)
{
switch (parameters)
{
@@ -233,7 +238,7 @@ namespace Org.BouncyCastle.Crypto.Engines
Array.Copy(input, 1, output, 0, BLOCK_SIZE - 1);
}
- void xor_block(byte[] state, byte[] block, int bOff, int size)
+ private void xor_block(byte[] state, byte[] block, int bOff, int size)
{
for (int i = 0; i < size; ++i)
{
@@ -244,7 +249,7 @@ namespace Org.BouncyCastle.Crypto.Engines
// Write the ith assocated data block to "output".
// The nonce is prepended and padding is added as required.
// adlen is the length of the associated data in bytes
- void get_ad_block(byte[] output, byte[] ad, int adlen, byte[] npub, int i)
+ private void get_ad_block(byte[] output, byte[] ad, int adlen, byte[] npub, int i)
{
int len = 0;
// First block contains nonce
@@ -282,9 +287,9 @@ namespace Org.BouncyCastle.Crypto.Engines
// Return the ith ciphertext block.
// clen is the length of the ciphertext in bytes
- void get_c_block(byte[] output, byte[] c, int cOff, int clen, int i)
+ private void get_c_block(byte[] output, byte[] c, int cOff, int clen, int i)
{
- int block_offset = cOff + i * BLOCK_SIZE;
+ int block_offset = i * BLOCK_SIZE;
// If clen is divisible by BLOCK_SIZE, add an additional padding block
if (block_offset == clen)
{
@@ -296,13 +301,13 @@ namespace Org.BouncyCastle.Crypto.Engines
// Fill with ciphertext if available
if (BLOCK_SIZE <= r_clen)
{ // enough ciphertext
- Array.Copy(c, block_offset, output, 0, BLOCK_SIZE);
+ Array.Copy(c, cOff + block_offset, output, 0, BLOCK_SIZE);
}
else
{ // not enough ciphertext, need to pad
if (r_clen > 0) // c might be nullptr
{
- Array.Copy(c, block_offset, output, 0, r_clen);
+ Array.Copy(c, cOff + block_offset, output, 0, r_clen);
}
Arrays.Fill(output, r_clen, BLOCK_SIZE, (byte)0);
output[r_clen] = 0x01;
@@ -313,10 +318,7 @@ namespace Org.BouncyCastle.Crypto.Engines
public void Init(bool forEncryption, ICipherParameters param)
{
- /**
- * Elephant encryption and decryption is completely symmetrical, so the
- * 'forEncryption' is irrelevant.
- */
+ this.forEncryption = forEncryption;
if (!(param is ParametersWithIV))
{
throw new ArgumentException(
@@ -350,10 +352,14 @@ namespace Org.BouncyCastle.Crypto.Engines
expanded_key = new byte[BLOCK_SIZE];
Array.Copy(k, 0, expanded_key, 0, CRYPTO_KEYBYTES);
permutation(expanded_key);
+ initialised = true;
+ reset(false);
}
- public string AlgorithmName => "Elephant AEAD";
+ public string AlgorithmName => algorithmName;
+
+ public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
public void ProcessAadByte(byte input)
{
@@ -363,26 +369,48 @@ namespace Org.BouncyCastle.Crypto.Engines
public void ProcessAadBytes(byte[] input, int inOff, int len)
{
+ if (inOff + len > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
aadData.Write(input, inOff, len);
}
public int ProcessByte(byte input, byte[] output, int outOff)
{
- return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+ message.Write(new byte[] { input }, 0, 1);
+ return 0;
}
public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
- if (encrypted)
+ if (inOff + len > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ message.Write(input, inOff, len);
+ return 0;
+ }
+
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ int mlen = (int)message.Length - (forEncryption ? 0 : CRYPTO_ABYTES);
+ if ((forEncryption && mlen + outOff + CRYPTO_ABYTES > output.Length) ||
+ (!forEncryption && mlen + outOff - CRYPTO_ABYTES > output.Length))
{
- throw new ArgumentException("Encryption has been processed");
+ throw new OutputLengthException("output buffer is too short");
}
- m = new byte[len];
- Array.Copy(input, inOff, m, 0, len);
+ byte[] tag_buffer = new byte[BLOCK_SIZE];
+ byte[] m = message.GetBuffer();
byte[] ad = aadData.GetBuffer();
- int mlen = len, adlen = (int)aadData.Length;
+ int adlen = (int)aadData.Length;
int nblocks_c = 1 + mlen / BLOCK_SIZE;
int nblocks_m = (mlen % BLOCK_SIZE) != 0 ? nblocks_c : nblocks_c - 1;
int nblocks_ad = 1 + (CRYPTO_NPUBBYTES + adlen) / BLOCK_SIZE;
@@ -415,11 +443,17 @@ namespace Org.BouncyCastle.Crypto.Engines
xor_block(buffer, m, offset, r_size);
Array.Copy(buffer, 0, output, offset + outOff, r_size);
}
-
if (i > 0 && i <= nblocks_c)
{
// Compute tag for ciphertext block
- get_c_block(buffer, output, outOff, mlen, i - 1);//encrypt != 0 ? c : m
+ if (forEncryption)
+ {
+ get_c_block(buffer, output, outOff, mlen, i - 1);
+ }
+ else
+ {
+ get_c_block(buffer, m, 0, mlen, i - 1);
+ }
xor_block(buffer, previous_mask, 0, BLOCK_SIZE);
xor_block(buffer, next_mask, 0, BLOCK_SIZE);
permutation(buffer);
@@ -444,30 +478,34 @@ namespace Org.BouncyCastle.Crypto.Engines
next_mask = temp;
offset += BLOCK_SIZE;
}
- encrypted = true;
- return 0;
- }
-
-
- public int DoFinal(byte[] output, int outOff)
- {
- byte[] tag = GetMac();
- Array.Copy(tag, 0, output, outOff, tag.Length);
+ outOff += mlen;
+ tag = new byte[CRYPTO_ABYTES];
+ xor_block(tag_buffer, expanded_key, 0, BLOCK_SIZE);
+ permutation(tag_buffer);
+ xor_block(tag_buffer, expanded_key, 0, BLOCK_SIZE);
+ if (forEncryption)
+ {
+ Array.Copy(tag_buffer, 0, tag, 0, CRYPTO_ABYTES);
+ Array.Copy(tag, 0, output, outOff, tag.Length);
+ mlen += CRYPTO_ABYTES;
+ }
+ else
+ {
+ for (int i = 0; i < CRYPTO_ABYTES; ++i)
+ {
+ if (tag_buffer[i] != m[mlen + i])
+ {
+ throw new ArgumentException("Mac does not match");
+ }
+ }
+ }
reset(false);
- return 0;
+ return mlen;
}
public byte[] GetMac()
{
- byte[] tag = new byte[CRYPTO_ABYTES];
- if (!aadFinished)
- {
- xor_block(tag_buffer, expanded_key, 0, BLOCK_SIZE);
- permutation(tag_buffer);
- xor_block(tag_buffer, expanded_key, 0, BLOCK_SIZE);
- }
- Array.Copy(tag_buffer, 0, tag, 0, CRYPTO_ABYTES);
return tag;
}
@@ -493,11 +531,12 @@ namespace Org.BouncyCastle.Crypto.Engines
{
if (clearMac)
{
- aadData.SetLength(0);
+ tag = null;
}
- encrypted = false;
- aadFinished = false;
+ aadData.SetLength(0);
+ message.SetLength(0);
}
+
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public void ProcessAadBytes(ReadOnlySpan<byte> input)
{
@@ -506,28 +545,48 @@ namespace Org.BouncyCastle.Crypto.Engines
public int ProcessByte(byte input, Span<byte> output)
{
- byte[] rv = new byte[1];
- ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
- rv.AsSpan(0, 1).CopyTo(output);
- return 1;
+ message.Write(new byte[] { input });
+ return 0;
}
public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
{
- byte[] rv = new byte[input.Length];
- ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
- rv.AsSpan(0, rv.Length).CopyTo(output);
- return rv.Length;
+ message.Write(input.ToArray());
+ return 0;
}
public int DoFinal(Span<byte> output)
{
- byte[] tag = GetMac();
- tag.AsSpan(0, tag.Length).CopyTo(output);
- reset(false);
- return tag.Length;
+ byte[] rv;
+ if (forEncryption)
+ {
+ rv = new byte[message.Length + CRYPTO_ABYTES];
+ }
+ else
+ {
+ rv = new byte[message.Length - CRYPTO_ABYTES];
+ }
+ int len = DoFinal(rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return rv.Length;
+
}
#endif
+
+ public int GetKeyBytesSize()
+ {
+ return CRYPTO_KEYBYTES;
+ }
+
+ public int GetIVBytesSize()
+ {
+ return CRYPTO_NPUBBYTES;
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
}
}
diff --git a/crypto/test/src/crypto/test/ElephantTest.cs b/crypto/test/src/crypto/test/ElephantTest.cs
index ff350b338..8d12a20e0 100644
--- a/crypto/test/src/crypto/test/ElephantTest.cs
+++ b/crypto/test/src/crypto/test/ElephantTest.cs
@@ -8,7 +8,7 @@ using Org.BouncyCastle.Utilities.Test;
using System.Collections.Generic;
using System.IO;
using Org.BouncyCastle.Crypto.Engines;
-
+using Org.BouncyCastle.Crypto.Modes;
namespace BouncyCastle.Crypto.Tests
{
@@ -25,6 +25,15 @@ namespace BouncyCastle.Crypto.Tests
testVectors(ElephantEngine.ElephantParameters.elephant160, "v160");
testVectors(ElephantEngine.ElephantParameters.elephant176, "v176");
testVectors(ElephantEngine.ElephantParameters.elephant200, "v200");
+ ElephantEngine elephant = new ElephantEngine(ElephantEngine.ElephantParameters.elephant160);
+ testExceptions(elephant, elephant.GetKeyBytesSize(), elephant.GetIVBytesSize(), elephant.GetBlockSize());
+ testParameters(elephant, 16, 12, 8, 20);
+ elephant = new ElephantEngine(ElephantEngine.ElephantParameters.elephant176);
+ testExceptions(elephant, elephant.GetKeyBytesSize(), elephant.GetIVBytesSize(), elephant.GetBlockSize());
+ testParameters(elephant, 16, 12, 8, 22);
+ elephant = new ElephantEngine(ElephantEngine.ElephantParameters.elephant200);
+ testExceptions(elephant, elephant.GetKeyBytesSize(), elephant.GetIVBytesSize(), elephant.GetBlockSize());
+ testParameters(elephant, 16, 12, 16, 25);
}
private void testVectors(ElephantEngine.ElephantParameters pbp, String filename)
@@ -49,28 +58,43 @@ namespace BouncyCastle.Crypto.Tests
//{
// continue;
//}
- param = new ParametersWithIV(new KeyParameter(Hex.Decode(map["Key"])), Hex.Decode(map["Nonce"]));
+ byte[] key = Hex.Decode(map["Key"]);
+ byte[] nonce = Hex.Decode(map["Nonce"]);
+ byte[] ad = Hex.Decode(map["AD"]);
+ byte[] pt = Hex.Decode(map["PT"]);
+ byte[] ct = Hex.Decode(map["CT"]);
+ param = new ParametersWithIV(new KeyParameter(key), nonce);
Elephant.Init(true, param);
- adByte = Hex.Decode(map["AD"]);
- Elephant.ProcessAadBytes(adByte, 0, adByte.Length);
- ptByte = Hex.Decode(map["PT"]);
- rv = new byte[Elephant.GetOutputSize(ptByte.Length)];
- Elephant.ProcessBytes(ptByte, 0, ptByte.Length, rv, 0);
- Elephant.DoFinal(rv, ptByte.Length);
- //foreach (byte b in Hex.Decode(map["CT"]))
+ Elephant.ProcessAadBytes(ad, 0, ad.Length);
+ rv = new byte[Elephant.GetOutputSize(pt.Length)];
+ int len = Elephant.ProcessBytes(pt, 0, pt.Length, rv, 0);
+ //byte[] mac = new byte[16];
+ Elephant.DoFinal(rv, len);
+ //foreach(byte b in Hex.Decode(map["CT"]))
//{
// Console.Write(b.ToString("X2"));
//}
//Console.WriteLine();
- //foreach (byte b in rv)
+ //foreach (byte b in Arrays.Concatenate(rv, mac))
//{
// Console.Write(b.ToString("X2"));
//}
//Console.WriteLine();
- Assert.True(Arrays.AreEqual(rv, Hex.Decode(map["CT"])));
+ Assert.True(Arrays.AreEqual(rv, ct));
+ Elephant.Reset();
+ Elephant.Init(false, param);
+ //Decrypt
+ Elephant.ProcessAadBytes(ad, 0, ad.Length);
+ rv = new byte[pt.Length + 16];
+ len = Elephant.ProcessBytes(ct, 0, ct.Length, rv, 0);
+ Elephant.DoFinal(rv, len);
+ byte[] pt_recovered = new byte[pt.Length];
+ Array.Copy(rv, 0, pt_recovered, 0, pt.Length);
+ Assert.True(Arrays.AreEqual(pt, pt_recovered));
//Console.WriteLine(map["Count"] + " pass");
map.Clear();
Elephant.Reset();
+
}
else
{
@@ -87,6 +111,320 @@ namespace BouncyCastle.Crypto.Tests
}
}
}
+
+ private void testExceptions(IAeadBlockCipher aeadBlockCipher, int keysize, int ivsize, int blocksize)
+ {
+ ICipherParameters param;
+ byte[] k = new byte[keysize];
+ byte[] iv = new byte[ivsize];
+ byte[] m = new byte[0];
+ byte[] c1 = new byte[aeadBlockCipher.GetOutputSize(m.Length)];
+ param = new ParametersWithIV(new KeyParameter(k), iv);
+ //try
+ //{
+ // aeadBlockCipher.ProcessBytes(m, 0, m.Length, c1, 0);
+ // Assert.Fail(aeadBlockCipher.AlgorithmName + " need to be initialed before ProcessBytes");
+ //}
+ //catch (ArgumentException e)
+ //{
+ // //expected
+ //}
+
+ //try
+ //{
+ // aeadBlockCipher.ProcessByte((byte)0, c1, 0);
+ // Assert.Fail(aeadBlockCipher.AlgorithmName + " need to be initialed before ProcessByte");
+ //}
+ //catch (ArgumentException e)
+ //{
+ // //expected
+ //}
+
+ //try
+ //{
+ // aeadBlockCipher.Reset();
+ // Assert.Fail(aeadBlockCipher.AlgorithmName + " need to be initialed before reset");
+ //}
+ //catch (ArgumentException e)
+ //{
+ // //expected
+ //}
+
+ try
+ {
+ aeadBlockCipher.DoFinal(c1, m.Length);
+ Assert.Fail(aeadBlockCipher.AlgorithmName + " need to be initialed before dofinal");
+ }
+ catch (ArgumentException e)
+ {
+ //expected
+ }
+
+ try
+ {
+ aeadBlockCipher.GetMac();
+ aeadBlockCipher.GetOutputSize(0);
+ aeadBlockCipher.GetUpdateOutputSize(0);
+ }
+ catch (ArgumentException e)
+ {
+ //expected
+ Assert.Fail(aeadBlockCipher.AlgorithmName + " functions can be called before initialisation");
+ }
+ Random rand = new Random();
+ int randomNum;
+ while ((randomNum = rand.Next(100)) == keysize) ;
+ byte[] k1 = new byte[randomNum];
+ while ((randomNum = rand.Next(100)) == ivsize) ;
+ byte[] iv1 = new byte[randomNum];
+ try
+ {
+ aeadBlockCipher.Init(true, new ParametersWithIV(new KeyParameter(k1), iv));
+ Assert.Fail(aeadBlockCipher.AlgorithmName + " k size does not match");
+ }
+ catch (ArgumentException e)
+ {
+ //expected
+ }
+ try
+ {
+ aeadBlockCipher.Init(true, new ParametersWithIV(new KeyParameter(k), iv1));
+ Assert.Fail(aeadBlockCipher.AlgorithmName + "iv size does not match");
+ }
+ catch (ArgumentException e)
+ {
+ //expected
+ }
+
+
+ aeadBlockCipher.Init(true, param);
+ try
+ {
+ aeadBlockCipher.DoFinal(c1, m.Length);
+ }
+ catch (Exception e)
+ {
+ Assert.Fail(aeadBlockCipher.AlgorithmName + " allows no input for AAD and plaintext");
+ }
+ byte[] mac2 = aeadBlockCipher.GetMac();
+ if (mac2 == null)
+ {
+ Assert.Fail("mac should not be empty after dofinal");
+ }
+ if (!Arrays.AreEqual(mac2, c1))
+ {
+ Assert.Fail("mac should be equal when calling dofinal and getMac");
+ }
+ aeadBlockCipher.ProcessAadByte((byte)0);
+ byte[] mac1 = new byte[aeadBlockCipher.GetOutputSize(0)];
+ aeadBlockCipher.DoFinal(mac1, 0);
+ if (Arrays.AreEqual(mac1, mac2))
+ {
+ Assert.Fail("mac should not match");
+ }
+ //aeadBlockCipher.Reset();
+ //aeadBlockCipher.ProcessBytes(new byte[blocksize], 0, blocksize, new byte[blocksize], 0);
+ //try
+ //{
+ // aeadBlockCipher.ProcessAadByte((byte)0);
+ // Assert.Fail("ProcessAadByte(s) cannot be called after encryption/decryption");
+ //}
+ //catch (ArgumentException e)
+ //{
+ // //expected
+ //}
+ //try
+ //{
+ // aeadBlockCipher.ProcessAadBytes(new byte[] { 0 }, 0, 1);
+ // Assert.Fail("ProcessAadByte(s) cannot be called once only");
+ //}
+ //catch (ArgumentException e)
+ //{
+ // //expected
+ //}
+
+ aeadBlockCipher.Reset();
+ try
+ {
+ aeadBlockCipher.ProcessAadBytes(new byte[] { 0 }, 1, 1);
+ Assert.Fail("input for ProcessAadBytes is too short");
+ }
+ catch (DataLengthException e)
+ {
+ //expected
+ }
+ try
+ {
+ aeadBlockCipher.ProcessBytes(new byte[] { 0 }, 1, 1, c1, 0);
+ Assert.Fail("input for ProcessBytes is too short");
+ }
+ catch (DataLengthException e)
+ {
+ //expected
+ }
+ //try
+ //{
+ // aeadBlockCipher.ProcessBytes(new byte[blocksize], 0, blocksize, new byte[blocksize], blocksize >> 1);
+ // Assert.Fail("output for ProcessBytes is too short");
+ //}
+ //catch (OutputLengthException e)
+ //{
+ // //expected
+ //}
+ try
+ {
+ aeadBlockCipher.DoFinal(new byte[2], 2);
+ Assert.Fail("output for dofinal is too short");
+ }
+ catch (DataLengthException e)
+ {
+ //expected
+ }
+
+ mac1 = new byte[aeadBlockCipher.GetOutputSize(0)];
+ mac2 = new byte[aeadBlockCipher.GetOutputSize(0)];
+ aeadBlockCipher.Reset();
+ aeadBlockCipher.ProcessAadBytes(new byte[] { 0, 0 }, 0, 2);
+ aeadBlockCipher.DoFinal(mac1, 0);
+ aeadBlockCipher.Reset();
+ aeadBlockCipher.ProcessAadByte((byte)0);
+ aeadBlockCipher.ProcessAadByte((byte)0);
+ aeadBlockCipher.DoFinal(mac2, 0);
+ if (!Arrays.AreEqual(mac1, mac2))
+ {
+ Assert.Fail("mac should match for the same AAD with different ways of inputing");
+ }
+
+ byte[] c2 = new byte[aeadBlockCipher.GetOutputSize(10)];
+ byte[] c3 = new byte[aeadBlockCipher.GetOutputSize(10) + 2];
+ byte[] aad2 = { 0, 1, 2, 3, 4 };
+ byte[] aad3 = { 0, 0, 1, 2, 3, 4, 5 };
+ byte[] m2 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ byte[] m3 = { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+ byte[] m4 = new byte[m2.Length];
+ aeadBlockCipher.Reset();
+ aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
+ int offset = aeadBlockCipher.ProcessBytes(m2, 0, m2.Length, c2, 0);
+ aeadBlockCipher.DoFinal(c2, offset);
+ aeadBlockCipher.Reset();
+ aeadBlockCipher.ProcessAadBytes(aad3, 1, aad2.Length);
+ offset = aeadBlockCipher.ProcessBytes(m3, 1, m2.Length, c3, 1);
+ aeadBlockCipher.DoFinal(c3, offset + 1);
+ byte[] c3_partial = new byte[c2.Length];
+ Array.Copy(c3, 1, c3_partial, 0, c2.Length);
+ if (!Arrays.AreEqual(c2, c3_partial))
+ {
+ Assert.Fail("mac should match for the same AAD and message with different offset for both input and output");
+ }
+ aeadBlockCipher.Reset();
+ aeadBlockCipher.Init(false, param);
+ aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
+ offset = aeadBlockCipher.ProcessBytes(c2, 0, c2.Length, m4, 0);
+ aeadBlockCipher.DoFinal(m4, offset);
+ if (!Arrays.AreEqual(m2, m4))
+ {
+ Assert.Fail("The encryption and decryption does not recover the plaintext");
+ }
+ Console.WriteLine(aeadBlockCipher.AlgorithmName + " test Exceptions pass");
+ c2[c2.Length - 1] ^= 1;
+ aeadBlockCipher.Reset();
+ aeadBlockCipher.Init(false, param);
+ aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
+ offset = aeadBlockCipher.ProcessBytes(c2, 0, c2.Length, m4, 0);
+ try
+ {
+ aeadBlockCipher.DoFinal(m4, offset);
+ Assert.Fail("The decryption should fail");
+ }
+ catch (ArgumentException e)
+ {
+ //expected;
+ }
+ c2[c2.Length - 1] ^= 1;
+
+ byte[] m7 = new byte[blocksize * 2];
+ for (int i = 0; i < m7.Length; ++i)
+ {
+ m7[i] = (byte)rand.Next();
+ }
+ byte[] c7 = new byte[aeadBlockCipher.GetOutputSize(m7.Length)];
+ byte[] c8 = new byte[c7.Length];
+ byte[] c9 = new byte[c7.Length];
+ aeadBlockCipher.Init(true, param);
+ aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
+ offset = aeadBlockCipher.ProcessBytes(m7, 0, m7.Length, c7, 0);
+ aeadBlockCipher.DoFinal(c7, offset);
+ aeadBlockCipher.Reset();
+ aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
+ offset = aeadBlockCipher.ProcessBytes(m7, 0, blocksize, c8, 0);
+ offset += aeadBlockCipher.ProcessBytes(m7, blocksize, m7.Length - blocksize, c8, offset);
+ aeadBlockCipher.DoFinal(c8, offset);
+ aeadBlockCipher.Reset();
+ int split = rand.Next(blocksize * 2);
+ aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
+ offset = aeadBlockCipher.ProcessBytes(m7, 0, split, c9, 0);
+ offset += aeadBlockCipher.ProcessBytes(m7, split, m7.Length - split, c9, offset);
+ aeadBlockCipher.DoFinal(c9, offset);
+ if (!Arrays.AreEqual(c7, c8) || !Arrays.AreEqual(c7, c9))
+ {
+ Assert.Fail("Splitting input of plaintext should output the same ciphertext");
+ }
+#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Span<byte> c4_1 = new byte[c2.Length];
+ Span<byte> c4_2 = new byte[c2.Length];
+ ReadOnlySpan<byte> m5 = new ReadOnlySpan<byte>(m2);
+ ReadOnlySpan<byte> aad4 = new ReadOnlySpan<byte>(aad2);
+ aeadBlockCipher.Init(true, param);
+ aeadBlockCipher.ProcessAadBytes(aad4);
+ offset = aeadBlockCipher.ProcessBytes(m5, c4_1);
+ aeadBlockCipher.DoFinal(c4_2);
+ byte[] c5 = new byte[c2.Length];
+ Array.Copy(c4_1.ToArray(), 0, c5, 0, offset);
+ Array.Copy(c4_2.ToArray(), 0, c5, offset, c5.Length - offset);
+ if (!Arrays.AreEqual(c2, c5))
+ {
+ Assert.Fail("mac should match for the same AAD and message with different offset for both input and output");
+ }
+ aeadBlockCipher.Reset();
+ aeadBlockCipher.Init(false, param);
+ Span<byte> m6_1 = new byte[m2.Length];
+ Span<byte> m6_2 = new byte[m2.Length];
+ ReadOnlySpan<byte> c6 = new ReadOnlySpan<byte>(c2);
+ aeadBlockCipher.ProcessAadBytes(aad4);
+ offset = aeadBlockCipher.ProcessBytes(c6, m6_1);
+ aeadBlockCipher.DoFinal(m6_2);
+ byte[] m6 = new byte[m2.Length];
+ Array.Copy(m6_1.ToArray(), 0, m6, 0, offset);
+ Array.Copy(m6_2.ToArray(), 0, m6, offset, m6.Length - offset);
+ if (!Arrays.AreEqual(m2, m6))
+ {
+ Assert.Fail("mac should match for the same AAD and message with different offset for both input and output");
+ }
+#endif
+
+ }
+
+ private void testParameters(ElephantEngine Elephant, int keySize, int ivSize, int macSize, int blockSize)
+ {
+ if (Elephant.GetKeyBytesSize() != keySize)
+ {
+ Assert.Fail("key bytes of " + Elephant.AlgorithmName + " is not correct");
+ }
+ if (Elephant.GetIVBytesSize() != ivSize)
+ {
+ Assert.Fail("iv bytes of " + Elephant.AlgorithmName + " is not correct");
+ }
+ if (Elephant.GetOutputSize(0) != macSize)
+ {
+ Assert.Fail("mac bytes of " + Elephant.AlgorithmName + " is not correct");
+ }
+ if (Elephant.GetBlockSize() != blockSize)
+ {
+ Assert.Fail("block size of " + Elephant.AlgorithmName + " is not correct");
+ }
+ Console.WriteLine(Elephant.AlgorithmName + " test Parameters pass");
+ }
+
}
}
|