summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/src/crypto/engines/VMPCEngine.cs121
-rw-r--r--crypto/src/crypto/engines/VMPCKSA3Engine.cs42
-rw-r--r--crypto/src/crypto/macs/VMPCMac.cs259
-rw-r--r--crypto/src/crypto/prng/VMPCRandomGenerator.cs7
4 files changed, 199 insertions, 230 deletions
diff --git a/crypto/src/crypto/engines/VMPCEngine.cs b/crypto/src/crypto/engines/VMPCEngine.cs
index f34259248..897068e1a 100644
--- a/crypto/src/crypto/engines/VMPCEngine.cs
+++ b/crypto/src/crypto/engines/VMPCEngine.cs
@@ -7,10 +7,6 @@ namespace Org.BouncyCastle.Crypto.Engines
     public class VmpcEngine
         : IStreamCipher
     {
-        /*
-        * variables to hold the state of the VMPC engine during encryption and
-        * decryption
-        */
         protected byte n = 0;
         protected byte[] P = null;
         protected byte s = 0;
@@ -18,10 +14,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         protected byte[] workingIV;
         protected byte[] workingKey;
 
-        public virtual string AlgorithmName
-        {
-            get { return "VMPC"; }
-        }
+        public virtual string AlgorithmName => "VMPC";
 
         /**
         * initialise a VMPC cipher.
@@ -33,64 +26,41 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException
         *    if the params argument is inappropriate.
         */
-        public virtual void Init(
-            bool				forEncryption,
-            ICipherParameters	parameters)
+        public virtual void Init(bool forEncryption, ICipherParameters parameters)
         {
-            if (!(parameters is ParametersWithIV))
+            if (!(parameters is ParametersWithIV ivParams))
                 throw new ArgumentException("VMPC Init parameters must include an IV");
-
-            ParametersWithIV ivParams = (ParametersWithIV) parameters;
-
-            if (!(ivParams.Parameters is KeyParameter))
+            if (!(ivParams.Parameters is KeyParameter key))
                 throw new ArgumentException("VMPC Init parameters must include a key");
 
-            KeyParameter key = (KeyParameter)ivParams.Parameters;
-
-            this.workingIV = ivParams.GetIV();
+            int keyLength = key.KeyLength;
+            if (keyLength < 16 || keyLength > 64)
+                throw new ArgumentException("VMPC requires 16 to 64 bytes of key");
 
-            if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768)
-                throw new ArgumentException("VMPC requires 1 to 768 bytes of IV");
+            int ivLength = ivParams.IVLength;
+            if (ivLength < 16 || ivLength > 64)
+                throw new ArgumentException("VMPC requires 16 to 64 bytes of IV");
 
             this.workingKey = key.GetKey();
+            this.workingIV = ivParams.GetIV();
 
             InitKey(this.workingKey, this.workingIV);
         }
 
-        protected virtual void InitKey(
-            byte[]	keyBytes,
-            byte[]	ivBytes)
+        protected virtual void InitKey(byte[] keyBytes, byte[] ivBytes)
         {
+            n = 0;
             s = 0;
             P = new byte[256];
             for (int i = 0; i < 256; i++)
             {
-                P[i] = (byte) i;
+                P[i] = (byte)i;
             }
-
-            for (int m = 0; m < 768; m++)
-            {
-                s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
-                byte temp = P[m & 0xff];
-                P[m & 0xff] = P[s & 0xff];
-                P[s & 0xff] = temp;
-            }
-            for (int m = 0; m < 768; m++)
-            {
-                s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
-                byte temp = P[m & 0xff];
-                P[m & 0xff] = P[s & 0xff];
-                P[s & 0xff] = temp;
-            }
-            n = 0;
+            KsaRound(P, ref s, keyBytes);
+            KsaRound(P, ref s, ivBytes);
         }
 
