summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-02-14 00:35:12 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-02-14 00:35:12 +0700
commit89b1a71ce769a26c6479c9ab73869967e25f9ac3 (patch)
treeefadd7d261a1240ba48f9be865abf0f6e0153e9c
parentRefactor LWC algorithms (diff)
downloadBouncyCastle.NET-ed25519-89b1a71ce769a26c6479c9ab73869967e25f9ac3.tar.xz
Rework AsconEngine
-rw-r--r--crypto/src/crypto/engines/AsconEngine.cs404
-rw-r--r--crypto/test/src/crypto/test/AsconTest.cs135
2 files changed, 305 insertions, 234 deletions
diff --git a/crypto/src/crypto/engines/AsconEngine.cs b/crypto/src/crypto/engines/AsconEngine.cs
index e8848c3d8..c7b203a8b 100644
--- a/crypto/src/crypto/engines/AsconEngine.cs
+++ b/crypto/src/crypto/engines/AsconEngine.cs
@@ -11,13 +11,11 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
-    /**
-    * ASCON AEAD v1.2, https://ascon.iaik.tugraz.at/
-    * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/ascon-spec-final.pdf
-    * <p>
-    * ASCON AEAD v1.2 with reference to C Reference Impl from: https://github.com/ascon/ascon-c
-    * </p>
-    */
+    /// <summary>ASCON v1.2 AEAD, https://ascon.iaik.tugraz.at/ .</summary>
+    /// <remarks>
+    /// https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/ascon-spec-final.pdf<br/>
+    /// ASCON v1.2 AEAD with reference to C Reference Impl from: https://github.com/ascon/ascon-c .
+    /// </remarks>
     public sealed class AsconEngine
         : IAeadCipher
     {
@@ -28,13 +26,23 @@ namespace Org.BouncyCastle.Crypto.Engines
             ascon128
         }
 
-        private readonly AsconParameters asconParameters;
+        private enum State
+        {
+            Uninitialized  = 0,
+            EncInit        = 1,
+            EncAad         = 2,
+            EncData        = 3,
+            EncFinal       = 4,
+            DecInit        = 5,
+            DecAad         = 6,
+            DecData        = 7,
+            DecFinal       = 8,
+        }
+
         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 AsconParameters asconParameters;
         private readonly int CRYPTO_KEYBYTES;
         private readonly int CRYPTO_ABYTES;
         private readonly int ASCON_AEAD_RATE;
@@ -52,8 +60,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         private ulong x3;
         private ulong x4;
         private string algorithmName;
-
-        public string AlgorithmName => algorithmName;
+        private State m_state = State.Uninitialized;
 
         public AsconEngine(AsconParameters asconParameters)
         {
@@ -85,7 +92,6 @@ namespace Org.BouncyCastle.Crypto.Engines
                 throw new ArgumentException("invalid parameter setting for ASCON AEAD");
             }
             nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
-            initialised = false;
         }
 
         public int GetKeyBytesSize()
@@ -98,9 +104,10 @@ namespace Org.BouncyCastle.Crypto.Engines
             return CRYPTO_ABYTES;
         }
 
+        public string AlgorithmName => algorithmName;
+
         public void Init(bool forEncryption, ICipherParameters parameters)
         {
-            this.forEncryption = forEncryption;
             if (!(parameters is ParametersWithIV withIV))
                 throw new ArgumentException("ASCON Init parameters must include an IV");
 
@@ -128,43 +135,36 @@ namespace Org.BouncyCastle.Crypto.Engines
                 K1 = Pack.BE_To_UInt64(k, 4);
                 K2 = Pack.BE_To_UInt64(k, 12);
             }
-            initialised = true;
-            /*Mask-Gen*/
+            else
+            {
+                throw new InvalidOperationException();
+            }
+
+            m_state = forEncryption ? State.EncInit : State.DecInit;
+
             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"));
-            }
+            CheckAad();
 
             aadData.WriteByte(input);
         }
 
         public void ProcessAadBytes(byte[] inBytes, 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"));
-            }
-
             Check.DataLength(inBytes, inOff, len, "input buffer too short");
 
