summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-08-24 22:30:53 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-08-24 22:30:53 +0700
commitcf62878dcfbb10a055dcbb460e1121cf3a693fb7 (patch)
tree654d0639d08f794e6f1f75df31b36418f5d0216f
parentFix GcmSivBlockCipher processing (diff)
downloadBouncyCastle.NET-ed25519-cf62878dcfbb10a055dcbb460e1121cf3a693fb7.tar.xz
Span-based variant for IAeadCipher.ProcessAadBytes
-rw-r--r--crypto/src/crypto/macs/GMac.cs11
-rw-r--r--crypto/src/crypto/modes/CcmBlockCipher.cs8
-rw-r--r--crypto/src/crypto/modes/ChaCha20Poly1305.cs13
-rw-r--r--crypto/src/crypto/modes/EAXBlockCipher.cs15
-rw-r--r--crypto/src/crypto/modes/GCMBlockCipher.cs46
-rw-r--r--crypto/src/crypto/modes/GcmSivBlockCipher.cs77
-rw-r--r--crypto/src/crypto/modes/IAeadCipher.cs7
-rw-r--r--crypto/src/crypto/modes/KCcmBlockCipher.cs7
-rw-r--r--crypto/src/crypto/modes/OCBBlockCipher.cs14
-rw-r--r--crypto/src/crypto/modes/gcm/GcmUtilities.cs15
10 files changed, 196 insertions, 17 deletions
diff --git a/crypto/src/crypto/macs/GMac.cs b/crypto/src/crypto/macs/GMac.cs
index 804097b3b..e0a448dda 100644
--- a/crypto/src/crypto/macs/GMac.cs
+++ b/crypto/src/crypto/macs/GMac.cs
@@ -89,16 +89,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public void BlockUpdate(ReadOnlySpan<byte> input)
         {
-            // TODO[span] Add span-based variant of ProcessAadBytes
-            byte[] tmp = new byte[64];
-            while (input.Length > 64)
-            {
-                input[..64].CopyTo(tmp);
-                input = input[64..];
-                cipher.ProcessAadBytes(tmp, 0, 64);
-            }
-            input.CopyTo(tmp);
-            cipher.ProcessAadBytes(tmp, 0, input.Length);
+            cipher.ProcessAadBytes(input);
         }
 #endif
 
