summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-08-24 14:37:11 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-08-24 14:37:11 +0700
commite643cf1909bc27a1307a27f31ac5b981f9ba225a (patch)
treee30dd5e80d94e7c4d6b9395a5cd0acde6ff87f7a
parentUse BitOperations when available (diff)
downloadBouncyCastle.NET-ed25519-e643cf1909bc27a1307a27f31ac5b981f9ba225a.tar.xz
Span-based variant for IMac.BlockUpdate
-rw-r--r--crypto/src/crypto/IMac.cs76
-rw-r--r--crypto/src/crypto/digests/SkeinDigest.cs4
-rw-r--r--crypto/src/crypto/digests/SkeinEngine.cs6
-rw-r--r--crypto/src/crypto/macs/CMac.cs43
-rw-r--r--crypto/src/crypto/macs/CbcBlockCipherMac.cs45
-rw-r--r--crypto/src/crypto/macs/CfbBlockCipherMac.cs51
-rw-r--r--crypto/src/crypto/macs/DSTU7564Mac.cs11
-rw-r--r--crypto/src/crypto/macs/DSTU7624Mac.cs196
-rw-r--r--crypto/src/crypto/macs/GMac.cs20
-rw-r--r--crypto/src/crypto/macs/GOST28147Mac.cs234
-rw-r--r--crypto/src/crypto/macs/HMac.cs7
-rw-r--r--crypto/src/crypto/macs/ISO9797Alg3Mac.cs38
-rw-r--r--crypto/src/crypto/macs/Poly1305.cs93
-rw-r--r--crypto/src/crypto/macs/SipHash.cs46
-rw-r--r--crypto/src/crypto/macs/SkeinMac.cs10
-rw-r--r--crypto/src/crypto/macs/VMPCMac.cs17
16 files changed, 613 insertions, 284 deletions
diff --git a/crypto/src/crypto/IMac.cs b/crypto/src/crypto/IMac.cs
index 03a86e8b6..3df4c354f 100644
--- a/crypto/src/crypto/IMac.cs
+++ b/crypto/src/crypto/IMac.cs
@@ -2,68 +2,44 @@ using System;
 
 namespace Org.BouncyCastle.Crypto
 {
-    /**
-     * The base interface for implementations of message authentication codes (MACs).
-     */
+    /// <summary>The base interface for implementations of message authentication codes (MACs).</summary>
     public interface IMac
     {
-        /**
-         * Initialise the MAC.
-         *
-         * @param param the key and other data required by the MAC.
-         * @exception ArgumentException if the parameters argument is
-         * inappropriate.
-         */
+        /// <summary>Initialise the MAC.</summary>
+        /// <param name="parameters">The key or other data required by the MAC.</param>
         void Init(ICipherParameters parameters);
 
-        /**
-         * Return the name of the algorithm the MAC implements.
-         *
-         * @return the name of the algorithm the MAC implements.
-         */
+        /// <summary>The algorithm name.</summary>
         string AlgorithmName { get; }
 
-		/**
-		 * Return the block size for this MAC (in bytes).
-		 *
-		 * @return the block size for this MAC in bytes.
-		 */
-		int GetMacSize();
+        /// <summary>Return the size, in bytes, of the MAC produced by this implementation.</summary>
+        /// <returns>the size, in bytes, of the MAC produced by this implementation.</returns>
+        int GetMacSize();
 
-        /**
-         * add a single byte to the mac for processing.
-         *
-         * @param in the byte to be processed.
-         * @exception InvalidOperationException if the MAC is not initialised.
-         */
+        /// <summary>Update the MAC with a single byte.</summary>
+        /// <param name="input">the input byte to be entered.</param>
         void Update(byte input);
 
-		/**
-         * @param in the array containing the input.
-         * @param inOff the index in the array the data begins at.
-         * @param len the length of the input starting at inOff.
-         * @exception InvalidOperationException if the MAC is not initialised.
-         * @exception DataLengthException if there isn't enough data in in.
-         */
-        void BlockUpdate(byte[] input, int inOff, int len);
+        /// <summary>Update the MAC with a block of bytes.</summary>
+        /// <param name="input">the byte array containing the data.</param>
+        /// <param name="inOff">the offset into the byte array where the data starts.</param>
+        /// <param name="inLen">the length of the data.</param>
+        void BlockUpdate(byte[] input, int inOff, int inLen);
 
-		/**
-         * Compute the final stage of the MAC writing the output to the out
-         * parameter.
-         * <p>
-         * doFinal leaves the MAC in the same state it was after the last init.
-         * </p>
-         * @param out the array the MAC is to be output to.
-         * @param outOff the offset into the out buffer the output is to start at.
-         * @exception DataLengthException if there isn't enough space in out.
-         * @exception InvalidOperationException if the MAC is not initialised.
-         */
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        /// <summary>Update the MAC with a span of bytes.</summary>
+        /// <param name="input">the span containing the data.</param>
+        void BlockUpdate(ReadOnlySpan<byte> input);
+#endif
+
+        /// <summary>Perform final calculations, producing the result MAC.</summary>
+        /// <remarks>This call leaves the MAC reset.</remarks>
+        /// <param name="output">the byte array the MAC is to be copied into.</param>
+        /// <param name="outOff">the offset into the byte array the MAC is to start at.</param>
+        /// <returns>the number of bytes written</returns>
         int DoFinal(byte[] output, int outOff);
 
-		/**
-         * Reset the MAC. At the end of resetting the MAC should be in the
-         * in the same state it was after the last init (if there was one).
-         */
+        /// <summary>Reset the MAC back to its initial state.</summary>
         void Reset();
     }
 }
diff --git a/crypto/src/crypto/digests/SkeinDigest.cs b/crypto/src/crypto/digests/SkeinDigest.cs
index 3dba9ec75..d56c0e788 100644
--- a/crypto/src/crypto/digests/SkeinDigest.cs
+++ b/crypto/src/crypto/digests/SkeinDigest.cs
@@ -102,7 +102,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 
 		public void BlockUpdate(byte[] inBytes, int inOff, int len)
 		{
-			engine.Update(inBytes, inOff, len);
+			engine.BlockUpdate(inBytes, inOff, len);
 		}
 
 		public int DoFinal(byte[] outBytes, int outOff)