+            CheckAad();
+
             aadData.Write(inBytes, inOff, len);
         }
 
 #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"));
-            }
+            CheckAad();
 
             aadData.Write(input);
         }
@@ -195,26 +195,34 @@ namespace Org.BouncyCastle.Crypto.Engines
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
             return ProcessBytes(inBytes.AsSpan(inOff, len), Spans.FromNullable(outBytes, outOff));
 #else
-            if (!initialised)
-                throw new ArgumentException("Need to call Init function before encryption/decryption");
+            CheckData();
 
             message.Write(inBytes, inOff, len);
-            int rv = ProcessBytes(outBytes, outOff);
-            encrypted = true;
-            return rv;
+
+            switch (m_state)
+            {
+            case State.DecData:     return ProcessBytes(false, outBytes, outOff);
+            case State.EncData:     return ProcessBytes(true, outBytes, outOff);
+            default:
+                throw new InvalidOperationException();
+            }
 #endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
         {
-            if (!initialised)
-                throw new ArgumentException("Need to call Init function before encryption/decryption");
+            CheckData();
 
             message.Write(input);
-            int rv = ProcessBytes(output);
-            encrypted = true;
-            return rv;
+
+            switch (m_state)
+            {
+            case State.DecData:     return ProcessBytes(false, output);
+            case State.EncData:     return ProcessBytes(true, output);
+            default:
+                throw new InvalidOperationException();
+            }
         }
 #endif
 
@@ -223,104 +231,91 @@ namespace Org.BouncyCastle.Crypto.Engines
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
             return DoFinal(outBytes.AsSpan(outOff));
 #else
-            if (!initialised)
-                throw new ArgumentException("Need to call Init before encryption/decryption");
+            CheckData();
 
-            if (!aadFinished)
-            {
-                ProcessAad();
-            }
-            if (!encrypted)
-            {
-                ProcessBytes(Array.Empty<byte>(), 0, 0, Array.Empty<byte>(), 0);
-            }
             byte[] input = message.GetBuffer();
             int len = Convert.ToInt32(message.Length);
-            if (forEncryption)
+
+            switch (m_state)
             {
-                Check.OutputLength(outBytes, outOff, len + CRYPTO_ABYTES, "output buffer too short");
-            }
-            else
+            case State.DecData:
             {
+                // TODO Check for underflow i.e. total input < CRYPTO_ABYTES
                 Check.OutputLength(outBytes, outOff, len - CRYPTO_ABYTES, "output buffer too short");
-            }
-            if (forEncryption)
-            {
-                ascon_final(outBytes, outOff, input, 0, len);
-                /* set tag */
-                mac = new byte[16];
-                Pack.UInt64_To_BE(x3, mac, 0);
-                Pack.UInt64_To_BE(x4, mac, 8);
-                Array.Copy(mac, 0, outBytes, len + outOff, 16);
-                Reset(false);
-                return len + CRYPTO_ABYTES;
-            }
-            else
-            {
                 len -= CRYPTO_ABYTES;
-                ascon_final(outBytes, outOff, input, 0, len);
+                ascon_final(false, outBytes, outOff, input, 0, len);
                 x3 ^= Pack.BE_To_UInt64(input, len);
                 x4 ^= Pack.BE_To_UInt64(input, len + 8);
                 ulong result = x3 | x4;
-                Reset(true);
 
                 if (result != 0UL)
                     throw new InvalidCipherTextException("mac check in " + AlgorithmName + " failed");
 
+                Reset(true);
                 return len;
             }