diff --git a/crypto/src/crypto/modes/CcmBlockCipher.cs b/crypto/src/crypto/modes/CcmBlockCipher.cs
index 8f0acce52..256cc1b13 100644
--- a/crypto/src/crypto/modes/CcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/CcmBlockCipher.cs
@@ -117,6 +117,14 @@ namespace Org.BouncyCastle.Crypto.Modes
             associatedText.Write(inBytes, inOff, len);
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
+        {
+            // TODO: Process AAD online
+            associatedText.Write(input);
+        }
+#endif
+
         public virtual int ProcessByte(
             byte	input,
             byte[]	outBytes,
diff --git a/crypto/src/crypto/modes/ChaCha20Poly1305.cs b/crypto/src/crypto/modes/ChaCha20Poly1305.cs
index 462013200..385977fd5 100644
--- a/crypto/src/crypto/modes/ChaCha20Poly1305.cs
+++ b/crypto/src/crypto/modes/ChaCha20Poly1305.cs
@@ -209,6 +209,19 @@ namespace Org.BouncyCastle.Crypto.Modes
             }
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
+        {
+            CheckAad();
+
+            if (!input.IsEmpty)
+            {
+                this.mAadCount = IncrementCount(mAadCount, (uint)input.Length, AadLimit);
+                mPoly1305.BlockUpdate(input);
+            }
+        }
+#endif
+
         public virtual int ProcessByte(byte input, byte[] outBytes, int outOff)
         {
             CheckData();
diff --git a/crypto/src/crypto/modes/EAXBlockCipher.cs b/crypto/src/crypto/modes/EAXBlockCipher.cs
index 624f385b5..ffe32ec68 100644
--- a/crypto/src/crypto/modes/EAXBlockCipher.cs
+++ b/crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -194,13 +194,22 @@ namespace Org.BouncyCastle.Crypto.Modes
         public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
         {
             if (cipherInitialized)
-            {
                 throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
-            }
+
             mac.BlockUpdate(inBytes, inOff, len);
         }
 
-        public virtual int ProcessByte(
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
+		{
+			if (cipherInitialized)
+				throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
+
+			mac.BlockUpdate(input);
+		}
+#endif
+
+		public virtual int ProcessByte(
 			byte	input,
 			byte[]	outBytes,
 			int		outOff)
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index ac54e9762..bf9c14e28 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -278,6 +278,9 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            ProcessAadBytes(inBytes.AsSpan(inOff, len));
+#else
             CheckStatus();
 
             if (atBlockPos > 0)
@@ -309,7 +312,42 @@ namespace Org.BouncyCastle.Crypto.Modes
 
             atBlockPos = BlockSize + inLimit - inOff;
             Array.Copy(inBytes, inOff, atBlock, 0, atBlockPos);
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
+        {
+            CheckStatus();
+
+            if (atBlockPos > 0)
+            {
+                int available = BlockSize - atBlockPos;
+                if (input.Length < available)
+                {
+                    input.CopyTo(atBlock.AsSpan(atBlockPos));
+                    atBlockPos += input.Length;
+                    return;
+                }
+
+                input[..available].CopyTo(atBlock.AsSpan(atBlockPos));
+                gHASHBlock(S_at, atBlock);
+                atLength += BlockSize;
+                input = input[available..];
+                //atBlockPos = 0;
+            }
+
+            while (input.Length >= BlockSize)
+            {
+                gHASHBlock(S_at, input);
+                atLength += BlockSize;
+                input = input[BlockSize..];
+            }
+
+            input.CopyTo(atBlock);
+            atBlockPos = input.Length;
         }
+#endif
 
         private void InitCipher()
         {
@@ -930,6 +968,13 @@ namespace Org.BouncyCastle.Crypto.Modes
             }
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        private void gHASHBlock(byte[] Y, ReadOnlySpan<byte> b)
+        {
+            GcmUtilities.Xor(Y, b);
+            multiplier.MultiplyH(Y);
+        }
+#else
         private void gHASHBlock(byte[] Y, byte[] b)
         {
             GcmUtilities.Xor(Y, b);
@@ -941,6 +986,7 @@ namespace Org.BouncyCastle.Crypto.Modes
             GcmUtilities.Xor(Y, b, off);
             multiplier.MultiplyH(Y);
         }
+#endif
 
         private void gHASHPartial(byte[] Y, byte[] b, int off, int len)
         {
diff --git a/crypto/src/crypto/modes/GcmSivBlockCipher.cs b/crypto/src/crypto/modes/GcmSivBlockCipher.cs
index 63808a53a..284a952a6 100644
--- a/crypto/src/crypto/modes/GcmSivBlockCipher.cs
+++ b/crypto/src/crypto/modes/GcmSivBlockCipher.cs
@@ -1,7 +1,6 @@
 using System;
 using System.IO;
 
-using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Modes.Gcm;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
@@ -296,15 +295,30 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public virtual void ProcessAadBytes(byte[] pData, int pOffset, int pLen)
         {
-            /* Check that we can supply AEAD */
-            CheckAeadStatus(pLen);
-
             /* Check input buffer */
             CheckBuffer(pData, pOffset, pLen, false);
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            ProcessAadBytes(pData.AsSpan(pOffset, pLen));
+#else
+            /* Check that we can supply AEAD */
+            CheckAeadStatus(pLen);
+
             /* Process the aead */
             theAEADHasher.updateHash(pData, pOffset, pLen);
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
+        {
+            /* Check that we can supply AEAD */
+            CheckAeadStatus(input.Length);
+
+            /* Process the aead */
+            theAEADHasher.updateHash(input);
         }
+#endif
 
         public virtual int ProcessByte(byte pByte, byte[] pOutput, int pOutOffset)
         {
@@ -647,6 +661,18 @@ namespace Org.BouncyCastle.Crypto.Modes
             }
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        private static void fillReverse(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            /* Loop through the buffer */
+            for (int i = 0, j = BUFLEN - 1; i < input.Length; i++, j--)
+            {
+                /* Copy byte */
+                output[j] = input[i];
+            }
+        }
+#endif
+
         /**
         * xor a full block buffer.
         * @param pLeft the left operand and result
@@ -891,6 +917,49 @@ namespace Org.BouncyCastle.Crypto.Modes
                 numHashed += (ulong)pLen;
             }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            internal void updateHash(ReadOnlySpan<byte> buffer)
+            {
+                int pLen = buffer.Length;
+
+                /* If we should process the cache */
+                int mySpace = BUFLEN - numActive;
+                if (numActive > 0 && buffer.Length >= mySpace)
+                {
+                    /* Copy data into the cache and hash it */
+                    buffer[..mySpace].CopyTo(theBuffer.AsSpan(numActive));
+                    fillReverse(theBuffer, parent.theReverse);
+                    parent.gHASH(parent.theReverse);
+
+                    /* Adjust counters */
+                    buffer = buffer[mySpace..];
+                    numActive = 0;
+                }
+
+                /* While we have full blocks */
+                while (buffer.Length >= BUFLEN)
+                {
+                    /* Access the next data */
+                    fillReverse(buffer[..BUFLEN], parent.theReverse);
+                    parent.gHASH(parent.theReverse);
+
+                    /* Adjust counters */
+                    buffer = buffer[BUFLEN..];
+                }
+
+                /* If we have remaining data */
+                if (!buffer.IsEmpty)
+                {
+                    /* Copy data into the cache */
+                    buffer.CopyTo(theBuffer.AsSpan(numActive));
+                    numActive += buffer.Length;
+                }
+
+                /* Adjust the number of bytes processed */
+                numHashed += (ulong)pLen;
+            }
+#endif
+
             /**
             * complete hash.
             */
diff --git a/crypto/src/crypto/modes/IAeadCipher.cs b/crypto/src/crypto/modes/IAeadCipher.cs
index 437693cb6..c61e13b01 100644
--- a/crypto/src/crypto/modes/IAeadCipher.cs
+++ b/crypto/src/crypto/modes/IAeadCipher.cs
@@ -41,6 +41,13 @@ namespace Org.BouncyCastle.Crypto.Modes
         /// <param name="len">The number of bytes to be processed.</param>
         void ProcessAadBytes(byte[] inBytes, int inOff, int len);
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        /// <summary>Add a span of bytes to the associated data check.</summary>
+        /// <remarks>If the implementation supports it, this will be an online operation and will not retain the associated data.</remarks>
+        /// <param name="input">the span containing the data.</param>
+        void ProcessAadBytes(ReadOnlySpan<byte> input);
+#endif
+
         /**
 		* Encrypt/decrypt a single byte.
 		*
diff --git a/crypto/src/crypto/modes/KCcmBlockCipher.cs b/crypto/src/crypto/modes/KCcmBlockCipher.cs
index afa7063a3..afa68a794 100644
--- a/crypto/src/crypto/modes/KCcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/KCcmBlockCipher.cs
@@ -158,6 +158,13 @@ namespace Org.BouncyCastle.Crypto.Modes
             associatedText.Write(input, inOff, len);
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
+        {
+            associatedText.Write(input);
+        }
+#endif
+
         private void ProcessAAD(byte[] assocText, int assocOff, int assocLen, int dataLen)
         {
             if (assocLen - assocOff < engine.GetBlockSize())
diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs
index 28e88a6c9..db6aa39ae 100644
--- a/crypto/src/crypto/modes/OCBBlockCipher.cs
+++ b/crypto/src/crypto/modes/OCBBlockCipher.cs
@@ -287,6 +287,20 @@ namespace Org.BouncyCastle.Crypto.Modes
             }
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
+        {
+            for (int i = 0; i < input.Length; ++i)
+            {
+                hashBlock[hashBlockPos] = input[i];
+                if (++hashBlockPos == hashBlock.Length)
+                {
+                    ProcessHashBlock();
+                }
+            }
+        }
+#endif
+
         public virtual int ProcessByte(byte input, byte[] output, int outOff)
         {
             mainBlock[mainBlockPos] = input;
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index 676d74107..78a1f0860 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -275,6 +275,21 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             z.n1 = x.n1 ^ y.n1;
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        internal static void Xor(Span<byte> x, ReadOnlySpan<byte> y)
+        {
+            int i = 0;
+            do
+            {
+                x[i] ^= y[i]; ++i;
+                x[i] ^= y[i]; ++i;
+                x[i] ^= y[i]; ++i;
+                x[i] ^= y[i]; ++i;
+            }
+            while (i < 16);
+        }
+#endif
+
         private static ulong ImplMul64(ulong x, ulong y)
         {
             ulong x0 = x & 0x1111111111111111UL;