-        public virtual void ProcessBytes(
-            byte[]	input,
-            int		inOff,
-            int		len,
-            byte[]	output,
-            int		outOff)
+        public virtual void ProcessBytes(byte[]	input, int inOff, int len, byte[] output, int outOff)
         {
             Check.DataLength(input, inOff, len, "input buffer too short");
             Check.OutputLength(output, outOff, len, "output buffer too short");
@@ -98,16 +68,12 @@ namespace Org.BouncyCastle.Crypto.Engines
             for (int i = 0; i < len; i++)
             {
                 byte pn = P[n];
-                s = P[(s + pn) & 0xff];
+                s = P[(s + pn) & 0xFF];
                 byte ps = P[s];
-                byte z = P[(P[ps] + 1) & 0xff];
-                // encryption
+                output[outOff + i] = (byte)(input[inOff + i] ^ P[(P[ps] + 1) & 0xFF]);
                 P[n] = ps;
                 P[s] = pn;
                 n = (byte)(n + 1);
-
-                // xor
-                output[i + outOff] = (byte)(input[i + inOff] ^ z);
             }
         }
 
@@ -119,16 +85,12 @@ namespace Org.BouncyCastle.Crypto.Engines
             for (int i = 0; i < input.Length; i++)
             {
                 byte pn = P[n];
-                s = P[(s + pn) & 0xff];
+                s = P[(s + pn) & 0xFF];
                 byte ps = P[s];
-                byte z = P[(P[ps] + 1) & 0xff];
-                // encryption
+                output[i] = (byte)(input[i] ^ P[(P[ps] + 1) & 0xFF]);
                 P[n] = ps;
                 P[s] = pn;
                 n = (byte)(n + 1);
-
-                // xor
-                output[i] = (byte)(input[i] ^ z);
             }
         }
 #endif
@@ -138,19 +100,36 @@ namespace Org.BouncyCastle.Crypto.Engines
             InitKey(this.workingKey, this.workingIV);
         }
 
-        public virtual byte ReturnByte(
-            byte input)
+        public virtual byte ReturnByte(byte input)
         {
-            s = P[(s + P[n & 0xff]) & 0xff];
-            byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
-            // encryption
-            byte temp = P[n & 0xff];
-            P[n & 0xff] = P[s & 0xff];
-            P[s & 0xff] = temp;
-            n = (byte) ((n + 1) & 0xff);
-
-            // xor
-            return (byte) (input ^ z);
+            byte pn = P[n];
+            s = P[(s + pn) & 0xFF];
+            byte ps = P[s];
+            byte output = (byte)(input ^ P[(P[ps] + 1) & 0xFF]);
+            P[n] = ps;
+            P[s] = pn;
+            n = (byte)(n + 1);
+            return output;
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        internal static void KsaRound(byte[] P, ref byte S, ReadOnlySpan<byte> input)
+#else
+        internal static void KsaRound(byte[] P, ref byte S, byte[] input)
+#endif
+        {
+            byte s = S;
+            int modulus = input.Length, offset = 0;
+            for (int m = 0; m < 768; m++)
+            {
+                byte pm = P[m & 0xFF];
+                s = P[(s + pm + input[offset]) & 0xFF];
+                int t = offset + 1 - modulus;
+                offset = t + (modulus & (t >> 31));
+                P[m & 0xFF] = P[s];
+                P[s] = pm;
+            }
+            S = s;
         }
     }
 }