+            case State.EncData:
+            {
+                Check.OutputLength(outBytes, outOff, len + CRYPTO_ABYTES, "output buffer too short");
+                ascon_final(true, outBytes, outOff, input, 0, len);
+                mac = new byte[16];
+                Pack.UInt64_To_BE(x3, mac, 0);
+                Pack.UInt64_To_BE(x4, mac, 8);
+                Array.Copy(mac, 0, outBytes, len + outOff, 16);
+                Reset(false);
+                return len + CRYPTO_ABYTES;
+            }
+            default:
+                throw new InvalidOperationException();
+            }
 #endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public int DoFinal(Span<byte> output)
         {
-            if (!initialised)
-                throw new ArgumentException("Need to call Init before encryption/decryption");
+            CheckData();
 
-            if (!aadFinished)
-            {
-                ProcessAad();
-            }
-            if (!encrypted)
-            {
-                ProcessBytes(Array.Empty<byte>(), 0, 0, Array.Empty<byte>(), 0);
-            }
             byte[] input = message.GetBuffer();
             int len = Convert.ToInt32(message.Length);
-            if (forEncryption)
+
+            switch (m_state)
             {
-                Check.OutputLength(output, len + CRYPTO_ABYTES, "output buffer too short");
-            }
-            else
+            case State.DecData:
             {
+                // TODO Check for underflow i.e. total input < CRYPTO_ABYTES
                 Check.OutputLength(output, len - CRYPTO_ABYTES, "output buffer too short");
-            }
-            if (forEncryption)
-            {
-                ascon_final(output, input.AsSpan(0, len));
-                /* set tag */
-                mac = new byte[CRYPTO_ABYTES];
-                Pack.UInt64_To_BE(x3, mac, 0);
-                Pack.UInt64_To_BE(x4, mac, 8);
-                mac.AsSpan(0, CRYPTO_ABYTES).CopyTo(output[len..]);
-                Reset(false);
-                return len + CRYPTO_ABYTES;
-            }
-            else
-            {
                 len -= CRYPTO_ABYTES;
-                ascon_final(output, input.AsSpan(0, len));
+                ascon_final(false, output, input.AsSpan(0, len));
                 x3 ^= Pack.BE_To_UInt64(input, len);
                 x4 ^= Pack.BE_To_UInt64(input, len + 8);
                 ulong result = x3 | x4;
-                Reset(true);
+
+                FinishData(State.DecFinal);
 
                 if (result != 0UL)
                     throw new InvalidCipherTextException("mac check in " + AlgorithmName + " failed");
 
+                Reset(true);
                 return len;
             }
+            case State.EncData:
+            {
+                Check.OutputLength(output, len + CRYPTO_ABYTES, "output buffer too short");
+                ascon_final(true, output, input.AsSpan(0, len));
+                mac = new byte[CRYPTO_ABYTES];
+                Pack.UInt64_To_BE(x3, mac, 0);
+                Pack.UInt64_To_BE(x4, mac, 8);
+
+                FinishData(State.EncFinal);
+
+                mac.AsSpan(0, CRYPTO_ABYTES).CopyTo(output[len..]);
+                Reset(false);
+                return len + CRYPTO_ABYTES;
+            }
+            default:
+                throw new InvalidOperationException();
+            }
         }
 #endif
 
@@ -331,25 +326,37 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public int GetUpdateOutputSize(int len)
         {
-            int totalData = Convert.ToInt32(message.Length + len);
-            if (!forEncryption)
-            {
-                if (totalData < CRYPTO_ABYTES)
-                    return 0;
+            int total = Convert.ToInt32(message.Length + System.Math.Max(0, len));
 
-                totalData -= CRYPTO_ABYTES;
+            switch (m_state)
+            {
+            case State.DecInit:
+            case State.DecAad:
+            case State.DecData:
+            case State.DecFinal:
+                total = System.Math.Max(0, total - CRYPTO_ABYTES);
+                break;
+            default:
+                break;
             }
-            return totalData - totalData % ASCON_AEAD_RATE;
+
+            return total - total % ASCON_AEAD_RATE;
         }
 
         public int GetOutputSize(int len)
         {
-            int totalData = Convert.ToInt32(message.Length + len);
+            int total = Convert.ToInt32(message.Length + System.Math.Max(0, len));
 
-            if (forEncryption)
-                return totalData + CRYPTO_ABYTES;
-
-            return System.Math.Max(0, totalData - CRYPTO_ABYTES);
+            switch (m_state)
+            {
+            case State.DecInit:
+            case State.DecAad:
+            case State.DecData:
+            case State.DecFinal:
+                return System.Math.Max(0, total - CRYPTO_ABYTES);
+            default:
+                return total + CRYPTO_ABYTES;
+            }
         }
 
         public void Reset()
@@ -357,6 +364,67 @@ namespace Org.BouncyCastle.Crypto.Engines
             Reset(true);
         }
 
