diff --git a/crypto/src/crypto/engines/Grain128AEADEngine.cs b/crypto/src/crypto/engines/Grain128AEADEngine.cs
new file mode 100644
index 000000000..e60368574
--- /dev/null
+++ b/crypto/src/crypto/engines/Grain128AEADEngine.cs
@@ -0,0 +1,578 @@
+using System;
+using System.IO;
+using System.Numerics;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ public class Grain128AeadEngine//: AeadCipher
+ {
+
+ /**
+ * Constants
+ */
+ private static readonly int STATE_SIZE = 4;
+
+ /**
+ * Variables to hold the state of the engine during encryption and
+ * decryption
+ */
+ private byte[] workingKey;
+ private byte[] workingIV;
+ private uint[] lfsr;
+ private uint[] nfsr;
+ private uint[] authAcc;
+ private uint[] authSr;
+ private uint outputZ;
+
+ private bool initialised = false;
+ private bool isEven = true; // zero treated as even
+ private bool aadFinished = false;
+ private MemoryStream aadData = new MemoryStream();
+
+ private byte[] mac;
+
+
+ public String GetAlgorithmName()
+ {
+ return "Grain-128AEAD";
+ }
+
+ /**
+ * Initialize a Grain-128AEAD cipher.
+ *
+ * @param forEncryption Whether or not we are for encryption.
+ * @param param The parameters required to set up the cipher.
+ * @throws ArgumentException If the params argument is inappropriate.
+ */
+ public void Init(bool forEncryption, ICipherParameters param)
+ {
+ /**
+ * Grain encryption and decryption is completely symmetrical, so the
+ * 'forEncryption' is irrelevant.
+ */
+ if (!(param is ParametersWithIV))
+ {
+ throw new ArgumentException(
+ "Grain-128AEAD Init parameters must include an IV");
+ }
+
+ ParametersWithIV ivParams = (ParametersWithIV)param;
+
+ byte[]
+ iv = ivParams.GetIV();
+
+ if (iv == null || iv.Length != 12)
+ {
+ throw new ArgumentException(
+ "Grain-128AEAD requires exactly 12 bytes of IV");
+ }
+
+ if (!(ivParams.Parameters is KeyParameter))
+ {
+ throw new ArgumentException(
+ "Grain-128AEAD Init parameters must include a key");
+ }
+
+ KeyParameter key = (KeyParameter)ivParams.Parameters;
+ byte[] keyBytes = key.GetKey();
+ if (keyBytes.Length != 16)
+ {
+ throw new ArgumentException(
+ "Grain-128AEAD key must be 128 bits long");
+ }
+ /**
+ * Initialize variables.
+ */
+ workingIV = new byte[key.GetKey().Length];
+ workingKey = new byte[key.GetKey().Length];
+ lfsr = new uint[STATE_SIZE];
+ nfsr = new uint[STATE_SIZE];
+ authAcc = new uint[2];
+ authSr = new uint[2];
+
+
+ Array.Copy(iv, 0, workingIV, 0, iv.Length);
+ Array.Copy(key.GetKey(), 0, workingKey, 0, key.GetKey().Length);
+
+ Reset();
+ }
+
+ /**
+ * 320 clocks initialization phase.
+ */
+ private void InitGrain()
+ {
+ for (int i = 0; i < 320; ++i)
+ {
+ outputZ = GetOutput();
+ nfsr = Shift(nfsr, (GetOutputNFSR() ^ lfsr[0] ^ outputZ) & 1);
+ lfsr = Shift(lfsr, (GetOutputLFSR() ^ outputZ) & 1);
+ }
+ for (int quotient = 0; quotient < 8; ++quotient)
+ {
+ for (int remainder = 0; remainder < 8; ++remainder)
+ {
+ outputZ = GetOutput();
+ nfsr = Shift(nfsr, (GetOutputNFSR() ^ lfsr[0] ^ outputZ ^ (uint)((workingKey[quotient]) >> remainder)) & 1);
+ lfsr = Shift(lfsr, (GetOutputLFSR() ^ outputZ ^ (uint)((workingKey[quotient + 8]) >> remainder)) & 1);
+ }
+ }
+ for (int quotient = 0; quotient < 2; ++quotient)
+ {
+ for (int remainder = 0; remainder < 32; ++remainder)
+ {
+ outputZ = GetOutput();
+ nfsr = Shift(nfsr, (GetOutputNFSR() ^ lfsr[0]) & 1);
+ lfsr = Shift(lfsr, (GetOutputLFSR()) & 1);
+ authAcc[quotient] |= outputZ << remainder;
+ }
+ }
+ for (int quotient = 0; quotient < 2; ++quotient)
+ {
+ for (int remainder = 0; remainder < 32; ++remainder)
+ {
+ outputZ = GetOutput();
+ nfsr = Shift(nfsr, (GetOutputNFSR() ^ lfsr[0]) & 1);
+ lfsr = Shift(lfsr, (GetOutputLFSR()) & 1);
+ authSr[quotient] |= outputZ << remainder;
+ }
+ }
+ initialised = true;
+ }
+
+ /**
+ * Get output from non-linear function g(x).
+ *
+ * @return Output from NFSR.
+ */
+ private uint GetOutputNFSR()
+ {
+ uint b0 = nfsr[0];
+ uint b3 = nfsr[0] >> 3;
+ uint b11 = nfsr[0] >> 11;
+ uint b13 = nfsr[0] >> 13;
+ uint b17 = nfsr[0] >> 17;
+ uint b18 = nfsr[0] >> 18;
+ uint b22 = nfsr[0] >> 22;
+ uint b24 = nfsr[0] >> 24;
+ uint b25 = nfsr[0] >> 25;
+ uint b26 = nfsr[0] >> 26;
+ uint b27 = nfsr[0] >> 27;
+ uint b40 = nfsr[1] >> 8;
+ uint b48 = nfsr[1] >> 16;
+ uint b56 = nfsr[1] >> 24;
+ uint b59 = nfsr[1] >> 27;
+ uint b61 = nfsr[1] >> 29;
+ uint b65 = nfsr[2] >> 1;
+ uint b67 = nfsr[2] >> 3;
+ uint b68 = nfsr[2] >> 4;
+ uint b70 = nfsr[2] >> 6;
+ uint b78 = nfsr[2] >> 14;
+ uint b82 = nfsr[2] >> 18;
+ uint b84 = nfsr[2] >> 20;
+ uint b88 = nfsr[2] >> 24;
+ uint b91 = nfsr[2] >> 27;
+ uint b92 = nfsr[2] >> 28;
+ uint b93 = nfsr[2] >> 29;
+ uint b95 = nfsr[2] >> 31;
+ uint b96 = nfsr[3];
+
+ return (b0 ^ b26 ^ b56 ^ b91 ^ b96 ^ b3 & b67 ^ b11 & b13 ^ b17 & b18
+ ^ b27 & b59 ^ b40 & b48 ^ b61 & b65 ^ b68 & b84 ^ b22 & b24 & b25 ^ b70 & b78 & b82 ^ b88 & b92 & b93 & b95) & 1;
+ }
+
+ /**
+ * Get output from linear function f(x).
+ *
+ * @return Output from LFSR.
+ */
+ private uint GetOutputLFSR()
+ {
+ uint s0 = lfsr[0];
+ uint s7 = lfsr[0] >> 7;
+ uint s38 = lfsr[1] >> 6;
+ uint s70 = lfsr[2] >> 6;
+ uint s81 = lfsr[2] >> 17;
+ uint s96 = lfsr[3];
+
+ return (s0 ^ s7 ^ s38 ^ s70 ^ s81 ^ s96) & 1;
+ }
+
+ /**
+ * Get output from output function h(x).
+ *
+ * @return y_t.
+ */
+ private uint GetOutput()
+ {
+ uint b2 = nfsr[0] >> 2;
+ uint b12 = nfsr[0] >> 12;
+ uint b15 = nfsr[0] >> 15;
+ uint b36 = nfsr[1] >> 4;
+ uint b45 = nfsr[1] >> 13;
+ uint b64 = nfsr[2];
+ uint b73 = nfsr[2] >> 9;
+ uint b89 = nfsr[2] >> 25;
+ uint b95 = nfsr[2] >> 31;
+ uint s8 = lfsr[0] >> 8;
+ uint s13 = lfsr[0] >> 13;
+ uint s20 = lfsr[0] >> 20;
+ uint s42 = lfsr[1] >> 10;
+ uint s60 = lfsr[1] >> 28;
+ uint s79 = lfsr[2] >> 15;
+ uint s93 = lfsr[2] >> 29;
+ uint s94 = lfsr[2] >> 30;
+ return ((b12 & s8) ^ (s13 & s20) ^ (b95 & s42) ^ (s60 & s79) ^ (b12 & b95 & s94) ^ s93
+ ^ b2 ^ b15 ^ b36 ^ b45 ^ b64 ^ b73 ^ b89) & 1;
+ }
+
+ /**
+ * Shift array 1 bit and add val to index.Length - 1.
+ *
+ * @param array The array to shift.
+ * @param val The value to shift in.
+ * @return The shifted array with val added to index.Length - 1.
+ */
+ private uint[] Shift(uint[] array, uint val)
+ {
+
+ array[0] = (array[0] >> 1) | (array[1] << 31);
+ array[1] = (array[1] >> 1) | (array[2] << 31);
+ array[2] = (array[2] >> 1) | (array[3] << 31);
+ array[3] = (array[3] >> 1) | (val << 31);
+
+ return array;
+ }
+
+ /**
+ * Set keys, reset cipher.
+ *
+ * @param keyBytes The key.
+ * @param ivBytes The IV.
+ */
+ private void SetKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ ivBytes[12] = (byte)0xFF;
+ ivBytes[13] = (byte)0xFF;
+ ivBytes[14] = (byte)0xFF;
+ ivBytes[15] = (byte)0x7F;//(byte) 0xFE;
+ workingKey = keyBytes;
+ workingIV = ivBytes;
+
+ /**
+ * Load NFSR and LFSR
+ */
+ int j = 0;
+ for (int i = 0; i < nfsr.Length; i++)
+ {
+ nfsr[i] = (uint)(((workingKey[j + 3]) << 24) | ((workingKey[j + 2]) << 16)
+ & 0x00FF0000 | ((workingKey[j + 1]) << 8) & 0x0000FF00
+ | ((workingKey[j]) & 0x000000FF));
+
+ lfsr[i] = (uint)(((workingIV[j + 3]) << 24) | ((workingIV[j + 2]) << 16)
+ & 0x00FF0000 | ((workingIV[j + 1]) << 8) & 0x0000FF00
+ | ((workingIV[j]) & 0x000000FF));
+ j += 4;
+ }
+ }
+
+ public int ProcessBytes(byte[] input, int inOff, int len, byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException(GetAlgorithmName()
+ + " not initialised");
+ }
+ if (!aadFinished)
+ {
+ DoProcessAADBytes(aadData.GetBuffer(), 0, (int)aadData.Length);
+ aadFinished = true;
+ }
+
+
+ if ((inOff + len) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + len) > output.Length)
+ {
+ throw new OutputLengthException("output buffer too short");
+ }
+ GetKeyStream(input, inOff, len, output, outOff);
+ return len;
+ }
+
+ public void Reset()
+ {
+ this.isEven = true;
+ this.mac = null;
+ this.aadData.SetLength(0);
+ this.aadFinished = false;
+
+ SetKey(workingKey, workingIV);
+ InitGrain();
+ }
+
+ private byte[] GetKeyStream(byte[] input, int inOff, int len, byte[] ciphertext, int outOff)
+ {
+ int mCnt = 0, acCnt = 0, cCnt = 0;
+ byte cc;
+ byte[] plaintext = new byte[len];
+ for (int i = 0; i < len; ++i)
+ {
+ plaintext[i] = (byte)ReverseByte(input[inOff + i]);
+ }
+ for (int i = 0; i < len; ++i)
+ {
+ cc = 0;
+ for (int j = 0; j < 16; ++j)
+ {
+ outputZ = GetOutput();
+ nfsr = Shift(nfsr, (GetOutputNFSR() ^ lfsr[0]) & 1);
+ lfsr = Shift(lfsr, (GetOutputLFSR()) & 1);
+ if (isEven)
+ {
+ cc |= (byte)(((((plaintext[mCnt >> 3]) >> (7 - (mCnt & 7))) & 1) ^ outputZ) << (cCnt & 7));
+ mCnt++;
+ cCnt++;
+ isEven = false;
+ }
+ else
+ {
+
+ if ((plaintext[acCnt >> 3] & (1 << (7 - (acCnt & 7)))) != 0)
+ {
+ Accumulate();
+ }
+ AuthShift(outputZ);
+ acCnt++;
+ isEven = true;
+ }
+ }
+ ciphertext[outOff + i] = cc;
+ }
+ //outputZ = GetOutput();
+ //nfsr = Shift(nfsr, (GetOutputNFSR() ^ lfsr[0]) & 1);
+ //lfsr = Shift(lfsr, (GetOutputLFSR()) & 1);
+ //Accumulate();
+ //cCnt = len + outOff;//acc_idx
+ //for (int i = 0; i < 2; ++i)
+ //{
+ // for (int j = 0; j < 4; ++j)
+ // {
+ // ciphertext[cCnt] = (byte)((authAcc[i] >> (j << 3)) & 0xff);
+ // cCnt++;
+ // }
+ //}
+
+ return ciphertext;
+ }
+
+
+ public byte ReturnByte(byte input)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException(GetAlgorithmName()
+ + " not initialised");
+ }
+ byte[] plaintext = new byte[1];
+ plaintext[0] = input;
+ byte[] ciphertext = new byte[1];
+ return GetKeyStream(plaintext, 0, 1, ciphertext, 0)[0];
+ }
+
+
+ public void ProcessAADByte(byte input)
+ {
+ if (aadFinished)
+ {
+ throw new ArgumentException("associated data must be added before plaintext/ciphertext");
+ }
+ aadData.Write(new byte[] { input }, 0, 1);
+
+ }
+
+ public void ProcessAADBytes(byte[] input, int inOff, int len)
+ {
+ if (aadFinished)
+ {
+ throw new ArgumentException("associated data must be added before plaintext/ciphertext");
+ }
+ aadData.Write(input, inOff, len);
+ }
+
+ private void Accumulate()
+ {
+ authAcc[0] ^= authSr[0];
+ authAcc[1] ^= authSr[1];
+ }
+
+ private void AuthShift(uint val)
+ {
+ authSr[0] = (authSr[0] >> 1) | (authSr[1] << 31);
+ authSr[1] = (authSr[1] >> 1) | (val << 31);
+ }
+
+
+ public int ProcessByte(byte input, byte[] output, int outOff)
+ {
+ return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+ }
+
+ private void DoProcessAADBytes(byte[] input, int inOff, int len)
+ {
+ byte[] ader;
+ int aderlen;
+ //encodeDer
+ if (len < 128)
+ {
+ ader = new byte[1 + len];
+ ader[0] = (byte)ReverseByte((uint)len);
+ aderlen = 0;
+ }
+ else
+ {
+ aderlen = LenLength(len);
+ ader = new byte[aderlen + 1 + len];
+ ader[0] = (byte)ReverseByte(0x80 | (uint)aderlen);
+ uint tmp = (uint)len;
+ for (int i = 0; i < aderlen; ++i)
+ {
+ ader[1 + i] = (byte)ReverseByte(tmp & 0xff);
+ tmp >>= 8;
+ }
+ }
+ for (int i = 0; i < len; ++i)
+ {
+ ader[1 + aderlen + i] = (byte)ReverseByte(input[inOff + i]);
+ }
+ byte adval;
+ int adCnt = 0;
+ for (int i = 0; i < ader.Length; ++i)
+ {
+ for (int j = 0; j < 16; ++j)
+ {
+ outputZ = GetOutput();
+ nfsr = Shift(nfsr, (GetOutputNFSR() ^ lfsr[0]) & 1);
+ lfsr = Shift(lfsr, (GetOutputLFSR()) & 1);
+ if ((j & 1) == 1)
+ {
+ adval = (byte)(ader[adCnt >> 3] & (1 << (7 - (adCnt & 7))));
+ if (adval != 0)
+ {
+ Accumulate();
+ }
+ AuthShift(outputZ);
+ adCnt++;
+ }
+ }
+ }
+
+
+ }
+
+ private int LenLength(int v)
+ {
+ if ((v & 0xff) == v)
+ {
+ return 1;
+ }
+ if ((v & 0xffff) == v)
+ {
+ return 2;
+ }
+ if ((v & 0xffffff) == v)
+ {
+ return 3;
+ }
+
+ return 4;
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (!aadFinished)
+ {
+ DoProcessAADBytes(aadData.GetBuffer(), 0, (int)aadData.Length);
+ aadFinished = true;
+ }
+
+ this.mac = new byte[8];
+
+ outputZ = GetOutput();
+ nfsr = Shift(nfsr, (GetOutputNFSR() ^ lfsr[0]) & 1);
+ lfsr = Shift(lfsr, (GetOutputLFSR()) & 1);
+ Accumulate();
+
+ int cCnt = 0;
+ for (int i = 0; i < 2; ++i)
+ {
+ for (int j = 0; j < 4; ++j)
+ {
+ mac[cCnt++] = (byte)((authAcc[i] >> (j << 3)) & 0xff);
+ }
+ }
+
+ Array.Copy(mac, 0, output, outOff, mac.Length);
+
+ try
+ {
+ return mac.Length;
+ }
+ finally
+ {
+ Reset();
+ }
+
+ }
+
+
+ public byte[] GetMac()
+ {
+ return mac;
+ }
+
+
+ public int GetUpdateOutputSize(int len)
+ {
+ return len;
+ }
+
+
+ public int GetOutputSize(int len)
+ {
+ return len + 8;
+ }
+
+ private uint ReverseByte(uint x)
+ {
+ x = (uint)(((x & 0x55) << 1) | ((x & (~0x55)) >> 1)) & 0xFF;
+ x = (uint)(((x & 0x33) << 2) | ((x & (~0x33)) >> 2)) & 0xFF;
+ x = (uint)(((x & 0x0f) << 4) | ((x & (~0x0f)) >> 4)) & 0xFF;
+ return x;
+ }
+
+ public uint HighestOneBit(uint v)
+ {
+ int[] MultiplyDeBruijnBitPosition ={
+ 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
+ 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
+ };
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+
+ return (uint)(1 << MultiplyDeBruijnBitPosition[(v * 0x07C4ACDDU) >> 27]);
+ }
+ }
+}
+
diff --git a/crypto/test/src/crypto/test/Grain128AeadTest.cs b/crypto/test/src/crypto/test/Grain128AeadTest.cs
new file mode 100644
index 000000000..049df3354
--- /dev/null
+++ b/crypto/test/src/crypto/test/Grain128AeadTest.cs
@@ -0,0 +1,217 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+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
+{
+ [TestFixture]
+ public class Grain128AeadTest : SimpleTest
+ {
+ public override string Name
+ {
+ get { return "Grain-128Aead"; }
+ }
+
+ [Test]
+ public override void PerformTest()
+ {
+ testVectors();
+ testSplitUpdate();
+ testLongAead();
+ testExceptions();
+ }
+
+
+ private void testVectors()
+ {
+ Grain128AeadEngine grain = new Grain128AeadEngine();
+ ICipherParameters param;
+ var buf = new Dictionary<string, string>();
+ //TestSampler sampler = new TestSampler();
+ using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.LWC_Aead_KAT_128_96.txt")))
+ {
+ string line;
+ string[] data;
+ byte[] ptByte, adByte;
+ byte[] rv;
+ Dictionary<string, string> map = new Dictionary<string, string>();
+ while ((line = src.ReadLine()) != null)
+ {
+ data = line.Split(' ');
+ if (data.Length == 1)
+ {
+ param = new ParametersWithIV(new KeyParameter(Hex.Decode(map["Key"])), Hex.Decode(map["Nonce"]));
+ grain.Init(true, param);
+ adByte = Hex.Decode(map["AD"]);
+ grain.ProcessAADBytes(adByte, 0, adByte.Length);
+ ptByte = Hex.Decode(map["PT"]);
+ rv = new byte[ptByte.Length];
+ grain.ProcessBytes(ptByte, 0, ptByte.Length, rv, 0);
+ byte[] mac = new byte[8];
+ grain.DoFinal(mac, 0);
+ Assert.True(Arrays.AreEqual(Arrays.Concatenate(rv, mac), Hex.Decode(map["CT"])));
+ map.Clear();
+ }
+ else
+ {
+ if (data.Length >= 3)
+ {
+ map[data[0].Trim()] = data[2].Trim();
+ }
+ else
+ {
+ map[data[0].Trim()] = "";
+ }
+
+ }
+ }
+ }
+ }
+
+ private void testSplitUpdate()
+ {
+ byte[] Key = Hex.Decode("000102030405060708090A0B0C0D0E0F");
+ byte[] Nonce = Hex.Decode("000102030405060708090A0B");
+ byte[] PT = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+ byte[] AD = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E");
+ byte[] CT = Hex.Decode("EAD60EF559493ACEF6A3C238C018835DE3ABB6AA621A9AA65EFAF7B9D05BBE6C0913DFC8674BACC9");
+
+ Grain128AeadEngine grain = new Grain128AeadEngine();
+ ParametersWithIV param = new ParametersWithIV(new KeyParameter(Key), Nonce);
+ grain.Init(true, param);
+
+ grain.ProcessAADBytes(AD, 0, 10);
+ grain.ProcessAADByte(AD[10]);
+ grain.ProcessAADBytes(AD, 11, AD.Length - 11);
+
+ byte[] rv = new byte[CT.Length];
+ int len = grain.ProcessBytes(PT, 0, 10, rv, 0);
+ len += grain.ProcessByte(PT[10], rv, len);
+ len += grain.ProcessBytes(PT, 11, PT.Length - 11, rv, len);
+
+ grain.DoFinal(rv, len);
+
+ Assert.True(Arrays.AreEqual(rv, CT));
+
+ grain.ProcessBytes(PT, 0, 10, rv, 0);
+ try
+ {
+ grain.ProcessAADByte((byte)0x01);
+ Assert.Fail("no exception");
+ }
+ catch (ArgumentException e)
+ {
+ Assert.IsTrue(Contains(e.Message, "associated data must be added before plaintext/ciphertext"));
+ }
+
+ try
+ {
+ grain.ProcessAADBytes(AD, 0, AD.Length);
+ Assert.Fail("no exception");
+ }
+ catch (ArgumentException e)
+ {
+ Assert.IsTrue(Contains(e.Message, "associated data must be added before plaintext/ciphertext"));
+ }
+ }
+
+ private bool Contains(string message, string sub)
+ {
+ return message.IndexOf(sub) >= 0;
+ }
+
+ private void testLongAead()
+ {
+ byte[] Key = Hex.Decode("000102030405060708090A0B0C0D0E0F");
+ byte[] Nonce = Hex.Decode("000102030405060708090A0B");
+ byte[] PT = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+ byte[] AD = Hex.Decode( // 186 bytes
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9");
+ byte[] CT = Hex.Decode("731DAA8B1D15317A1CCB4E3DD320095FB27E5BB2A10F2C669F870538637D4F162298C70430A2B560");
+
+ Grain128AeadEngine grain = new Grain128AeadEngine();
+ ParametersWithIV param = new ParametersWithIV(new KeyParameter(Key), Nonce);
+ grain.Init(true, param);
+
+ grain.ProcessAADBytes(AD, 0, AD.Length);
+
+ byte[] rv = new byte[CT.Length];
+ int len = grain.ProcessBytes(PT, 0, 10, rv, 0);
+ len += grain.ProcessByte(PT[10], rv, len);
+ len += grain.ProcessBytes(PT, 11, PT.Length - 11, rv, len);
+
+ grain.DoFinal(rv, len);
+
+ Assert.IsTrue(Arrays.AreEqual(rv, CT));
+
+ grain.ProcessBytes(PT, 0, 10, rv, 0);
+ try
+ {
+ grain.ProcessAADByte((byte)0x01);
+ Assert.Fail("no exception");
+ }
+ catch (ArgumentException e)
+ {
+ Assert.IsTrue(Contains(e.Message, "associated data must be added before plaintext/ciphertext"));
+ }
+
+ try
+ {
+ grain.ProcessAADBytes(AD, 0, AD.Length);
+ Assert.Fail("no exception");
+ }
+ catch (ArgumentException e)
+ {
+ Assert.IsTrue(Contains(e.Message, "associated data must be added before plaintext/ciphertext"));
+ }
+ }
+
+ private void testExceptions()
+
+ {
+ try
+ {
+ Grain128AeadEngine grain128 = new Grain128AeadEngine();
+
+ grain128.Init(true, new KeyParameter(new byte[10]));
+ Assert.Fail("no exception");
+ }
+ catch (ArgumentException e)
+ {
+ Assert.IsTrue(Contains(e.Message, "Grain-128Aead Init parameters must include an IV"));
+ }
+
+ try
+ {
+ Grain128AeadEngine grain128 = new Grain128AeadEngine();
+
+ grain128.Init(true, new ParametersWithIV(new KeyParameter(new byte[10]), new byte[8]));
+ Assert.Fail("no exception");
+ }
+ catch (ArgumentException e)
+ {
+ Assert.IsTrue(Contains(e.Message, "Grain-128Aead requires exactly 12 bytes of IV"));
+ }
+
+ try
+ {
+ Grain128AeadEngine grain128 = new Grain128AeadEngine();
+
+ grain128.Init(true, new ParametersWithIV(new KeyParameter(new byte[10]), new byte[12]));
+ Assert.Fail("no exception");
+ }
+ catch (ArgumentException e)
+ {
+ Assert.IsTrue(Contains(e.Message, "Grain-128Aead key must be 128 bits long"));
+ }
+ }
+
+ }
+}
+
|