diff --git a/crypto/src/crypto/engines/VMPCKSA3Engine.cs b/crypto/src/crypto/engines/VMPCKSA3Engine.cs
index 95b6813b7..d44c15b0b 100644
--- a/crypto/src/crypto/engines/VMPCKSA3Engine.cs
+++ b/crypto/src/crypto/engines/VMPCKSA3Engine.cs
@@ -5,47 +5,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 	public class VmpcKsa3Engine
 		: VmpcEngine
 	{
-		public override string AlgorithmName
-		{
-			get { return "VMPC-KSA3"; }
-		}
+		public override string AlgorithmName => "VMPC-KSA3";
 
-		protected override void InitKey(
-			byte[]	keyBytes,
-			byte[]	ivBytes)
+		protected override void InitKey(byte[] keyBytes, byte[] ivBytes)
 		{
-			s = 0;
-			P = new byte[256];
-			for (int i = 0; i < 256; i++)
-			{
-				P[i] = (byte) i;
-			}
-
-			for (int m = 0; m < 768; m++)
-			{
-				s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
-				byte temp = P[m & 0xff];
-				P[m & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
-			}
-
-			for (int m = 0; m < 768; m++)
-			{
-				s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
-				byte temp = P[m & 0xff];
-				P[m & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
-			}
-
-			for (int m = 0; m < 768; m++)
-			{
-				s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
-				byte temp = P[m & 0xff];
-				P[m & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
-			}
+			base.InitKey(keyBytes, ivBytes);
 
-			n = 0;
+            KsaRound(P, ref s, keyBytes);
 		}
 	}
 }
diff --git a/crypto/src/crypto/macs/VMPCMac.cs b/crypto/src/crypto/macs/VMPCMac.cs
index c2902179f..a64ce4ffc 100644
--- a/crypto/src/crypto/macs/VMPCMac.cs
+++ b/crypto/src/crypto/macs/VMPCMac.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Parameters;
 
 namespace Org.BouncyCastle.Crypto.Macs
@@ -13,7 +14,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 		private byte[] P = null;
 		private byte s = 0;
 
-		private byte[] T;
+		private readonly byte[] T = new byte[32];
 		private byte[] workingIV;
 
 		private byte[] workingKey;
@@ -28,43 +29,43 @@ namespace Org.BouncyCastle.Crypto.Macs
 			// Execute the Post-Processing Phase
 			for (int r = 1; r < 25; r++)
 			{
-				s = P[(s + P[n & 0xff]) & 0xff];
-
-				x4 = P[(x4 + x3 + r) & 0xff];
-				x3 = P[(x3 + x2 + r) & 0xff];
-				x2 = P[(x2 + x1 + r) & 0xff];
-				x1 = P[(x1 + s + r) & 0xff];
-				T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1);
-				T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2);
-				T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3);
-				T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4);
-				g = (byte) ((g + 4) & 0x1f);
-
-				byte temp = P[n & 0xff];
-				P[n & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
-				n = (byte) ((n + 1) & 0xff);
+				s = P[(s + P[n & 0xFF]) & 0xFF];
+
+				x4 = P[(x4 + x3 + r) & 0xFF];
+				x3 = P[(x3 + x2 + r) & 0xFF];
+				x2 = P[(x2 + x1 + r) & 0xFF];
+				x1 = P[(x1 + s + r) & 0xFF];
+				T[g & 0x1F] = (byte)(T[g & 0x1F] ^ x1);
+				T[(g + 1) & 0x1F] = (byte)(T[(g + 1) & 0x1F] ^ x2);
+				T[(g + 2) & 0x1F] = (byte)(T[(g + 2) & 0x1F] ^ x3);
+				T[(g + 3) & 0x1F] = (byte)(T[(g + 3) & 0x1F] ^ x4);
+				g = (byte)((g + 4) & 0x1F);
+
+				byte temp = P[n & 0xFF];
+				P[n & 0xFF] = P[s & 0xFF];
+				P[s & 0xFF] = temp;
+				n = (byte)((n + 1) & 0xFF);
 			}
 
 			// Input T to the IV-phase of the VMPC KSA
 			for (int m = 0; m < 768; m++)
 			{
-				s = P[(s + P[m & 0xff] + T[m & 0x1f]) & 0xff];
-				byte temp = P[m & 0xff];
-				P[m & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
+				s = P[(s + P[m & 0xFF] + T[m & 0x1F]) & 0xFF];
+				byte temp = P[m & 0xFF];
+				P[m & 0xFF] = P[s & 0xFF];
+				P[s & 0xFF] = temp;
 			}
 
 			// Store 20 new outputs of the VMPC Stream Cipher input table M
 			byte[] M = new byte[20];
 			for (int i = 0; i < 20; i++)
 			{
-				s = P[(s + P[i & 0xff]) & 0xff];
-				M[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+				s = P[(s + P[i & 0xFF]) & 0xFF];
+				M[i] = P[(P[(P[s & 0xFF]) & 0xFF] + 1) & 0xFF];
 
-				byte temp = P[i & 0xff];
-				P[i & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
+				byte temp = P[i & 0xFF];
+				P[i & 0xFF] = P[s & 0xFF];
+				P[s & 0xFF] = temp;
 			}
 
 			Array.Copy(M, 0, output, outOff, M.Length);
@@ -80,43 +81,43 @@ namespace Org.BouncyCastle.Crypto.Macs
 			// Execute the Post-Processing Phase
 			for (int r = 1; r < 25; r++)
 			{
-				s = P[(s + P[n & 0xff]) & 0xff];
-
-				x4 = P[(x4 + x3 + r) & 0xff];
-				x3 = P[(x3 + x2 + r) & 0xff];
-				x2 = P[(x2 + x1 + r) & 0xff];
-				x1 = P[(x1 + s + r) & 0xff];
-				T[g & 0x1f] = (byte)(T[g & 0x1f] ^ x1);
-				T[(g + 1) & 0x1f] = (byte)(T[(g + 1) & 0x1f] ^ x2);
-				T[(g + 2) & 0x1f] = (byte)(T[(g + 2) & 0x1f] ^ x3);
-				T[(g + 3) & 0x1f] = (byte)(T[(g + 3) & 0x1f] ^ x4);
-				g = (byte)((g + 4) & 0x1f);
-
-				byte temp = P[n & 0xff];
-				P[n & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
-				n = (byte)((n + 1) & 0xff);
+				s = P[(s + P[n & 0xFF]) & 0xFF];
+
+				x4 = P[(x4 + x3 + r) & 0xFF];
+				x3 = P[(x3 + x2 + r) & 0xFF];
+				x2 = P[(x2 + x1 + r) & 0xFF];
+				x1 = P[(x1 + s + r) & 0xFF];
+				T[g & 0x1F] = (byte)(T[g & 0x1F] ^ x1);
+				T[(g + 1) & 0x1F] = (byte)(T[(g + 1) & 0x1F] ^ x2);
+				T[(g + 2) & 0x1F] = (byte)(T[(g + 2) & 0x1F] ^ x3);
+				T[(g + 3) & 0x1F] = (byte)(T[(g + 3) & 0x1F] ^ x4);
+				g = (byte)((g + 4) & 0x1F);
+
+				byte temp = P[n & 0xFF];
+				P[n & 0xFF] = P[s & 0xFF];
+				P[s & 0xFF] = temp;
+				n = (byte)((n + 1) & 0xFF);
 			}
 
 			// Input T to the IV-phase of the VMPC KSA
 			for (int m = 0; m < 768; m++)
 			{
-				s = P[(s + P[m & 0xff] + T[m & 0x1f]) & 0xff];
-				byte temp = P[m & 0xff];
-				P[m & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
+				s = P[(s + P[m & 0xFF] + T[m & 0x1F]) & 0xFF];
+				byte temp = P[m & 0xFF];
+				P[m & 0xFF] = P[s & 0xFF];
+				P[s & 0xFF] = temp;
 			}
 
 			// Store 20 new outputs of the VMPC Stream Cipher input table M
 			byte[] M = new byte[20];
 			for (int i = 0; i < 20; i++)
 			{
-				s = P[(s + P[i & 0xff]) & 0xff];
-				M[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+				s = P[(s + P[i & 0xFF]) & 0xFF];
+				M[i] = P[(P[(P[s & 0xFF]) & 0xFF] + 1) & 0xFF];
 
-				byte temp = P[i & 0xff];
-				P[i & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
+				byte temp = P[i & 0xFF];
+				P[i & 0xFF] = P[s & 0xFF];
+				P[s & 0xFF] = temp;
 			}
 
 			M.CopyTo(output);
@@ -126,113 +127,129 @@ namespace Org.BouncyCastle.Crypto.Macs
 		}
 #endif
 
-		public virtual string AlgorithmName
-		{
-			get { return "VMPC-MAC"; }
-		}
+		public virtual string AlgorithmName => "VMPC-MAC";
 
-		public virtual int GetMacSize()
-		{
-			return 20;
-		}
+		public virtual int GetMacSize() => 20;
 
 		public virtual void Init(ICipherParameters parameters)
 		{
-			if (!(parameters is ParametersWithIV))
+			if (!(parameters is ParametersWithIV ivParams))
 				throw new ArgumentException("VMPC-MAC Init parameters must include an IV", "parameters");
-
-			ParametersWithIV ivParams = (ParametersWithIV) parameters;
-			KeyParameter key = (KeyParameter) ivParams.Parameters;
-
-			if (!(ivParams.Parameters is KeyParameter))
+			if (!(ivParams.Parameters is KeyParameter key))
 				throw new ArgumentException("VMPC-MAC Init parameters must include a key", "parameters");
 
-			this.workingIV = ivParams.GetIV();
+            int keyLength = key.KeyLength;
+            if (keyLength < 16 || keyLength > 64)
+                throw new ArgumentException("VMPC requires 16 to 64 bytes of key");
 
-			if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768)
-				throw new ArgumentException("VMPC-MAC requires 1 to 768 bytes of IV", "parameters");
+            int ivLength = ivParams.IVLength;
+            if (ivLength < 16 || ivLength > 64)
+                throw new ArgumentException("VMPC requires 16 to 64 bytes of IV");
 
-			this.workingKey = key.GetKey();
+            this.workingKey = key.GetKey();
+            this.workingIV = ivParams.GetIV();
 
 			Reset();
-
 		}
 
-		private void initKey(byte[] keyBytes, byte[] ivBytes)
+		private void InitKey(byte[] keyBytes, byte[] ivBytes)
 		{
-			s = 0;
+            n = 0;
+            s = 0;
 			P = new byte[256];
 			for (int i = 0; i < 256; i++)
 			{
-				P[i] = (byte) i;
-			}
-			for (int m = 0; m < 768; m++)
-			{
-				s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
-				byte temp = P[m & 0xff];
-				P[m & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
-			}
-			for (int m = 0; m < 768; m++)
-			{
-				s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
-				byte temp = P[m & 0xff];
-				P[m & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
+				P[i] = (byte)i;
 			}
-			n = 0;
+			VmpcEngine.KsaRound(P, ref s, keyBytes);
+            VmpcEngine.KsaRound(P, ref s, ivBytes);
 		}
 
 		public virtual void Reset()
 		{
-			initKey(this.workingKey, this.workingIV);
+			InitKey(this.workingKey, this.workingIV);
 			g = x1 = x2 = x3 = x4 = n = 0;
-			T = new byte[32];
-			for (int i = 0; i < 32; i++)
-			{
-				T[i] = 0;
-			}
+			Array.Clear(T, 0, T.Length);
 		}
 
 		public virtual void Update(byte input)
 		{
-			s = P[(s + P[n & 0xff]) & 0xff];
-			byte c = (byte) (input ^ P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]);
-
-			x4 = P[(x4 + x3) & 0xff];
-			x3 = P[(x3 + x2) & 0xff];
-			x2 = P[(x2 + x1) & 0xff];
-			x1 = P[(x1 + s + c) & 0xff];
-			T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1);
-			T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2);
-			T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3);
-			T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4);
-			g = (byte) ((g + 4) & 0x1f);
-
-			byte temp = P[n & 0xff];
-			P[n & 0xff] = P[s & 0xff];
-			P[s & 0xff] = temp;
-			n = (byte) ((n + 1) & 0xff);
-		}
-
-		public virtual void BlockUpdate(byte[] input, int inOff, int inLen)
+            byte pn = P[n];
+            s = P[(s + pn) & 0xFF];
+            byte ps = P[s];
+            byte c = (byte)(input ^ P[(P[ps] + 1) & 0xFF]);
+
+            x4 = P[(x4 + x3) & 0xFF];
+            x3 = P[(x3 + x2) & 0xFF];
+            x2 = P[(x2 + x1) & 0xFF];
+            x1 = P[(x1 + s + c) & 0xFF];
+            T[g & 0x1F] = (byte)(T[g & 0x1F] ^ x1);
+            T[(g + 1) & 0x1F] = (byte)(T[(g + 1) & 0x1F] ^ x2);
+            T[(g + 2) & 0x1F] = (byte)(T[(g + 2) & 0x1F] ^ x3);
+            T[(g + 3) & 0x1F] = (byte)(T[(g + 3) & 0x1F] ^ x4);
+            g = (byte)((g + 4) & 0x1F);
+
+            P[n] = ps;
+            P[s] = pn;
+            n = (byte)(n + 1);
+        }
+
+        public virtual void BlockUpdate(byte[] input, int inOff, int inLen)
 		{
 			Check.DataLength(input, inOff, inLen, "input buffer too short");
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+			BlockUpdate(input.AsSpan(inOff, inLen));
+#else
 			for (int i = 0; i < inLen; i++)
 			{
-				Update(input[inOff + i]);
-			}
-		}
+                byte pn = P[n];
+                s = P[(s + pn) & 0xFF];
+                byte ps = P[s];
+                byte c = (byte)(input[inOff + i] ^ P[(P[ps] + 1) & 0xFF]);
+
+                x4 = P[(x4 + x3) & 0xFF];
+                x3 = P[(x3 + x2) & 0xFF];
+                x2 = P[(x2 + x1) & 0xFF];
+                x1 = P[(x1 + s + c) & 0xFF];
+                T[g & 0x1F] = (byte)(T[g & 0x1F] ^ x1);
+                T[(g + 1) & 0x1F] = (byte)(T[(g + 1) & 0x1F] ^ x2);
+                T[(g + 2) & 0x1F] = (byte)(T[(g + 2) & 0x1F] ^ x3);
+                T[(g + 3) & 0x1F] = (byte)(T[(g + 3) & 0x1F] ^ x4);
+                g = (byte)((g + 4) & 0x1F);
+
+                P[n] = ps;
+                P[s] = pn;
+                n = (byte)(n + 1);
+            }
+#endif
+        }
 
 #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]);