+        private void CheckAad()
+        {
+            switch (m_state)
+            {
+            case State.DecInit:
+                m_state = State.DecAad;
+                break;
+            case State.EncInit:
+                m_state = State.EncAad;
+                break;
+            case State.DecAad:
+            case State.EncAad:
+                break;
+            case State.EncFinal:
+                throw new InvalidOperationException(AlgorithmName + " cannot be reused for encryption");
+            default:
+                throw new InvalidOperationException();
+            }
+        }
+
+        private void CheckData()
+        {
+            switch (m_state)
+            {
+            case State.DecInit:
+            case State.DecAad:
+                FinishAad(State.DecData);
+                break;
+            case State.EncInit:
+            case State.EncAad:
+                FinishAad(State.EncData);
+                break;
+            case State.DecData:
+            case State.EncData:
+                break;
+            case State.EncFinal:
+                throw new InvalidOperationException(AlgorithmName + " cannot be reused for encryption");
+            default:
+                throw new InvalidOperationException();
+            }
+        }
+
+        private void FinishAad(State nextState)
+        {
+            byte[] aad = aadData.GetBuffer();
+            int aadLen = Convert.ToInt32(aadData.Length);
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            ascon_adata(aad.AsSpan(0, aadLen));
+#else
+            ascon_adata(aad, 0, aadLen);
+#endif
+
+            m_state = nextState;
+        }
+
+        private void FinishData(State nextState)
+        {
+            m_state = nextState;
+        }
+
         private void P(int nr)
         {
             if (nr >= 8)
@@ -396,34 +464,17 @@ namespace Org.BouncyCastle.Crypto.Engines
             x4 = t4 ^ Longs.RotateRight(t4, 7) ^ Longs.RotateRight(t4, 41);
         }
 