@@ -113,7 +113,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public void BlockUpdate(ReadOnlySpan<byte> input)
         {
-            engine.Update(input);
+            engine.BlockUpdate(input);
         }
 
         public int DoFinal(Span<byte> output)
diff --git a/crypto/src/crypto/digests/SkeinEngine.cs b/crypto/src/crypto/digests/SkeinEngine.cs
index 86aa3c938..2535f786a 100644
--- a/crypto/src/crypto/digests/SkeinEngine.cs
+++ b/crypto/src/crypto/digests/SkeinEngine.cs
@@ -752,17 +752,17 @@ namespace Org.BouncyCastle.Crypto.Digests
         public void Update(byte inByte)
         {
             singleByte[0] = inByte;
-            Update(singleByte, 0, 1);
+            BlockUpdate(singleByte, 0, 1);
         }
 
-        public void Update(byte[] inBytes, int inOff, int len)
+        public void BlockUpdate(byte[] inBytes, int inOff, int len)
         {
             CheckInitialised();
             ubi.Update(inBytes, inOff, len, chain);
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        public void Update(ReadOnlySpan<byte> input)
+        public void BlockUpdate(ReadOnlySpan<byte> input)
         {
             CheckInitialised();
             ubi.Update(input, chain);
diff --git a/crypto/src/crypto/macs/CMac.cs b/crypto/src/crypto/macs/CMac.cs
index 682c12bac..dbd696429 100644
--- a/crypto/src/crypto/macs/CMac.cs
+++ b/crypto/src/crypto/macs/CMac.cs
@@ -132,8 +132,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             return ret;
         }
 
-        public void Init(
-            ICipherParameters parameters)
+        public void Init(ICipherParameters parameters)
         {
             if (parameters is KeyParameter)
             {
@@ -159,8 +158,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             return macSize;
         }
 
-        public void Update(
-            byte input)
+        public void Update(byte input)
         {
             if (bufOff == buf.Length)
             {
@@ -171,14 +169,14 @@ namespace Org.BouncyCastle.Crypto.Macs
             buf[bufOff++] = input;
         }
 
-        public void BlockUpdate(
-            byte[]	inBytes,
-            int		inOff,
-            int		len)
+        public void BlockUpdate(byte[] inBytes, int inOff, int len)
         {
             if (len < 0)
                 throw new ArgumentException("Can't have a negative input length!");
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            BlockUpdate(inBytes.AsSpan(inOff, len));
+#else
             int blockSize = cipher.GetBlockSize();
             int gapLen = blockSize - bufOff;
 
@@ -204,8 +202,37 @@ namespace Org.BouncyCastle.Crypto.Macs
             Array.Copy(inBytes, inOff, buf, bufOff, len);
 
             bufOff += len;
+#endif
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            int blockSize = cipher.GetBlockSize();
+            int gapLen = blockSize - bufOff;
+
+            if (input.Length > gapLen)
+            {
+                input[..gapLen].CopyTo(buf.AsSpan(bufOff));
+
+                cipher.ProcessBlock(buf, mac);
+
+                bufOff = 0;
+                input = input[gapLen..];
+
+                while (input.Length > blockSize)
+                {
+                    cipher.ProcessBlock(input, mac);
+                    input = input[blockSize..];
+                }
+            }
+
+            input.CopyTo(buf.AsSpan(bufOff));
+
+            bufOff += input.Length;
+        }
+#endif
+
         public int DoFinal(
             byte[]	outBytes,
             int		outOff)
diff --git a/crypto/src/crypto/macs/CbcBlockCipherMac.cs b/crypto/src/crypto/macs/CbcBlockCipherMac.cs
index 146e16aa8..de7a5f2e4 100644
--- a/crypto/src/crypto/macs/CbcBlockCipherMac.cs
+++ b/crypto/src/crypto/macs/CbcBlockCipherMac.cs
@@ -99,8 +99,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             get { return cipher.AlgorithmName; }
         }
 
-		public void Init(
-            ICipherParameters parameters)
+		public void Init(ICipherParameters parameters)
         {
             Reset();
 
@@ -112,8 +111,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             return macSize;
         }
 
-		public void Update(
-            byte input)
+		public void Update(byte input)
         {
 			if (bufOff == buf.Length)
             {
@@ -124,15 +122,15 @@ namespace Org.BouncyCastle.Crypto.Macs
 			buf[bufOff++] = input;
         }
 
-        public void BlockUpdate(
-            byte[]	input,
-            int		inOff,
-            int		len)
+        public void BlockUpdate(byte[] input, int inOff, int len)
         {
             if (len < 0)
                 throw new ArgumentException("Can't have a negative input length!");
 
-			int blockSize = cipher.GetBlockSize();
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            BlockUpdate(input.AsSpan(inOff, len));
+#else
+            int blockSize = cipher.GetBlockSize();
             int gapLen = blockSize - bufOff;
 
             if (len > gapLen)
@@ -157,7 +155,36 @@ namespace Org.BouncyCastle.Crypto.Macs
             Array.Copy(input, inOff, buf, bufOff, len);
 
             bufOff += len;
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            int blockSize = cipher.GetBlockSize();
+            int gapLen = blockSize - bufOff;
+
+            if (input.Length > gapLen)
+            {
+                input[..gapLen].CopyTo(buf.AsSpan(bufOff));
+
+                cipher.ProcessBlock(buf, buf);
+
+                bufOff = 0;
+                input = input[gapLen..];
+
+                while (input.Length > blockSize)
+                {
+                    cipher.ProcessBlock(input, buf);
+                    input = input[blockSize..];
+                }
+            }
+
+            input.CopyTo(buf.AsSpan(bufOff));
+
+            bufOff += input.Length;
         }
+#endif
 
         public int DoFinal(
             byte[]	output,
diff --git a/crypto/src/crypto/macs/CfbBlockCipherMac.cs b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
index e10bb438d..b454306e3 100644
--- a/crypto/src/crypto/macs/CfbBlockCipherMac.cs
+++ b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
@@ -263,8 +263,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             get { return cipher.AlgorithmName; }
         }
 
-		public void Init(
-            ICipherParameters parameters)
+		public void Init(ICipherParameters parameters)
         {
             Reset();
 
@@ -276,8 +275,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             return macSize;
         }
 
-		public void Update(
-            byte input)
+		public void Update(byte input)
         {
             if (bufOff == Buffer.Length)
             {
@@ -288,15 +286,15 @@ namespace Org.BouncyCastle.Crypto.Macs
 			Buffer[bufOff++] = input;
         }
 
-		public void BlockUpdate(
-            byte[]	input,
-            int		inOff,
-            int		len)
+		public void BlockUpdate(byte[] input, int inOff, int len)
         {
             if (len < 0)
                 throw new ArgumentException("Can't have a negative input length!");
 
-			int blockSize = cipher.GetBlockSize();
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            BlockUpdate(input.AsSpan(inOff, len));
+#else
+            int blockSize = cipher.GetBlockSize();
             int resultLen = 0;
             int gapLen = blockSize - bufOff;
 
@@ -322,11 +320,39 @@ namespace Org.BouncyCastle.Crypto.Macs
 			Array.Copy(input, inOff, Buffer, bufOff, len);
 
 			bufOff += len;
+#endif
         }
 
-		public int DoFinal(
-            byte[]	output,
-            int		outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            int blockSize = cipher.GetBlockSize();
+            int resultLen = 0;
+            int gapLen = blockSize - bufOff;
+
+            if (input.Length > gapLen)
+            {
+                input[..gapLen].CopyTo(Buffer.AsSpan(bufOff));
+
+                resultLen += cipher.ProcessBlock(Buffer, mac);
+
+                bufOff = 0;
+                input = input[gapLen..];
+
+                while (input.Length > blockSize)
+                {
+                    resultLen += cipher.ProcessBlock(input, mac);
+                    input = input[blockSize..];
+                }
+            }
+
+            input.CopyTo(Buffer.AsSpan(bufOff));
+
+            bufOff += input.Length;
+        }
+#endif
+
+        public int DoFinal(byte[] output, int outOff)
         {
             int blockSize = cipher.GetBlockSize();
 
@@ -367,5 +393,4 @@ namespace Org.BouncyCastle.Crypto.Macs
             cipher.Reset();
         }
     }
-
 }
diff --git a/crypto/src/crypto/macs/DSTU7564Mac.cs b/crypto/src/crypto/macs/DSTU7564Mac.cs
index fc905cc99..43fe7fb90 100644
--- a/crypto/src/crypto/macs/DSTU7564Mac.cs
+++ b/crypto/src/crypto/macs/DSTU7564Mac.cs
@@ -70,6 +70,17 @@ namespace Org.BouncyCastle.Crypto.Macs
             inputLength += (ulong)len;
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            if (paddedKey == null)
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+            engine.BlockUpdate(input);
+            inputLength += (ulong)input.Length;
+        }
+#endif
+
         public void Update(byte input)
         {
             engine.Update(input);
diff --git a/crypto/src/crypto/macs/DSTU7624Mac.cs b/crypto/src/crypto/macs/DSTU7624Mac.cs
index 953d8164f..01c1f869c 100644
--- a/crypto/src/crypto/macs/DSTU7624Mac.cs
+++ b/crypto/src/crypto/macs/DSTU7624Mac.cs
@@ -1,87 +1,89 @@
 using System;
 
-using Org.BouncyCastle.Utilities;
-using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Parameters;
-
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Macs
 {
-     /**
+    /**
      * implementation of DSTU 7624 MAC
      */
-     public class Dstu7624Mac : IMac
-     {
-          private int macSize;
-                    
-          private Dstu7624Engine engine;
-          private int blockSize;
+    public class Dstu7624Mac : IMac
+    {
+        private int macSize;
+
+        private Dstu7624Engine engine;
+        private int blockSize;
+
+        private byte[] c, cTemp, kDelta;
+        private byte[] buf;
+        private int bufOff;
+
+        public Dstu7624Mac(int blockSizeBits, int q)
+        {
+            engine = new Dstu7624Engine(blockSizeBits);
+
+            blockSize = blockSizeBits / 8;
 
-          private byte[] c, cTemp, kDelta;
-          private byte[] buf;
-          private int bufOff;
+            macSize = q / 8;
 
-          public Dstu7624Mac(int blockSizeBits, int q)
-          {
-               engine = new Dstu7624Engine(blockSizeBits);
+            c = new byte[blockSize];
 
-               blockSize = blockSizeBits / 8;
+            cTemp = new byte[blockSize];
 
-               macSize = q / 8;
+            kDelta = new byte[blockSize];
+            buf = new byte[blockSize];
+        }
+
+        public void Init(ICipherParameters parameters)
+        {
+            if (parameters is KeyParameter)
+            {
+                engine.Init(true, (KeyParameter)parameters);
+
+                engine.ProcessBlock(kDelta, 0, kDelta, 0);
+            }
+            else
+            {
+                throw new ArgumentException("invalid parameter passed to Dstu7624Mac init - "
+                + Platform.GetTypeName(parameters));
+            }
+        }
 
-               c = new byte[blockSize];
-              
-               cTemp = new byte[blockSize];
+        public string AlgorithmName
+        {
+            get { return "Dstu7624Mac"; }
+        }
 
-               kDelta = new byte[blockSize];
-               buf = new byte[blockSize];
+        public int GetMacSize()
+        {
+            return macSize;
         }
 
-          public void Init(ICipherParameters parameters)
-          {
-               if (parameters is KeyParameter)
-               {
-                    engine.Init(true, (KeyParameter)parameters);
-
-                    engine.ProcessBlock(kDelta, 0, kDelta, 0);
-               }
-               else
-               {
-                    throw new ArgumentException("invalid parameter passed to Dstu7624Mac init - "
-                    + Platform.GetTypeName(parameters));
-               }             
-          }
-
-          public string AlgorithmName
-          {
-               get { return "Dstu7624Mac"; }
-          }
-
-          public int GetMacSize()
-          {
-               return macSize;
-          }
-
-          public void Update(byte input)
-          {
+        public void Update(byte input)
+        {
             if (bufOff == buf.Length)
             {
-                processBlock(buf, 0);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                ProcessBlock(buf);
+#else
+                ProcessBlock(buf, 0);
+#endif
                 bufOff = 0;
             }
 
             buf[bufOff++] = input;
         }
 
-          public void BlockUpdate(byte[] input, int inOff, int len)
-          {
+        public void BlockUpdate(byte[] input, int inOff, int len)
+        {
             if (len < 0)
-            {
-                throw new ArgumentException(
-                    "Can't have a negative input length!");
-            }
+                throw new ArgumentException("Can't have a negative input length!");
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            BlockUpdate(input.AsSpan(inOff, len));
+#else
             int blockSize = engine.GetBlockSize();
             int gapLen = blockSize - bufOff;
 
@@ -89,7 +91,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             {
                 Array.Copy(input, inOff, buf, bufOff, gapLen);
 
-                processBlock(buf, 0);
+                ProcessBlock(buf, 0);
 
                 bufOff = 0;
                 len -= gapLen;
@@ -97,7 +99,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 
                 while (len > blockSize)
                 {
-                    processBlock(input, inOff);
+                    ProcessBlock(input, inOff);
 
                     len -= blockSize;
                     inOff += blockSize;
@@ -107,29 +109,73 @@ namespace Org.BouncyCastle.Crypto.Macs
             Array.Copy(input, inOff, buf, bufOff, len);
 
             bufOff += len;
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            int blockSize = engine.GetBlockSize();
+            int gapLen = blockSize - bufOff;
+
+            if (input.Length > gapLen)
+            {
+                input[..gapLen].CopyTo(buf.AsSpan(bufOff));
+
+                ProcessBlock(buf);
+
+                bufOff = 0;
+                input = input[gapLen..];
+
+                while (input.Length > blockSize)
+                {
+                    ProcessBlock(input);
+                    input = input[blockSize..];
+                }
+            }
+
+            input.CopyTo(buf.AsSpan(bufOff));
+
+            bufOff += input.Length;
+        }
+#endif
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        private void ProcessBlock(ReadOnlySpan<byte> input)
+        {
+            Xor(c, input, cTemp);
+
+            engine.ProcessBlock(cTemp, c);
         }
 
-        private void processBlock(byte[] input, int inOff)
+        private void Xor(ReadOnlySpan<byte> c, ReadOnlySpan<byte> input, Span<byte> xorResult)
+        {
+            for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
+            {
+                xorResult[byteIndex] = (byte)(c[byteIndex] ^ input[byteIndex]);
+            }
+        }
+#else
+        private void ProcessBlock(byte[] input, int inOff)
         {
             Xor(c, 0, input, inOff, cTemp);
 
             engine.ProcessBlock(cTemp, 0, c, 0);
         }
+#endif
 
         private void Xor(byte[] c, int cOff, byte[] input, int inOff, byte[] xorResult)
-          {
-               for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
-               {
-                    xorResult[byteIndex] = (byte)(c[byteIndex + cOff] ^ input[byteIndex + inOff]);
-               }
-          }
-
-          public int DoFinal(byte[] output, int outOff)
-          {
-            if (bufOff % buf.Length != 0)
+        {
+            for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
             {
-                throw new DataLengthException("Input must be a multiple of blocksize");
+                xorResult[byteIndex] = (byte)(c[byteIndex + cOff] ^ input[byteIndex + inOff]);
             }
+        }
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (bufOff % buf.Length != 0)
+                throw new DataLengthException("Input must be a multiple of blocksize");
 
             //Last block
             Xor(c, 0, buf, 0, cTemp);
@@ -137,17 +183,15 @@ namespace Org.BouncyCastle.Crypto.Macs
             engine.ProcessBlock(c, 0, c, 0);
 
             if (macSize + outOff > output.Length)
-            {
                 throw new DataLengthException("Output buffer too short");
-            }
 
             Array.Copy(c, 0, output, outOff, macSize);
 
             return macSize;
         }
 
-          public void Reset()
-          {
+        public void Reset()
+        {
             Arrays.Fill(c, (byte)0x00);
             Arrays.Fill(cTemp, (byte)0x00);
             Arrays.Fill(kDelta, (byte)0x00);
@@ -156,5 +200,5 @@ namespace Org.BouncyCastle.Crypto.Macs
             engine.ProcessBlock(kDelta, 0, kDelta, 0);
             bufOff = 0;
         }
-     }
+    }
 }
diff --git a/crypto/src/crypto/macs/GMac.cs b/crypto/src/crypto/macs/GMac.cs
index 0554c44f0..804097b3b 100644
--- a/crypto/src/crypto/macs/GMac.cs
+++ b/crypto/src/crypto/macs/GMac.cs
@@ -52,10 +52,8 @@ namespace Org.BouncyCastle.Crypto.Macs
         /// </summary>
         public void Init(ICipherParameters parameters)
         {
-            if (parameters is ParametersWithIV)
+            if (parameters is ParametersWithIV param)
             {
-                ParametersWithIV param = (ParametersWithIV)parameters;
-
                 byte[] iv = param.GetIV();
                 KeyParameter keyParam = (KeyParameter)param.Parameters;
 
@@ -88,6 +86,22 @@ namespace Org.BouncyCastle.Crypto.Macs
             cipher.ProcessAadBytes(input, inOff, len);
         }
 
+#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);
+        }
+#endif
+
         public int DoFinal(byte[] output, int outOff)
         {
             try
diff --git a/crypto/src/crypto/macs/GOST28147Mac.cs b/crypto/src/crypto/macs/GOST28147Mac.cs
index 33c2d67ee..6a6907934 100644
--- a/crypto/src/crypto/macs/GOST28147Mac.cs
+++ b/crypto/src/crypto/macs/GOST28147Mac.cs
@@ -1,7 +1,7 @@
 using System;
 
-using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Macs
@@ -9,10 +9,11 @@ namespace Org.BouncyCastle.Crypto.Macs
 	/**
 	* implementation of GOST 28147-89 MAC
 	*/
-	public class Gost28147Mac : IMac
+	public class Gost28147Mac
+		: IMac
 	{
-		private const int			blockSize = 8;
-		private const int			macSize = 4;
+		private const int			BlockSize = 8;
+		private const int			MacSize = 4;
 		private int					bufOff;
 		private byte[]				buf;
 		private byte[]				mac;
@@ -36,8 +37,8 @@ namespace Org.BouncyCastle.Crypto.Macs
 
 		public Gost28147Mac()
 		{
-			mac = new byte[blockSize];
-			buf = new byte[blockSize];
+			mac = new byte[BlockSize];
+			buf = new byte[BlockSize];
 			bufOff = 0;
 		}
 
@@ -50,22 +51,19 @@ namespace Org.BouncyCastle.Crypto.Macs
 			int[] key = new int[8];
 			for(int i=0; i!=8; i++)
 			{
-				key[i] = bytesToint(userKey,i*4);
+				key[i] = (int)Pack.LE_To_UInt32(userKey, i * 4);
 			}
 
 			return key;
 		}
 
-		public void Init(
-			ICipherParameters parameters)
+		public void Init(ICipherParameters parameters)
 		{
 			Reset();
-			buf = new byte[blockSize];
+			buf = new byte[BlockSize];
             macIV = null;
-            if (parameters is ParametersWithSBox)
+            if (parameters is ParametersWithSBox param)
 			{
-				ParametersWithSBox param = (ParametersWithSBox)parameters;
-
 				//
 				// Set the S-Box
 				//
@@ -79,17 +77,15 @@ namespace Org.BouncyCastle.Crypto.Macs
 					workingKey = GenerateWorkingKey(((KeyParameter)param.Parameters).GetKey());
 				}
 			}
-			else if (parameters is KeyParameter)
+			else if (parameters is KeyParameter keyParameter)
 			{
-				workingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey());
+				workingKey = GenerateWorkingKey(keyParameter.GetKey());
 			}
-            else if (parameters is ParametersWithIV)
+            else if (parameters is ParametersWithIV ivParam)
             {
-                ParametersWithIV p = (ParametersWithIV)parameters;
-
-                workingKey = GenerateWorkingKey(((KeyParameter)p.Parameters).GetKey());
-                Array.Copy(p.GetIV(), 0, mac, 0, mac.Length);
-                macIV = p.GetIV(); // don't skip the initial CM5Func
+                workingKey = GenerateWorkingKey(((KeyParameter)ivParam.Parameters).GetKey());
+				macIV = ivParam.GetIV(); // don't skip the initial CM5Func
+				Array.Copy(macIV, 0, mac, 0, mac.Length);
             }
 			else
 			{
@@ -105,10 +101,10 @@ namespace Org.BouncyCastle.Crypto.Macs
 
 		public int GetMacSize()
 		{
-			return macSize;
+			return MacSize;
 		}
 
-		private int gost28147_mainStep(int n1, int key)
+		private int Gost28147_mainStep(int n1, int key)
 		{
 			int cm = (key + n1); // CM1
 
@@ -130,177 +126,187 @@ namespace Org.BouncyCastle.Crypto.Macs
 			return omLeft | omRight;
 		}
 
-		private void gost28147MacFunc(
+		private void Gost28147MacFunc(
 			int[]	workingKey,
 			byte[]	input,
 			int		inOff,
 			byte[]	output,
 			int		outOff)
 		{
-			int N1, N2, tmp;  //tmp -> for saving N1
-			N1 = bytesToint(input, inOff);
-			N2 = bytesToint(input, inOff + 4);
+			int N1 = (int)Pack.LE_To_UInt32(input, inOff);
+			int N2 = (int)Pack.LE_To_UInt32(input, inOff + 4);
+			int tmp;  //tmp -> for saving N1
 
 			for (int k = 0; k < 2; k++)  // 1-16 steps
 			{
 				for (int j = 0; j < 8; j++)
 				{
 					tmp = N1;
-					N1 = N2 ^ gost28147_mainStep(N1, workingKey[j]); // CM2
+					N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
 					N2 = tmp;
 				}
 			}
 
-			intTobytes(N1, output, outOff);
-			intTobytes(N2, output, outOff + 4);
-		}
-
-		//array of bytes to type int
-		private static int bytesToint(
-			byte[]	input,
-			int		inOff)
-		{
-			return (int)((input[inOff + 3] << 24) & 0xff000000) + ((input[inOff + 2] << 16) & 0xff0000)
-				+ ((input[inOff + 1] << 8) & 0xff00) + (input[inOff] & 0xff);
-		}
-
-		//int to array of bytes
-		private static void intTobytes(
-			int		num,
-			byte[]	output,
-			int		outOff)
-		{
-			output[outOff + 3] = (byte)(num >> 24);
-			output[outOff + 2] = (byte)(num >> 16);
-			output[outOff + 1] = (byte)(num >> 8);
-			output[outOff] =     (byte)num;
-		}
-
-		private static byte[] CM5func(
-			byte[]	buf,
-			int		bufOff,
-			byte[]	mac)
-		{
-			byte[] sum = new byte[buf.Length - bufOff];
-
-			Array.Copy(buf, bufOff, sum, 0, mac.Length);
-
-			for (int i = 0; i != mac.Length; i++)
-			{
-				sum[i] = (byte)(sum[i] ^ mac[i]);
-			}
-
-			return sum;
+			Pack.UInt32_To_LE((uint)N1, output, outOff);
+			Pack.UInt32_To_LE((uint)N2, output, outOff + 4);
 		}
 
-		public void Update(
-			byte input)
+		public void Update(byte input)
 		{
 			if (bufOff == buf.Length)
 			{
-				byte[] sumbuf = new byte[buf.Length];
-				Array.Copy(buf, 0, sumbuf, 0, mac.Length);
-
+				byte[] sum = new byte[buf.Length];
 				if (firstStep)
 				{
 					firstStep = false;
                     if (macIV != null)
                     {
-                        sumbuf = CM5func(buf, 0, macIV);
+                        Cm5Func(buf, 0, macIV, sum);
                     }
-                }
+					else
+                    {
+						Array.Copy(buf, 0, sum, 0, mac.Length);
+					}
+				}
 				else
 				{
-					sumbuf = CM5func(buf, 0, mac);
+					Cm5Func(buf, 0, mac, sum);
 				}
 
-				gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+				Gost28147MacFunc(workingKey, sum, 0, mac, 0);
 				bufOff = 0;
 			}
 
 			buf[bufOff++] = input;
 		}
 
-		public void BlockUpdate(
-			byte[]	input,
-			int		inOff,
-			int		len)
+		public void BlockUpdate(byte[] input, int inOff, int len)
 		{
 			if (len < 0)
 				throw new ArgumentException("Can't have a negative input length!");
 
-			int gapLen = blockSize - bufOff;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+			BlockUpdate(input.AsSpan(inOff, len));
+#else
+			int gapLen = BlockSize - bufOff;
 
 			if (len > gapLen)
 			{
 				Array.Copy(input, inOff, buf, bufOff, gapLen);
 
-				byte[] sumbuf = new byte[buf.Length];
-				Array.Copy(buf, 0, sumbuf, 0, mac.Length);
-
+				byte[] sum = new byte[buf.Length];
 				if (firstStep)
 				{
 					firstStep = false;
                     if (macIV != null)
                     {
-                        sumbuf = CM5func(buf, 0, macIV);
+                        Cm5Func(buf, 0, macIV, sum);
                     }
-                }
+					else
+                    {
+						Array.Copy(buf, 0, sum, 0, mac.Length);
+					}
+				}
 				else
 				{
-					sumbuf = CM5func(buf, 0, mac);
+					Cm5Func(buf, 0, mac, sum);
 				}
 
-				gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+				Gost28147MacFunc(workingKey, sum, 0, mac, 0);
 
 				bufOff = 0;
 				len -= gapLen;
 				inOff += gapLen;
 
-				while (len > blockSize)
+				while (len > BlockSize)
 				{
-					sumbuf = CM5func(input, inOff, mac);
-					gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+					Cm5Func(input, inOff, mac, sum);
+					Gost28147MacFunc(workingKey, sum, 0, mac, 0);
 
-					len -= blockSize;
-					inOff += blockSize;
+					len -= BlockSize;
+					inOff += BlockSize;
 				}
 			}
 
 			Array.Copy(input, inOff, buf, bufOff, len);
 
 			bufOff += len;
+#endif
 		}
 
-		public int DoFinal(
-			byte[]	output,
-			int		outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public void BlockUpdate(ReadOnlySpan<byte> input)
+		{
+			int gapLen = BlockSize - bufOff;
+
+			if (input.Length > gapLen)
+			{
+				input[..gapLen].CopyTo(buf.AsSpan(bufOff));
+
+				byte[] sum = new byte[buf.Length];
+				if (firstStep)
+				{
+					firstStep = false;
+                    if (macIV != null)
+                    {
+                        Cm5Func(buf, macIV, sum);
+                    }
+                    else
+                    {
+						Array.Copy(buf, 0, sum, 0, mac.Length);
+					}
+				}
+				else
+				{
+					Cm5Func(buf, mac, sum);
+				}
+
+				Gost28147MacFunc(workingKey, sum, 0, mac, 0);
+
+				bufOff = 0;
+				input = input[gapLen..];
+
+				while (input.Length > BlockSize)
+				{
+					Cm5Func(input, mac, sum);
+					Gost28147MacFunc(workingKey, sum, 0, mac, 0);
+
+					input = input[BlockSize..];
+				}
+			}
+
+			input.CopyTo(buf.AsSpan(bufOff));
+
+			bufOff += input.Length;
+		}
+#endif
+
+		public int DoFinal(byte[] output, int outOff)
 		{
 			//padding with zero
-			while (bufOff < blockSize)
+			while (bufOff < BlockSize)
 			{
 				buf[bufOff++] = 0;
 			}
 
-			byte[] sumbuf = new byte[buf.Length];
-			Array.Copy(buf, 0, sumbuf, 0, mac.Length);
-
+			byte[] sum = new byte[buf.Length];
 			if (firstStep)
 			{
 				firstStep = false;
+				Array.Copy(buf, 0, sum, 0, mac.Length);
 			}
 			else
 			{
-				sumbuf = CM5func(buf, 0, mac);
+				Cm5Func(buf, 0, mac, sum);
 			}
 
-			gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+			Gost28147MacFunc(workingKey, sum, 0, mac, 0);
 
-			Array.Copy(mac, (mac.Length/2)-macSize, output, outOff, macSize);
+			Array.Copy(mac, (mac.Length/2)-MacSize, output, outOff, MacSize);
 
 			Reset();
 
-			return macSize;
+			return MacSize;
 		}
 
 		public void Reset()
@@ -311,5 +317,23 @@ namespace Org.BouncyCastle.Crypto.Macs
 
 			firstStep = true;
 		}
+
+		private static void Cm5Func(byte[] buf, int bufOff, byte[] mac, byte[] sum)
+		{
+			for (int i = 0; i < BlockSize; ++i)
+			{
+				sum[i] = (byte)(buf[bufOff + i] ^ mac[i]);
+			}
+		}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		private static void Cm5Func(ReadOnlySpan<byte> buffer, ReadOnlySpan<byte> mac, Span<byte> sum)
+		{
+			for (int i = 0; i < BlockSize; ++i)
+			{
+				sum[i] = (byte)(buffer[i] ^ mac[i]);
+			}
+		}
+#endif
 	}
 }
diff --git a/crypto/src/crypto/macs/HMac.cs b/crypto/src/crypto/macs/HMac.cs
index a717ce4f7..389c03a23 100644
--- a/crypto/src/crypto/macs/HMac.cs
+++ b/crypto/src/crypto/macs/HMac.cs
@@ -99,6 +99,13 @@ namespace Org.BouncyCastle.Crypto.Macs
             digest.BlockUpdate(input, inOff, len);
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            digest.BlockUpdate(input);
+        }
+#endif
+
         public virtual int DoFinal(byte[] output, int outOff)
         {
             digest.DoFinal(outputBuf, blockLength);
diff --git a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
index 6fee619c1..f516e9b96 100644
--- a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
+++ b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
@@ -180,14 +180,14 @@ namespace Org.BouncyCastle.Crypto.Macs
 			buf[bufOff++] = input;
 		}
 
-		public void BlockUpdate(
-			byte[]	input,
-			int		inOff,
-			int		len)
+		public void BlockUpdate(byte[] input, int inOff, int len)
 		{
 			if (len < 0)
 				throw new ArgumentException("Can't have a negative input length!");
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+			BlockUpdate(input.AsSpan(inOff, len));
+#else
 			int blockSize = cipher.GetBlockSize();
 			int resultLen = 0;
 			int gapLen = blockSize - bufOff;
@@ -214,8 +214,38 @@ namespace Org.BouncyCastle.Crypto.Macs
 			Array.Copy(input, inOff, buf, bufOff, len);
 
 			bufOff += len;
+#endif
 		}
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public void BlockUpdate(ReadOnlySpan<byte> input)
+		{
+			int blockSize = cipher.GetBlockSize();
+			int resultLen = 0;
+			int gapLen = blockSize - bufOff;
+
+			if (input.Length > gapLen)
+			{
+				input[..gapLen].CopyTo(buf.AsSpan(bufOff));
+
+				resultLen += cipher.ProcessBlock(buf, mac);
+
+				bufOff = 0;
+				input = input[gapLen..];
+
+				while (input.Length > blockSize)
+				{
+					resultLen += cipher.ProcessBlock(input, mac);
+					input = input[blockSize..];
+				}
+			}
+
+			input.CopyTo(buf.AsSpan(bufOff));
+
+			bufOff += input.Length;
+		}
+#endif
+
 		public int DoFinal(
 			byte[]	output,
 			int		outOff)
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
index 595d9b051..65fb8bf01 100644
--- a/crypto/src/crypto/macs/Poly1305.cs
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -167,15 +167,22 @@ namespace Org.BouncyCastle.Crypto.Macs
             currentBlock[currentBlockOffset++] = input;
             if (currentBlockOffset == BlockSize)
             {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                ProcessBlock(currentBlock);
+#else
                 ProcessBlock(currentBlock, 0);
+#endif
                 currentBlockOffset = 0;
             }
         }
 
         public void BlockUpdate(byte[] input, int inOff, int len)
         {
-            // TODO Validity check on arguments
+            Check.DataLength(input, inOff, len, "input buffer too short");
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            BlockUpdate(input.AsSpan(inOff, len));
+#else
             int available = BlockSize - currentBlockOffset;
             if (len < available)
             {
@@ -189,37 +196,108 @@ namespace Org.BouncyCastle.Crypto.Macs
             {
                 Array.Copy(input, inOff, currentBlock, currentBlockOffset, available);
                 pos = available;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                ProcessBlock(currentBlock);
+#else
                 ProcessBlock(currentBlock, 0);
+#endif
             }
 
             int remaining;
             while ((remaining = len - pos) >= BlockSize)
             {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                ProcessBlock(input.AsSpan(inOff + pos));
+#else
                 ProcessBlock(input, inOff + pos);
+#endif
                 pos += BlockSize;
             }
 
             Array.Copy(input, inOff + pos, currentBlock, 0, remaining);
             currentBlockOffset = remaining;
+#endif
         }
 
-        private void ProcessBlock(byte[] buf, int off)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            int available = BlockSize - currentBlockOffset;
+            if (input.Length < available)
+            {
+                input.CopyTo(currentBlock.AsSpan(currentBlockOffset));
+                currentBlockOffset += input.Length;
+                return;
+            }
+
+            int pos = 0;
+            if (currentBlockOffset > 0)
+            {
+                input[..available].CopyTo(currentBlock.AsSpan(currentBlockOffset));
+                pos = available;
+                ProcessBlock(currentBlock);
+            }
+
+            int remaining;
+            while ((remaining = input.Length - pos) >= BlockSize)
+            {
+                ProcessBlock(input[pos..]);
+                pos += BlockSize;
+            }
+
+            input[pos..].CopyTo(currentBlock);
+            currentBlockOffset = remaining;
+        }
+#endif
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        private void ProcessBlock(ReadOnlySpan<byte> block)
         {
 #if NETCOREAPP3_0_OR_GREATER
             if (BitConverter.IsLittleEndian)
             {
                 Span<uint> t = stackalloc uint[4];
-                Unsafe.CopyBlockUnaligned(ref Unsafe.As<uint, byte>(ref t[0]), ref buf[off], 16);
+                Unsafe.CopyBlockUnaligned(ref Unsafe.As<uint, byte>(ref t[0]), ref Unsafe.AsRef(block[0]), 16);
 
                 h0 +=   t[0]                        & 0x3ffffffU;
                 h1 += ((t[1] <<  6) | (t[0] >> 26)) & 0x3ffffffU;
                 h2 += ((t[2] << 12) | (t[1] >> 20)) & 0x3ffffffU;
                 h3 += ((t[3] << 18) | (t[2] >> 14)) & 0x3ffffffU;
-                h4 +=     (1 << 24) | (t[3] >>  8);
+                h4 += (1 << 24) | (t[3] >> 8);
             }
             else
 #endif
             {
+                uint t0 = Pack.LE_To_UInt32(block);
+                uint t1 = Pack.LE_To_UInt32(block[4..]);
+                uint t2 = Pack.LE_To_UInt32(block[8..]);
+                uint t3 = Pack.LE_To_UInt32(block[12..]);
+
+                h0 +=   t0                      & 0x3ffffffU;
+                h1 += ((t1 <<  6) | (t0 >> 26)) & 0x3ffffffU;
+                h2 += ((t2 << 12) | (t1 >> 20)) & 0x3ffffffU;
+                h3 += ((t3 << 18) | (t2 >> 14)) & 0x3ffffffU;
+                h4 +=  ( 1 << 24) | (t3 >>  8);
+            }
+
+            ulong tp0 = (ulong)h0 * r0 + (ulong)h1 * s4 + (ulong)h2 * s3 + (ulong)h3 * s2 + (ulong)h4 * s1;
+            ulong tp1 = (ulong)h0 * r1 + (ulong)h1 * r0 + (ulong)h2 * s4 + (ulong)h3 * s3 + (ulong)h4 * s2;
+            ulong tp2 = (ulong)h0 * r2 + (ulong)h1 * r1 + (ulong)h2 * r0 + (ulong)h3 * s4 + (ulong)h4 * s3;
+            ulong tp3 = (ulong)h0 * r3 + (ulong)h1 * r2 + (ulong)h2 * r1 + (ulong)h3 * r0 + (ulong)h4 * s4;
+            ulong tp4 = (ulong)h0 * r4 + (ulong)h1 * r3 + (ulong)h2 * r2 + (ulong)h3 * r1 + (ulong)h4 * r0;
+
+            h0 = (uint)tp0 & 0x3ffffff; tp1 += (tp0 >> 26);
+            h1 = (uint)tp1 & 0x3ffffff; tp2 += (tp1 >> 26);
+            h2 = (uint)tp2 & 0x3ffffff; tp3 += (tp2 >> 26);
+            h3 = (uint)tp3 & 0x3ffffff; tp4 += (tp3 >> 26);
+            h4 = (uint)tp4 & 0x3ffffff;
+            h0 += (uint)(tp4 >> 26) * 5;
+            h1 += h0 >> 26; h0 &= 0x3ffffff;
+        }
+#else
+        private void ProcessBlock(byte[] buf, int off)
+        {
+            {
                 uint t0 = Pack.LE_To_UInt32(buf, off +  0);
                 uint t1 = Pack.LE_To_UInt32(buf, off +  4);
                 uint t2 = Pack.LE_To_UInt32(buf, off +  8);
@@ -246,10 +324,11 @@ namespace Org.BouncyCastle.Crypto.Macs
             h0 += (uint)(tp4 >> 26) * 5;
             h1 += h0 >> 26; h0 &= 0x3ffffff;
         }
+#endif
 
         public int DoFinal(byte[] output, int outOff)
         {
-            Check.DataLength(output, outOff, BlockSize, "Output buffer is too short.");
+            Check.DataLength(output, outOff, BlockSize, "output buffer is too short.");
 
             if (currentBlockOffset > 0)
             {
@@ -265,7 +344,11 @@ namespace Org.BouncyCastle.Crypto.Macs
                     h4 -= (1 << 24);
                 }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                ProcessBlock(currentBlock);
+#else
                 ProcessBlock(currentBlock, 0);
+#endif
             }
 
             Debug.Assert(h4 >> 26 == 0);
diff --git a/crypto/src/crypto/macs/SipHash.cs b/crypto/src/crypto/macs/SipHash.cs
index e1a19fa5b..fc0a66ed1 100644
--- a/crypto/src/crypto/macs/SipHash.cs
+++ b/crypto/src/crypto/macs/SipHash.cs
@@ -80,6 +80,9 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         public virtual void BlockUpdate(byte[] input, int offset, int length)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            BlockUpdate(input.AsSpan(offset, length));
+#else
             int i = 0, fullWords = length & ~7;
             if (wordPos == 0)
             {
@@ -115,8 +118,51 @@ namespace Org.BouncyCastle.Crypto.Macs
                     }
                 }
             }
+#endif
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            int length = input.Length;
+            int i = 0, fullWords = length & ~7;
+            if (wordPos == 0)
+            {
+                for (; i < fullWords; i += 8)
+                {
+                    m = (long)Pack.LE_To_UInt64(input[i..]);
+                    ProcessMessageWord();
+                }
+                for (; i < length; ++i)
+                {
+                    m = (long)(((ulong)m >> 8) | ((ulong)input[i] << 56));
+                }
+                wordPos = length - fullWords;
+            }
+            else
+            {
+                int bits = wordPos << 3;
+                for (; i < fullWords; i += 8)
+                {
+                    ulong n = Pack.LE_To_UInt64(input[i..]);
+                    m = (long)((n << bits) | ((ulong)m >> -bits));
+                    ProcessMessageWord();
+                    m = (long)n;
+                }
+                for (; i < length; ++i)
+                {
+                    m = (long)(((ulong)m >> 8) | ((ulong)input[i] << 56));
+
+                    if (++wordPos == 8)
+                    {
+                        ProcessMessageWord();
+                        wordPos = 0;
+                    }
+                }
+            }
+        }
+#endif
+
         public virtual long DoFinal()
         {
             // NOTE: 2 distinct shifts to avoid "64-bit shift" when wordPos == 0
diff --git a/crypto/src/crypto/macs/SkeinMac.cs b/crypto/src/crypto/macs/SkeinMac.cs
index 07eff24f4..6adc93ef9 100644
--- a/crypto/src/crypto/macs/SkeinMac.cs
+++ b/crypto/src/crypto/macs/SkeinMac.cs
@@ -106,13 +106,19 @@ namespace Org.BouncyCastle.Crypto.Macs
 
 		public void BlockUpdate(byte[] input, int inOff, int len)
 		{
-			engine.Update(input, inOff, len);
+			engine.BlockUpdate(input, inOff, len);
 		}
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public void BlockUpdate(ReadOnlySpan<byte> input)
+		{
+			engine.BlockUpdate(input);
+		}
+#endif
+
 		public int DoFinal(byte[] output, int outOff)
 		{
 			return engine.DoFinal(output, outOff);
 		}
-
 	}
 }
diff --git a/crypto/src/crypto/macs/VMPCMac.cs b/crypto/src/crypto/macs/VMPCMac.cs
index 6f2da075c..76912f736 100644
--- a/crypto/src/crypto/macs/VMPCMac.cs
+++ b/crypto/src/crypto/macs/VMPCMac.cs
@@ -159,15 +159,24 @@ namespace Org.BouncyCastle.Crypto.Macs
 			n = (byte) ((n + 1) & 0xff);
 		}
 
-		public virtual void BlockUpdate(byte[] input, int inOff, int len)
+		public virtual void BlockUpdate(byte[] input, int inOff, int inLen)
 		{
-			if ((inOff + len) > input.Length)
-				throw new DataLengthException("input buffer too short");
+			Check.DataLength(input, inOff, inLen, "input buffer too short");
 
-			for (int i = 0; i < len; i++)
+			for (int i = 0; i < inLen; i++)
 			{
 				Update(input[inOff + i]);
 			}
 		}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public virtual void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+			for (int i = 0; i < input.Length; i++)
+			{
+				Update(input[i]);
+			}
+		}
+#endif
 	}
 }