-			}
-		}
+                byte pn = P[n];
+                s = P[(s + pn) & 0xFF];
+                byte ps = P[s];
+                byte c = (byte)(input[i] ^ P[(P[ps] + 1) & 0xFF]);
+
+                x4 = P[(x4 + x3) & 0xFF];
+                x3 = P[(x3 + x2) & 0xFF];
+                x2 = P[(x2 + x1) & 0xFF];
+                x1 = P[(x1 + s + c) & 0xFF];
+                T[g & 0x1F] = (byte)(T[g & 0x1F] ^ x1);
+                T[(g + 1) & 0x1F] = (byte)(T[(g + 1) & 0x1F] ^ x2);
+                T[(g + 2) & 0x1F] = (byte)(T[(g + 2) & 0x1F] ^ x3);
+                T[(g + 3) & 0x1F] = (byte)(T[(g + 3) & 0x1F] ^ x4);
+                g = (byte)((g + 4) & 0x1F);
+
+                P[n] = ps;
+                P[s] = pn;
+                n = (byte)(n + 1);
+            }
+        }
 #endif
-	}
+    }
 }
diff --git a/crypto/src/crypto/prng/VMPCRandomGenerator.cs b/crypto/src/crypto/prng/VMPCRandomGenerator.cs
index 92d163710..23f2d2ec1 100644
--- a/crypto/src/crypto/prng/VMPCRandomGenerator.cs
+++ b/crypto/src/crypto/prng/VMPCRandomGenerator.cs
@@ -56,6 +56,12 @@ namespace Org.BouncyCastle.Crypto.Prng
 
         public void AddSeedMaterial(byte[] seed) 
         {
+            if (seed == null)
+                return;
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            AddSeedMaterial(seed.AsSpan());
+#else
             for (int m = 0; m < seed.Length; m++) 
             {
                 byte pn = P[n];
@@ -64,6 +70,7 @@ namespace Org.BouncyCastle.Crypto.Prng
                 P[s] = pn;
                 n = (byte)(n + 1);
             }
+#endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER