summary refs log tree commit diff
diff options
context:
space:
mode:
authorgefeili <gli@keyfactor.com>2023-01-23 13:17:29 +1030
committergefeili <gli@keyfactor.com>2023-01-23 14:18:48 +1030
commitc6ef589a56695e45de1f1df99b21698cd50a8881 (patch)
treefcf989715f8078637160f7693c378de191649e05
parentComplete tests for Ascon AEAD (diff)
downloadBouncyCastle.NET-ed25519-c6ef589a56695e45de1f1df99b21698cd50a8881.tar.xz
Complete tests for Ascon AEAD
-rw-r--r--crypto/src/crypto/engines/AsconEngine.cs354
-rw-r--r--crypto/test/src/crypto/test/AsconTest.cs362
2 files changed, 635 insertions, 81 deletions
diff --git a/crypto/src/crypto/engines/AsconEngine.cs b/crypto/src/crypto/engines/AsconEngine.cs
index 14d3ddf6d..c3091b9ef 100644
--- a/crypto/src/crypto/engines/AsconEngine.cs
+++ b/crypto/src/crypto/engines/AsconEngine.cs
@@ -4,6 +4,7 @@ using Org.BouncyCastle.Crypto.Modes;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
+using static Org.BouncyCastle.Tls.DtlsReliableHandshake;
 
 /**
 * ASCON AEAD v1.2, https://ascon.iaik.tugraz.at/
@@ -25,11 +26,16 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         private readonly AsconParameters asconParameters;
         private readonly MemoryStream aadData = new MemoryStream();
+        private readonly MemoryStream message = new MemoryStream();
         private bool encrypted;
+        private bool initialised;
+        private bool forEncryption;
+        private bool aadFinished;
         private readonly int CRYPTO_KEYBYTES;
         private readonly int CRYPTO_ABYTES;
         private readonly int ASCON_AEAD_RATE;
         private readonly int nr;
+        private byte[] mac;
         private ulong K0;
         private ulong K1;
         private ulong K2;
@@ -41,10 +47,11 @@ namespace Org.BouncyCastle.Crypto.Engines
         private ulong x2;
         private ulong x3;
         private ulong x4;
+        private String algorithmName;
 
         public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
 
-        public string AlgorithmName => "ASCON AEAD";
+        public string AlgorithmName => algorithmName;
 
         public AsconEngine(AsconParameters asconParameters)
         {
@@ -56,35 +63,39 @@ namespace Org.BouncyCastle.Crypto.Engines
                     CRYPTO_ABYTES = 16;
                     ASCON_AEAD_RATE = 8;
                     ASCON_IV = 0xa0400c0600000000UL;
+                    algorithmName = "Ascon-80pq AEAD";
                     break;
                 case AsconParameters.ascon128a:
                     CRYPTO_KEYBYTES = 16;
                     CRYPTO_ABYTES = 16;
                     ASCON_AEAD_RATE = 16;
                     ASCON_IV = 0x80800c0800000000UL;
+                    algorithmName = "Ascon-128a AEAD";
                     break;
                 case AsconParameters.ascon128:
                     CRYPTO_KEYBYTES = 16;
                     CRYPTO_ABYTES = 16;
                     ASCON_AEAD_RATE = 8;
                     ASCON_IV = 0x80400c0600000000UL;
+                    algorithmName = "Ascon-128 AEAD";
                     break;
                 default:
                     throw new ArgumentException("invalid parameter setting for ASCON AEAD");
             }
             nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
+            initialised = false;
         }
 
         private ulong U64BIG(ulong x)
         {
-            return (((0x00000000000000FFUL & (x)) << 56) |
-            ((0x000000000000FF00UL & (x)) << 40) |
-            ((0x0000000000FF0000UL & (x)) << 24) |
-            ((0x00000000FF000000UL & (x)) << 8) |
-            ((0x000000FF00000000UL & (x)) >> 8) |
-            ((0x0000FF0000000000UL & (x)) >> 24) |
-            ((0x00FF000000000000UL & (x)) >> 40) |
-            ((0xFF00000000000000UL & (x)) >> 56));
+            return (((0x00000000000000FFUL & x) << 56) |
+            ((0x000000000000FF00UL & x) << 40) |
+            ((0x0000000000FF0000UL & x) << 24) |
+            ((0x00000000FF000000UL & x) << 8) |
+            ((0x000000FF00000000UL & x) >> 8) |
+            ((0x0000FF0000000000UL & x) >> 24) |
+            ((0x00FF000000000000UL & x) >> 40) |
+            ((0xFF00000000000000UL & x) >> 56));
         }
 
         private ulong ROR(ulong x, int n)
@@ -121,10 +132,17 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         private void STORE(byte[] bytes, int inOff, ulong w, int n)
         {
-            ulong x = Pack.LE_To_UInt64(bytes, inOff);
+            ulong x = 0;
+            for (int i = 0; i < n; ++i)
+            {
+                x |= (bytes[i + inOff] & 0xFFUL) << (i << 3);
+            }
             x &= ~MASK(n);
             x |= U64BIG(w);
-            Pack.UInt64_To_LE(x, bytes, inOff);
+            for (int i = 0; i < n; ++i)
+            {
+                bytes[i + inOff] = (byte)(x >> (i << 3));
+            }
         }
 
         private ulong LOADBYTES(byte[] bytes, int inOff, int n)
@@ -261,34 +279,102 @@ namespace Org.BouncyCastle.Crypto.Engines
                 cOff += ASCON_AEAD_RATE;
                 mlen -= ASCON_AEAD_RATE;
             }
-            /* readonly plaintext block */
-            if (ASCON_AEAD_RATE == 16 && mlen >= 8)
+        }
+
+        private void ascon_decrypt(byte[] m, int mOff, byte[] c, int cOff, int clen)
+        {
+            /* full ciphertext blocks */
+            while (clen >= ASCON_AEAD_RATE)
             {
-                x0 ^= LOAD(m, mOff, 8);
-                STORE(c, cOff, x0, 8);
-                mOff += 8;
-                cOff += 8;
-                mlen -= 8;
-                x1 ^= PAD(mlen);
-                if (mlen != 0)
+                ulong cx = LOAD(c, cOff, 8);
+                x0 ^= cx;
+                STORE(m, mOff, x0, 8);
+                x0 = cx;
+                if (ASCON_AEAD_RATE == 16)
+                {
+                    cx = LOAD(c, cOff + 8, 8);
+                    x1 ^= cx;
+                    STORE(m, mOff + 8, x1, 8);
+                    x1 = cx;
+                }
+                P(nr);
+                mOff += ASCON_AEAD_RATE;
+                cOff += ASCON_AEAD_RATE;
+                clen -= ASCON_AEAD_RATE;
+            }
+        }
+
+        private ulong CLEAR(ulong w, int n)
+        {
+            /* undefined for n == 0 */
+            ulong mask = 0x00ffffffffffffffUL >> (n * 8 - 8);
+            return w & mask;
+        }
+
+        private void ascon_final(byte[] c, int cOff, byte[] m, int mOff, int mlen)
+        {
+            if (forEncryption)
+            {
+                /* final plaintext block */
+                if (ASCON_AEAD_RATE == 16 && mlen >= 8)
+                {
+                    x0 ^= LOAD(m, mOff, 8);
+                    STORE(c, cOff, x0, 8);
+                    mOff += 8;
+                    cOff += 8;
+                    mlen -= 8;
+                    x1 ^= PAD(mlen);
+                    if (mlen != 0)
+                    {
+                        x1 ^= LOAD(m, mOff, mlen);
+                        STORE(c, cOff, x1, mlen);
+                    }
+                }
+                else
                 {
-                    x1 ^= LOAD(m, mOff, mlen);
-                    STORE(c, cOff, x1, mlen);
+                    x0 ^= PAD(mlen);
+                    if (mlen != 0)
+                    {
+                        x0 ^= LOAD(m, mOff, mlen);
+                        STORE(c, cOff, x0, mlen);
+                    }
                 }
             }
             else
             {
-                x0 ^= PAD(mlen);
-                if (mlen != 0)
+                /* final ciphertext block */
+                if (ASCON_AEAD_RATE == 16 && mlen >= 8)
                 {
-                    x0 ^= LOAD(m, mOff, mlen);
-                    STORE(c, cOff, x0, mlen);
+                    ulong cx = LOAD(m, mOff, 8);
+                    x0 ^= cx;
+                    STORE(c, cOff, x0, 8);
+                    x0 = cx;
+                    mOff += 8;
+                    cOff += 8;
+                    mlen -= 8;
+                    x1 ^= PAD(mlen);
+                    if (mlen != 0)
+                    {
+                        cx = LOAD(m, mOff, mlen);
+                        x1 ^= cx;
+                        STORE(c, cOff, x1, mlen);
+                        x1 = CLEAR(x1, mlen);
+                        x1 ^= cx;
+                    }
+                }
+                else
+                {
+                    x0 ^= PAD(mlen);
+                    if (mlen != 0)
+                    {
+                        ulong cx = LOAD(m, mOff, mlen);
+                        x0 ^= cx;
+                        STORE(c, cOff, x0, mlen);
+                        x0 = CLEAR(x0, mlen);
+                        x0 ^= cx;
+                    }
                 }
             }
-        }
-
-        private void ascon_final()
-        {
             /* finalize */
             switch (asconParameters)
             {
@@ -313,10 +399,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public void Init(bool forEncryption, ICipherParameters param)
         {
-            /**
-            * ASCON encryption and decryption is completely symmetrical, so the
-            * 'forEncryption' is irrelevant.
-*/
+            this.forEncryption = forEncryption;
             if (!(param is ParametersWithIV))
             {
                 throw new ArgumentException(
@@ -352,18 +435,33 @@ namespace Org.BouncyCastle.Crypto.Engines
                 K1 = LOADBYTES(k, 4, 8);
                 K2 = LOADBYTES(k, 12, 8);
             }
+            initialised = true;
             /*Mask-Gen*/
-            Reset();
+            reset(false);
         }
 
         public void ProcessAadByte(byte input)
         {
+            if (aadFinished)
+            {
+                throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+                    " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+            }
             aadData.Write(new byte[] { input }, 0, 1);
         }
 
 
         public void ProcessAadBytes(byte[] input, int inOff, int len)
         {
+            if (aadFinished)
+            {
+                throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+                    " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+            }
+            if ((inOff + len) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
             aadData.Write(input, inOff, len);
         }
 
@@ -376,46 +474,127 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
         {
-            if (encrypted)
+            if (!initialised)
             {
-                throw new ArgumentException("ProcessBytes for ASCONcan be called once only");
+                throw new ArgumentException("Need call init function before encryption/decryption");
             }
-            byte[] ad = aadData.GetBuffer();
-            int adlen = (int)aadData.Length;
-            /* perform ascon computation */
-            //ascon_aeadinit();
-            ascon_adata(ad, 0, adlen);
-            ascon_encrypt(output, outOff, input, inOff, len);
-            ascon_final();
+            if ((inOff + len) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            message.Write(input, inOff, len);
+            int rv = processBytes(output, outOff);
             encrypted = true;
-            return len;
+            return rv;
+        }
+
+        private void processAAD()
+        {
+            if (!aadFinished)
+            {
+                byte[] ad = aadData.GetBuffer();
+                int adlen = (int)aadData.Length;
+                /* perform ascon computation */
+                ascon_adata(ad, 0, adlen);
+                aadFinished = true;
+            }
         }
 
+        private int processBytes(byte[] output, int outOff)
+        {
+            int len = 0;
+            if (forEncryption)
+            {
+                if ((int)message.Length >= ASCON_AEAD_RATE)
+                {
+                    processAAD();
+                    byte[] input = message.GetBuffer();
+                    len = ((int)message.Length / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
+                    if (len + outOff > output.Length)
+                    {
+                        throw new OutputLengthException("output buffer is too short");
+                    }
+                    ascon_encrypt(output, outOff, input, 0, len);
+                    int len_orig = (int)message.Length;
+                    message.SetLength(0);
+                    message.Write(input, len, len_orig - len);
+                }
+            }
+            else
+            {
+                if ((int)message.Length - CRYPTO_ABYTES >= ASCON_AEAD_RATE)
+                {
+                    processAAD();
+                    byte[] input = message.GetBuffer();
+                    len = (((int)message.Length - CRYPTO_ABYTES) / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
+                    if (len + outOff > output.Length)
+                    {
+                        throw new OutputLengthException("output buffer is too short");
+                    }
+                    ascon_decrypt(output, outOff, input, 0, len);
+                    int len_orig = (int)message.Length;
+                    message.SetLength(0);
+                    message.Write(input, len, len_orig - len);
+                }
+            }
+            return len;
+        }
 
         public int DoFinal(byte[] output, int outOff)
         {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            if (!aadFinished)
+            {
+                processAAD();
+            }
             if (!encrypted)
             {
                 ProcessBytes(new byte[] { }, 0, 0, new byte[] { }, 0);
             }
-            /* set tag */
-            STOREBYTES(output, outOff, x3, 8);
-            STOREBYTES(output, outOff + 8, x4, 8);
-            Reset();
-            return CRYPTO_ABYTES;
+            byte[] input = message.GetBuffer();
+            int len = (int)message.Length;
+            if ((forEncryption && outOff + len + CRYPTO_ABYTES > output.Length) ||
+                (!forEncryption && outOff + len - CRYPTO_ABYTES > output.Length))
+            {
+                throw new OutputLengthException("output buffer too short");
+            }
+            if (forEncryption)
+            {
+                ascon_final(output, outOff, input, 0, len);
+                /* set tag */
+                mac = new byte[16];
+                STOREBYTES(mac, 0, x3, 8);
+                STOREBYTES(mac, 8, x4, 8);
+                Array.Copy(mac, 0, output, len + outOff, 16);
+                reset(false);
+                return len + CRYPTO_ABYTES;
+            }
+            else
+            {
+                len -= CRYPTO_ABYTES;
+                ascon_final(output, outOff, input, 0, len);
+                x3 ^= LOADBYTES(input, len, 8);
+                x4 ^= LOADBYTES(input, len + 8, 8);
+                ulong result = x3 | x4;
+                result |= result >> 32;
+                result |= result >> 16;
+                result |= result >> 8;
+                reset(true);
+                if ((((((int)(result & 0xffUL) - 1) >> 8) & 1) - 1) != 0)
+                {
+                    throw new ArgumentException("Mac does not match");
+                }
+                return len;
+            }
         }
 
 
         public byte[] GetMac()
         {
-            if (!encrypted)
-            {
-                ProcessBytes(new byte[] { }, 0, 0, new byte[] { }, 0);
-            }
-            byte[] output = new byte[CRYPTO_ABYTES];
-            STOREBYTES(output, 0, x3, 8);
-            STOREBYTES(output, 8, x4, 8);
-            return output;
+            return mac;
         }
 
 
@@ -429,49 +608,86 @@ namespace Org.BouncyCastle.Crypto.Engines
             return len + CRYPTO_ABYTES;
         }
 
-
         public void Reset()
         {
+            reset(true);
+        }
+
+        private void reset(bool clearMac)
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
             x0 = x1 = x2 = x3 = x4 = 0;
             ascon_aeadinit();
             aadData.SetLength(0);
+            message.SetLength(0);
             encrypted = false;
+            aadFinished = false;
+            if (clearMac)
+            {
+                mac = null;
+            }
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public void ProcessAadBytes(ReadOnlySpan<byte> input)
         {
+            if (aadFinished)
+            {
+                throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+                    " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+            }
             aadData.Write(input);
         }
 
         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;
+            int len = ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return len;
         }
 
         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;
+            int len = ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return len;
         }
 
         public int DoFinal(Span<byte> output)
         {
-            byte[] tag = GetMac();
-            tag.AsSpan(0, tag.Length).CopyTo(output);
-            Reset();
-            return tag.Length;
+            byte[] rv;
+            if (forEncryption)
+            {
+                rv = new byte[message.Length + 16];
+            }
+            else
+            {
+                rv = new byte[message.Length];
+            }
+            int len = DoFinal(rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return rv.Length;
         }
 #endif
         public int GetBlockSize()
         {
             return ASCON_AEAD_RATE;
         }
+
+        public int GetKeyBytesSize()
+        {
+            return CRYPTO_KEYBYTES;
+        }
+
+        public int GetIVBytesSize()
+        {
+            return CRYPTO_ABYTES;
+        }
     }
 }
 
diff --git a/crypto/test/src/crypto/test/AsconTest.cs b/crypto/test/src/crypto/test/AsconTest.cs
index f1da9133f..1dc32ba4b 100644
--- a/crypto/test/src/crypto/test/AsconTest.cs
+++ b/crypto/test/src/crypto/test/AsconTest.cs
@@ -8,6 +8,8 @@ using Org.BouncyCastle.Utilities.Test;
 using System.Collections.Generic;
 using System.IO;
 using Org.BouncyCastle.Crypto.Engines;
+using System.Security.Cryptography;
+using Org.BouncyCastle.Crypto.Modes;
 
 namespace BouncyCastle.Crypto.Tests
 {
@@ -22,6 +24,15 @@ namespace BouncyCastle.Crypto.Tests
         [Test]
         public override void PerformTest()
         {
+            AsconEngine Ascon = new AsconEngine(AsconEngine.AsconParameters.ascon80pq);
+            testExceptions(Ascon, Ascon.GetKeyBytesSize(), Ascon.GetIVBytesSize(), Ascon.GetBlockSize());
+            testParameters(Ascon, 20, 16, 16, 8);
+            Ascon = new AsconEngine(AsconEngine.AsconParameters.ascon128a);
+            testExceptions(Ascon, Ascon.GetKeyBytesSize(), Ascon.GetIVBytesSize(), Ascon.GetBlockSize());
+            testParameters(Ascon, 16, 16, 16, 16);
+            Ascon = new AsconEngine(AsconEngine.AsconParameters.ascon128);
+            testExceptions(Ascon, Ascon.GetKeyBytesSize(), Ascon.GetIVBytesSize(), Ascon.GetBlockSize());
+            testParameters(Ascon, 16, 16, 16, 8);
             testVectors(AsconEngine.AsconParameters.ascon80pq, "160_128");
             testVectors(AsconEngine.AsconParameters.ascon128a, "128_128_a");
             testVectors(AsconEngine.AsconParameters.ascon128, "128_128");
@@ -37,7 +48,6 @@ namespace BouncyCastle.Crypto.Tests
             {
                 string line;
                 string[] data;
-                byte[] ptByte, adByte;
                 byte[] rv;
                 Dictionary<string, string> map = new Dictionary<string, string>();
                 while ((line = src.ReadLine()) != null)
@@ -45,19 +55,22 @@ namespace BouncyCastle.Crypto.Tests
                     data = line.Split(' ');
                     if (data.Length == 1)
                     {
-                        //if (!map["Count"].Equals("2"))
+                        //if (!map["Count"].Equals("265"))
                         //{
                         //    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);
                         Ascon.Init(true, param);
-                        adByte = Hex.Decode(map["AD"]);
-                        Ascon.ProcessAadBytes(adByte, 0, adByte.Length);
-                        ptByte = Hex.Decode(map["PT"]);
-                        rv = new byte[Ascon.GetOutputSize(ptByte.Length)];
-                        Ascon.ProcessBytes(ptByte, 0, ptByte.Length, rv, 0);
+                        Ascon.ProcessAadBytes(ad, 0, ad.Length);
+                        rv = new byte[Ascon.GetOutputSize(pt.Length)];
+                        int len = Ascon.ProcessBytes(pt, 0, pt.Length, rv, 0);
                         //byte[] mac = new byte[16];
-                        Ascon.DoFinal(rv, ptByte.Length);
+                        Ascon.DoFinal(rv, len);
                         //foreach(byte b in Hex.Decode(map["CT"]))
                         //{
                         //    Console.Write(b.ToString("X2"));
@@ -68,10 +81,20 @@ namespace BouncyCastle.Crypto.Tests
                         //    Console.Write(b.ToString("X2"));
                         //}
                         //Console.WriteLine();
-                        Assert.True(Arrays.AreEqual(rv, Hex.Decode(map["CT"])));
+                        Assert.True(Arrays.AreEqual(rv, ct));
+                        Ascon.Reset();
+                        Ascon.Init(false, param);
+                        //Decrypt
+                        Ascon.ProcessAadBytes(ad, 0, ad.Length);
+                        rv = new byte[pt.Length + 16];
+                        len = Ascon.ProcessBytes(ct, 0, ct.Length, rv, 0);
+                        Ascon.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();
-                        Ascon.Reset();
+
                     }
                     else
                     {
@@ -89,5 +112,320 @@ namespace BouncyCastle.Crypto.Tests
             }
             Console.WriteLine("Ascon AEAD pass");
         }
+
+
+        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[16], 0, 16, new byte[16], 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[16], 0, 16, new byte[16], 8);
+                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 NETCOREAPP2_1_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(AsconEngine ascon, int keySize, int ivSize, int macSize, int blockSize)
+        {
+            if (ascon.GetKeyBytesSize() != keySize)
+            {
+                Assert.Fail("key bytes of " + ascon.AlgorithmName + " is not correct");
+            }
+            if (ascon.GetIVBytesSize() != ivSize)
+            {
+                Assert.Fail("iv bytes of " + ascon.AlgorithmName + " is not correct");
+            }
+            if (ascon.GetOutputSize(0) != macSize)
+            {
+                Assert.Fail("mac bytes of " + ascon.AlgorithmName + " is not correct");
+            }
+            if (ascon.GetBlockSize() != blockSize)
+            {
+                Assert.Fail("block size of " + ascon.AlgorithmName + " is not correct");
+            }
+            Console.WriteLine(ascon.AlgorithmName + " test Parameters pass");
+        }
     }
-}
+}
\ No newline at end of file