-        private void ProcessAad()
-        {
-            if (!aadFinished)
-            {
-                byte[] ad = aadData.GetBuffer();
-                int adlen = Convert.ToInt32(aadData.Length);
-                /* perform ascon computation */
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-                ascon_adata(ad.AsSpan(0, adlen));
-#else
-                ascon_adata(ad, 0, adlen);
-#endif
-                aadFinished = true;
-            }
-        }
-
         private void ascon_aeadinit()
         {
-            /* initialize */
-            x0 ^= ASCON_IV;
+            x0 = ASCON_IV;
             if (CRYPTO_KEYBYTES == 20)
             {
                 x0 ^= K0;
             }
-            x1 ^= K1;
-            x2 ^= K2;
-            x3 ^= N0;
-            x4 ^= N1;
+            x1 = K1;
+            x2 = K2;
+            x3 = N0;
+            x4 = N1;
             P(12);
             if (CRYPTO_KEYBYTES == 20)
             {
@@ -434,7 +485,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        private int ProcessBytes(Span<byte> output)
+        private int ProcessBytes(bool forEncryption, Span<byte> output)
         {
             int msgLen = Convert.ToInt32(message.Length);
             int outLen = 0;
@@ -442,7 +493,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             {
                 if (msgLen >= ASCON_AEAD_RATE)
                 {
-                    ProcessAad();
                     byte[] input = message.GetBuffer();
                     outLen = (msgLen / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
                     Check.OutputLength(output, outLen, "output buffer is too short");
@@ -455,7 +505,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             {
                 if (msgLen - CRYPTO_ABYTES >= ASCON_AEAD_RATE)
                 {
-                    ProcessAad();
                     byte[] input = message.GetBuffer();
                     outLen = ((msgLen - CRYPTO_ABYTES) / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
                     Check.OutputLength(output, outLen, "output buffer is too short");
@@ -547,7 +596,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
-        private void ascon_final(Span<byte> output, ReadOnlySpan<byte> input)
+        private void ascon_final(bool forEncryption, Span<byte> output, ReadOnlySpan<byte> input)
         {
             if (forEncryption)
             {
@@ -631,7 +680,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             x4 ^= K2;
         }
 #else
-        private int ProcessBytes(byte[] output, int outOff)
+        private int ProcessBytes(bool forEncryption, byte[] output, int outOff)
         {
             int msgLen = Convert.ToInt32(message.Length);
             int outLen = 0;
@@ -639,7 +688,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             {
                 if (msgLen >= ASCON_AEAD_RATE)
                 {
-                    ProcessAad();
                     byte[] input = message.GetBuffer();
                     outLen = (msgLen / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
                     Check.OutputLength(output, outOff, outLen, "output buffer is too short");
@@ -652,7 +700,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             {
                 if (msgLen - CRYPTO_ABYTES >= ASCON_AEAD_RATE)
                 {
-                    ProcessAad();
                     byte[] input = message.GetBuffer();
                     outLen = ((msgLen - CRYPTO_ABYTES) / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
                     Check.OutputLength(output, outOff, outLen, "output buffer is too short");
@@ -664,40 +711,40 @@ namespace Org.BouncyCastle.Crypto.Engines
             return outLen;
         }
 
-        private void ascon_adata(byte[] ad, int adOff, int adlen)
+        private void ascon_adata(byte[] aad, int aadOff, int aadLen)
         {
-            if (adlen != 0)
+            if (aadLen != 0)
             {
                 /* full associated data blocks */
-                while (adlen >= ASCON_AEAD_RATE)
+                while (aadLen >= ASCON_AEAD_RATE)
                 {
-                    x0 ^= Pack.BE_To_UInt64(ad, adOff);
+                    x0 ^= Pack.BE_To_UInt64(aad, aadOff);
                     if (ASCON_AEAD_RATE == 16)
                     {
-                        x1 ^= Pack.BE_To_UInt64(ad, adOff + 8);
+                        x1 ^= Pack.BE_To_UInt64(aad, aadOff + 8);
                     }
                     P(nr);
-                    adOff += ASCON_AEAD_RATE;
-                    adlen -= ASCON_AEAD_RATE;
+                    aadOff += ASCON_AEAD_RATE;
+                    aadLen -= ASCON_AEAD_RATE;
                 }
                 /* final associated data block */
-                if (ASCON_AEAD_RATE == 16 && adlen >= 8)
+                if (ASCON_AEAD_RATE == 16 && aadLen >= 8)
                 {
-                    x0 ^= Pack.BE_To_UInt64(ad, adOff);
-                    adOff += 8;
-                    adlen -= 8;
-                    x1 ^= PAD(adlen);
-                    if (adlen != 0)
+                    x0 ^= Pack.BE_To_UInt64(aad, aadOff);
+                    aadOff += 8;
+                    aadLen -= 8;
+                    x1 ^= PAD(aadLen);
+                    if (aadLen != 0)
                     {
-                        x1 ^= Pack.BE_To_UInt64_High(ad, adOff, adlen);
+                        x1 ^= Pack.BE_To_UInt64_High(aad, aadOff, aadLen);
                     }
                 }
                 else
                 {
-                    x0 ^= PAD(adlen);
-                    if (adlen != 0)
+                    x0 ^= PAD(aadLen);
+                    if (aadLen != 0)
                     {
-                        x0 ^= Pack.BE_To_UInt64_High(ad, adOff, adlen);
+                        x0 ^= Pack.BE_To_UInt64_High(aad, aadOff, aadLen);
                     }
                 }
                 P(nr);
@@ -748,7 +795,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
-        private void ascon_final(byte[] c, int cOff, byte[] m, int mOff, int mlen)
+        private void ascon_final(bool forEncryption, byte[] c, int cOff, byte[] m, int mOff, int mlen)
         {
             if (forEncryption)
             {
@@ -837,19 +884,34 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         private void Reset(bool clearMac)
         {
-            if (!initialised)
-                throw new ArgumentException("Need to call Init function before encryption/decryption");
+            if (clearMac)
+            {
+                mac = null;
+            }
 
-            x0 = x1 = x2 = x3 = x4 = 0;
-            ascon_aeadinit();
             aadData.SetLength(0);
             message.SetLength(0);
-            encrypted = false;
-            aadFinished = false;
-            if (clearMac)
+
+            switch (m_state)
             {
-                mac = null;
+            case State.DecInit:
+            case State.EncInit:
+                break;
+            case State.DecAad:
+            case State.DecData:
+            case State.DecFinal:
+                m_state = State.DecInit;
+                break;
+            case State.EncAad:
+            case State.EncData:
+            case State.EncFinal:
+                m_state = State.EncFinal;
+                return;
+            default:
+                throw new InvalidOperationException();
             }
+
+            ascon_aeadinit();
         }
 
         private static ulong PAD(int i)
diff --git a/crypto/test/src/crypto/test/AsconTest.cs b/crypto/test/src/crypto/test/AsconTest.cs
index 665673a55..95dd9c210 100644
--- a/crypto/test/src/crypto/test/AsconTest.cs
+++ b/crypto/test/src/crypto/test/AsconTest.cs
@@ -129,17 +129,17 @@ namespace Org.BouncyCastle.Crypto.Tests
                 asconEngine.ProcessBytes(m, 0, m.Length, null, 0);
                 Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before ProcessBytes");
             }
-            catch (ArgumentException)
+            catch (InvalidOperationException)
             {
                 //expected
             }
 
             try
             {
-                asconEngine.ProcessByte((byte)0, null, 0);
+                asconEngine.ProcessByte(0x00, null, 0);
                 Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before ProcessByte");
             }
-            catch (ArgumentException)
+            catch (InvalidOperationException)
             {
                 //expected
             }
@@ -149,7 +149,7 @@ namespace Org.BouncyCastle.Crypto.Tests
                 asconEngine.Reset();
                 Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before Reset");
             }
-            catch (ArgumentException)
+            catch (InvalidOperationException)
             {
                 //expected
             }
@@ -159,7 +159,7 @@ namespace Org.BouncyCastle.Crypto.Tests
                 asconEngine.DoFinal(null, m.Length);
                 Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before DoFinal");
             }
-            catch (ArgumentException)
+            catch (InvalidOperationException)
             {
                 //expected
             }
@@ -170,7 +170,7 @@ namespace Org.BouncyCastle.Crypto.Tests
                 asconEngine.GetOutputSize(0);
                 asconEngine.GetUpdateOutputSize(0);
             }
-            catch (ArgumentException)
+            catch (InvalidOperationException)
             {
                 //expected
                 Assert.Fail(asconEngine.AlgorithmName + " functions can be called before initialization");
@@ -220,38 +220,44 @@ namespace Org.BouncyCastle.Crypto.Tests
             {
                 Assert.Fail("mac should be equal when calling DoFinal and GetMac");
             }
-            asconEngine.ProcessAadByte((byte)0);
+
+            // TODO Maybe use a different IV for this
+            asconEngine.Init(true, param);
+            asconEngine.ProcessAadByte(0x00);
             byte[] mac1 = new byte[asconEngine.GetOutputSize(0)];
             asconEngine.DoFinal(mac1, 0);
             if (Arrays.AreEqual(mac1, mac2))
             {
                 Assert.Fail("mac should not match");
             }
-            asconEngine.Reset();
-            asconEngine.ProcessBytes(new byte[16], 0, 16, new byte[16], 0);
+
+            // TODO Maybe use a different IV for this
+            asconEngine.Init(true, param);
+            asconEngine.ProcessByte(0, null, 0);
             try
             {
-                asconEngine.ProcessAadByte((byte)0);
-                Assert.Fail("ProcessAadByte(s) cannot be called after encryption/decryption");
+                asconEngine.ProcessAadByte(0x00);
+                Assert.Fail("ProcessAadByte cannot be called after encryption/decryption");
             }
-            catch (ArgumentException)
+            catch (InvalidOperationException)
             {
                 //expected
             }
             try
             {
-                asconEngine.ProcessAadBytes(new byte[] { 0 }, 0, 1);
-                Assert.Fail("ProcessAadByte(s) cannot be called once only");
+                asconEngine.ProcessAadBytes(new byte[1], 0, 1);
+                Assert.Fail("ProcessAadBytes cannot be called after encryption/decryption");
             }
-            catch (ArgumentException)
+            catch (InvalidOperationException)
             {
                 //expected
             }
 
-            asconEngine.Reset();
+            // TODO Maybe use a different IV for this
+            asconEngine.Init(true, param);
             try
             {
-                asconEngine.ProcessAadBytes(new byte[] { 0 }, 1, 1);
+                asconEngine.ProcessAadBytes(new byte[1], 1, 1);
                 Assert.Fail("input for ProcessAadBytes is too short");
             }
             catch (DataLengthException)
@@ -260,13 +266,14 @@ namespace Org.BouncyCastle.Crypto.Tests
             }
             try
             {
-                asconEngine.ProcessBytes(new byte[] { 0 }, 1, 1, c1, 0);
+                asconEngine.ProcessBytes(new byte[1], 1, 1, c1, 0);
                 Assert.Fail("input for ProcessBytes is too short");
             }
             catch (DataLengthException)
             {
                 //expected
             }
+
             try
             {
                 int inputSize = rand.Next(32, 64);
@@ -290,40 +297,50 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             mac1 = new byte[asconEngine.GetOutputSize(0)];
             mac2 = new byte[asconEngine.GetOutputSize(0)];
-            asconEngine.Reset();
-            asconEngine.ProcessAadBytes(new byte[] { 0, 0 }, 0, 2);
+
+            // TODO Maybe use a different IV for this
+            asconEngine.Init(true, param);
+            asconEngine.ProcessAadBytes(new byte[2], 0, 2);
             asconEngine.DoFinal(mac1, 0);
-            asconEngine.Reset();
-            asconEngine.ProcessAadByte((byte)0);
-            asconEngine.ProcessAadByte((byte)0);
+
+            // TODO Maybe use a different IV for this
+            asconEngine.Init(true, param);
+            asconEngine.ProcessAadByte(0x00);
+            asconEngine.ProcessAadByte(0x00);
             asconEngine.DoFinal(mac2, 0);
+
             if (!Arrays.AreEqual(mac1, mac2))
             {
-                Assert.Fail("mac should match for the same AAD with different ways of inputing");
+                Assert.Fail("mac should match for the same AAD with different ways of inputting");
             }
 
-            byte[] c2 = new byte[asconEngine.GetOutputSize(10)];
-            byte[] c3 = new byte[asconEngine.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];
-            asconEngine.Reset();
+            byte[] c2 = new byte[asconEngine.GetOutputSize(m2.Length)];
+            byte[] c3 = new byte[asconEngine.GetOutputSize(m3.Length)];
+
+            // TODO Maybe use a different IV for this
+            asconEngine.Init(true, param);
             asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
             offset = asconEngine.ProcessBytes(m2, 0, m2.Length, c2, 0);
             asconEngine.DoFinal(c2, offset);
-            asconEngine.Reset();
+
+            // TODO Maybe use a different IV for this
+            asconEngine.Init(true, param);
             asconEngine.ProcessAadBytes(aad3, 1, aad2.Length);
             offset = asconEngine.ProcessBytes(m3, 1, m2.Length, c3, 1);
             asconEngine.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");
             }
-            asconEngine.Reset();
+
             asconEngine.Init(false, param);
             asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
             offset = asconEngine.ProcessBytes(c2, 0, c2.Length, m4, 0);
@@ -332,9 +349,9 @@ namespace Org.BouncyCastle.Crypto.Tests
             {
                 Assert.Fail("The encryption and decryption does not recover the plaintext");
             }
+
             c2[c2.Length - 1] ^= 1;
-            asconEngine.Reset();
-            asconEngine.Init(false, param);
+
             asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
             offset = asconEngine.ProcessBytes(c2, 0, c2.Length, m4, 0);
             try
@@ -351,6 +368,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             byte[] m7 = new byte[32 + rand.Next(32)];
             rand.NextBytes(m7);
 
+            // TODO Maybe use a different IV for this
             asconEngine.Init(true, param);
             byte[] c7 = new byte[asconEngine.GetOutputSize(m7.Length)];
             byte[] c8 = new byte[c7.Length];
@@ -358,12 +376,16 @@ namespace Org.BouncyCastle.Crypto.Tests
             asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
             offset = asconEngine.ProcessBytes(m7, 0, m7.Length, c7, 0);
             offset += asconEngine.DoFinal(c7, offset);
-            asconEngine.Reset();
+
+            // TODO Maybe use a different IV for this
+            asconEngine.Init(true, param);
             asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
             offset = asconEngine.ProcessBytes(m7, 0, m7.Length / 2, c8, 0);
             offset += asconEngine.ProcessBytes(m7, m7.Length / 2, m7.Length - m7.Length / 2, c8, offset);
             offset += asconEngine.DoFinal(c8, offset);
-            asconEngine.Reset();
+
+            // TODO Maybe use a different IV for this
+            asconEngine.Init(true, param);
             int split = rand.Next(1, m7.Length);
             asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
             offset = asconEngine.ProcessBytes(m7, 0, split, c9, 0);
@@ -374,37 +396,27 @@ namespace Org.BouncyCastle.Crypto.Tests
                 Assert.Fail("Splitting input of plaintext should output the same ciphertext");
             }
             // NOTE: .NET Core 3.1 has Span<T>, but is tested against our .NET Standard 2.0 assembly.
-//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            //#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
 #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);
+            // TODO Maybe use a different IV for this
             asconEngine.Init(true, param);
-            asconEngine.ProcessAadBytes(aad4);
-            offset = asconEngine.ProcessBytes(m5, c4_1);
-            asconEngine.DoFinal(c4_2);
-            byte[] c5 = new byte[c2.Length];
-            c4_1[..offset].CopyTo(c5);
-            c4_2[..(c5.Length - offset)].CopyTo(c5.AsSpan(offset));
-            if (!Arrays.AreEqual(c2, c5))
+            Span<byte> c4 = new byte[asconEngine.GetOutputSize(m2.Length)];
+            asconEngine.ProcessAadBytes(aad2);
+            offset = asconEngine.ProcessBytes(m2, c4);
+            offset += asconEngine.DoFinal(c4[offset..]);
+            if (!c4[..offset].SequenceEqual(c2))
             {
-                Assert.Fail("mac should match for the same AAD and message with different offset for both input and output");
+                Assert.Fail("Encryption should match for the same AAD and message with/without Span-based API");
             }
-            asconEngine.Reset();
+
             asconEngine.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);
-            asconEngine.ProcessAadBytes(aad4);
-            offset = asconEngine.ProcessBytes(c6, m6_1);
-            asconEngine.DoFinal(m6_2);
-            byte[] m6 = new byte[m2.Length];
-            m6_1[..offset].CopyTo(m6);
-            m6_2[..(m6.Length - offset)].CopyTo(m6.AsSpan(offset));
-            if (!Arrays.AreEqual(m2, m6))
+            Span<byte> m6 = new byte[m2.Length];
+            asconEngine.ProcessAadBytes(aad2);
+            offset = asconEngine.ProcessBytes(c2, m6);
+            offset += asconEngine.DoFinal(m6[offset..]);
+            if (!m6[..offset].SequenceEqual(m2))
             {
-                Assert.Fail("mac should match for the same AAD and message with different offset for both input and output");
+                Assert.Fail("Decryption should match for the same AAD and message with/without Span-based API");
             }
 #endif
         }
@@ -460,7 +472,6 @@ namespace Org.BouncyCastle.Crypto.Tests
                         {
                             map[data[0].Trim()] = "";
                         }
-
                     }
                 }
             }
@@ -468,10 +479,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 
         private void ImplTestExceptions(AsconDigest asconDigest, int digestSize)
         {
-            if (asconDigest.GetDigestSize() != digestSize)
-            {
-                Assert.Fail(asconDigest.AlgorithmName + ": digest size is not correct");
-            }
+            Assert.AreEqual(digestSize, asconDigest.GetDigestSize(),
+                asconDigest.AlgorithmName + ": digest size is not correct");
 
             try
             {