summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-08-25 01:03:22 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-08-25 01:03:22 +0700
commit145e57023efdc09d757a21c421a938786c75c48a (patch)
tree685d516e56d6405080c197ecbb67f886893f3dd5
parentSpan-based variant for IAeadCipher.ProcessAadBytes (diff)
downloadBouncyCastle.NET-ed25519-145e57023efdc09d757a21c421a938786c75c48a.tar.xz
Span-based variant for IMac.DoFinal
-rw-r--r--crypto/src/crypto/IMac.cs8
-rw-r--r--crypto/src/crypto/macs/CMac.cs39
-rw-r--r--crypto/src/crypto/macs/CbcBlockCipherMac.cs44
-rw-r--r--crypto/src/crypto/macs/CfbBlockCipherMac.cs34
-rw-r--r--crypto/src/crypto/macs/DSTU7564Mac.cs22
-rw-r--r--crypto/src/crypto/macs/DSTU7624Mac.cs24
-rw-r--r--crypto/src/crypto/macs/GMac.cs11
-rw-r--r--crypto/src/crypto/macs/GOST28147Mac.cs34
-rw-r--r--crypto/src/crypto/macs/HMac.cs38
-rw-r--r--crypto/src/crypto/macs/ISO9797Alg3Mac.cs52
-rw-r--r--crypto/src/crypto/macs/Poly1305.cs56
-rw-r--r--crypto/src/crypto/macs/SipHash.cs9
-rw-r--r--crypto/src/crypto/macs/SkeinMac.cs7
-rw-r--r--crypto/src/crypto/macs/VMPCMac.cs56
14 files changed, 413 insertions, 21 deletions
diff --git a/crypto/src/crypto/IMac.cs b/crypto/src/crypto/IMac.cs
index 3df4c354f..aa539b968 100644
--- a/crypto/src/crypto/IMac.cs
+++ b/crypto/src/crypto/IMac.cs
@@ -39,6 +39,14 @@ namespace Org.BouncyCastle.Crypto
         /// <returns>the number of bytes written</returns>
         int DoFinal(byte[] output, int outOff);
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        /// <summary>Perform final calculations, producing the result MAC.</summary>
+        /// <remarks>This call leaves the MAC reset.</remarks>
+        /// <param name="output">the span the MAC is to be copied into.</param>
+        /// <returns>the number of bytes written</returns>
+        int DoFinal(Span<byte> output);
+#endif
+
         /// <summary>Reset the MAC back to its initial state.</summary>
         void Reset();
     }
diff --git a/crypto/src/crypto/macs/CMac.cs b/crypto/src/crypto/macs/CMac.cs
index dbd696429..342dbd93d 100644
--- a/crypto/src/crypto/macs/CMac.cs
+++ b/crypto/src/crypto/macs/CMac.cs
@@ -233,10 +233,11 @@ namespace Org.BouncyCastle.Crypto.Macs
         }
 #endif
 
-        public int DoFinal(
-            byte[]	outBytes,
-            int		outOff)
+        public int DoFinal(byte[] outBytes, int outOff)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return DoFinal(outBytes.AsSpan(outOff));
+#else
             int blockSize = cipher.GetBlockSize();
 
             byte[] lu;
@@ -262,8 +263,40 @@ namespace Org.BouncyCastle.Crypto.Macs
             Reset();
 
             return macSize;
+#endif
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            int blockSize = cipher.GetBlockSize();
+
+            byte[] lu;
+            if (bufOff == blockSize)
+            {
+                lu = Lu;
+            }
+            else
+            {
+                new ISO7816d4Padding().AddPadding(buf, bufOff);
+                lu = Lu2;
+            }
+
+            for (int i = 0; i < mac.Length; i++)
+            {
+                buf[i] ^= lu[i];
+            }
+
+            cipher.ProcessBlock(buf, mac);
+
+            mac.AsSpan(0, macSize).CopyTo(output);
+
+            Reset();
+
+            return macSize;
+        }
+#endif
+
         /**
         * Reset the mac generator.
         */
diff --git a/crypto/src/crypto/macs/CbcBlockCipherMac.cs b/crypto/src/crypto/macs/CbcBlockCipherMac.cs
index de7a5f2e4..abf06170c 100644
--- a/crypto/src/crypto/macs/CbcBlockCipherMac.cs
+++ b/crypto/src/crypto/macs/CbcBlockCipherMac.cs
@@ -186,10 +186,11 @@ namespace Org.BouncyCastle.Crypto.Macs
         }
 #endif
 
-        public int DoFinal(
-            byte[]	output,
-            int		outOff)
+        public int DoFinal(byte[] output, int outOff)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return DoFinal(output.AsSpan(outOff));
+#else
             int blockSize = cipher.GetBlockSize();
 
             if (padding == null)
@@ -218,9 +219,44 @@ namespace Org.BouncyCastle.Crypto.Macs
 			Reset();
 
 			return macSize;
+#endif
         }
 
-		/**
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            int blockSize = cipher.GetBlockSize();
+
+            if (padding == null)
+            {
+                // pad with zeroes
+                while (bufOff < blockSize)
+                {
+                    buf[bufOff++] = 0;
+                }
+            }
+            else
+            {
+                if (bufOff == blockSize)
+                {
+                    cipher.ProcessBlock(buf, buf);
+                    bufOff = 0;
+                }
+
+				padding.AddPadding(buf, bufOff);
+            }
+
+			cipher.ProcessBlock(buf, buf);
+
+            buf.AsSpan(0, macSize).CopyTo(output);
+
+			Reset();
+
+			return macSize;
+        }
+#endif
+
+        /**
         * Reset the mac generator.
         */
         public void Reset()
diff --git a/crypto/src/crypto/macs/CfbBlockCipherMac.cs b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
index b454306e3..a4d005700 100644
--- a/crypto/src/crypto/macs/CfbBlockCipherMac.cs
+++ b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
@@ -354,6 +354,9 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         public int DoFinal(byte[] output, int outOff)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return DoFinal(output.AsSpan(outOff));
+#else
             int blockSize = cipher.GetBlockSize();
 
             // pad with zeroes
@@ -378,8 +381,39 @@ namespace Org.BouncyCastle.Crypto.Macs
 			Reset();
 
 			return macSize;
+#endif
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            int blockSize = cipher.GetBlockSize();
+
+            // pad with zeroes
+            if (this.padding == null)
+            {
+                while (bufOff < blockSize)
+                {
+                    Buffer[bufOff++] = 0;
+                }
+            }
+            else
+            {
+                padding.AddPadding(Buffer, bufOff);
+            }
+
+            cipher.ProcessBlock(Buffer, 0, mac, 0);
+
+            cipher.GetMacBlock(mac);
+
+            mac.AsSpan(0, macSize).CopyTo(output);
+
+            Reset();
+
+            return macSize;
+        }
+#endif
+
         /**
         * Reset the mac generator.
         */
diff --git a/crypto/src/crypto/macs/DSTU7564Mac.cs b/crypto/src/crypto/macs/DSTU7564Mac.cs
index 43fe7fb90..401d85a1e 100644
--- a/crypto/src/crypto/macs/DSTU7564Mac.cs
+++ b/crypto/src/crypto/macs/DSTU7564Mac.cs
@@ -89,11 +89,11 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         public int DoFinal(byte[] output, int outOff)
         {
-            Check.OutputLength(output, outOff, macSize, "output buffer too short");
-
             if (paddedKey == null)
                 throw new InvalidOperationException(AlgorithmName + " not initialised");
 
+            Check.OutputLength(output, outOff, macSize, "output buffer too short");
+
             Pad();
 
             engine.BlockUpdate(invertedKey, 0, invertedKey.Length);
@@ -103,6 +103,24 @@ namespace Org.BouncyCastle.Crypto.Macs
             return engine.DoFinal(output, outOff);
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            if (paddedKey == null)
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+            Check.OutputLength(output, macSize, "output buffer too short");
+
+            Pad();
+
+            engine.BlockUpdate(invertedKey);
+
+            inputLength = 0;
+
+            return engine.DoFinal(output);
+        }
+#endif
+
         public void Reset()
         {
             inputLength = 0;
diff --git a/crypto/src/crypto/macs/DSTU7624Mac.cs b/crypto/src/crypto/macs/DSTU7624Mac.cs
index 01c1f869c..8fecb1915 100644
--- a/crypto/src/crypto/macs/DSTU7624Mac.cs
+++ b/crypto/src/crypto/macs/DSTU7624Mac.cs
@@ -177,19 +177,37 @@ namespace Org.BouncyCastle.Crypto.Macs
             if (bufOff % buf.Length != 0)
                 throw new DataLengthException("Input must be a multiple of blocksize");
 
+            Check.OutputLength(output, outOff, macSize, "output buffer too short");
+
             //Last block
             Xor(c, 0, buf, 0, cTemp);
             Xor(cTemp, 0, kDelta, 0, c);
             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;
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            if (bufOff % buf.Length != 0)
+                throw new DataLengthException("Input must be a multiple of blocksize");
+
+            Check.OutputLength(output, macSize, "output buffer too short");
+
+            //Last block
+            Xor(c, 0, buf, 0, cTemp);
+            Xor(cTemp, 0, kDelta, 0, c);
+            engine.ProcessBlock(c, c);
+
+            c.AsSpan(0, macSize).CopyTo(output);
+
+            return macSize;
+        }
+#endif
+
         public void Reset()
         {
             Arrays.Fill(c, (byte)0x00);
diff --git a/crypto/src/crypto/macs/GMac.cs b/crypto/src/crypto/macs/GMac.cs
index e0a448dda..aa124bb04 100644
--- a/crypto/src/crypto/macs/GMac.cs
+++ b/crypto/src/crypto/macs/GMac.cs
@@ -106,6 +106,17 @@ namespace Org.BouncyCastle.Crypto.Macs
             }
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            // TODO[span] call cipher.DoFinal(Span<byte) when available
+            byte[] tmp = new byte[GetMacSize()];
+            int result = DoFinal(tmp, 0);
+            tmp.CopyTo(output);
+            return result;
+        }
+#endif
+
         public void Reset()
         {
             cipher.Reset();
diff --git a/crypto/src/crypto/macs/GOST28147Mac.cs b/crypto/src/crypto/macs/GOST28147Mac.cs
index 6a6907934..8c39fc6b0 100644
--- a/crypto/src/crypto/macs/GOST28147Mac.cs
+++ b/crypto/src/crypto/macs/GOST28147Mac.cs
@@ -283,6 +283,9 @@ namespace Org.BouncyCastle.Crypto.Macs
 
 		public int DoFinal(byte[] output, int outOff)
 		{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+			return DoFinal(output.AsSpan(outOff));
+#else
 			//padding with zero
 			while (bufOff < BlockSize)
 			{
@@ -307,8 +310,39 @@ namespace Org.BouncyCastle.Crypto.Macs
 			Reset();
 
 			return MacSize;
+#endif
 		}
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public int DoFinal(Span<byte> output)
+		{
+			//padding with zero
+			while (bufOff < BlockSize)
+			{
+				buf[bufOff++] = 0;
+			}
+
+			byte[] sum = new byte[buf.Length];
+			if (firstStep)
+			{
+				firstStep = false;
+				Array.Copy(buf, 0, sum, 0, mac.Length);
+			}
+			else
+			{
+				Cm5Func(buf, 0, mac, sum);
+			}
+
+			Gost28147MacFunc(workingKey, sum, 0, mac, 0);
+
+			mac.AsSpan((mac.Length / 2) - MacSize, MacSize).CopyTo(output);
+
+			Reset();
+
+			return MacSize;
+		}
+#endif
+
 		public void Reset()
 		{
 			// Clear the buffer.
diff --git a/crypto/src/crypto/macs/HMac.cs b/crypto/src/crypto/macs/HMac.cs
index 389c03a23..3445a945b 100644
--- a/crypto/src/crypto/macs/HMac.cs
+++ b/crypto/src/crypto/macs/HMac.cs
@@ -108,12 +108,15 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         public virtual int DoFinal(byte[] output, int outOff)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return DoFinal(output.AsSpan(outOff));
+#else
             digest.DoFinal(outputBuf, blockLength);
 
 			if (opadState != null)
 			{
 				((IMemoable)digest).Reset(opadState);
-				digest.BlockUpdate(outputBuf, blockLength, digest.GetDigestSize());
+				digest.BlockUpdate(outputBuf, blockLength, digestSize);
 			}
 			else
 			{
@@ -134,8 +137,41 @@ namespace Org.BouncyCastle.Crypto.Macs
 			}
 
             return len;
+#endif
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual int DoFinal(Span<byte> output)
+        {
+            digest.DoFinal(outputBuf.AsSpan(blockLength));
+
+            if (opadState != null)
+            {
+                ((IMemoable)digest).Reset(opadState);
+                digest.BlockUpdate(outputBuf.AsSpan(blockLength, digestSize));
+            }
+            else
+            {
+                digest.BlockUpdate(outputBuf);
+            }
+
+            int len = digest.DoFinal(output);
+
+            Array.Clear(outputBuf, blockLength, digestSize);
+
+            if (ipadState != null)
+            {
+                ((IMemoable)digest).Reset(ipadState);
+            }
+            else
+            {
+                digest.BlockUpdate(inputPad);
+            }
+
+            return len;
+        }
+#endif
+
         /**
         * Reset the mac generator.
         */
diff --git a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
index f516e9b96..40a68007e 100644
--- a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
+++ b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
@@ -246,10 +246,11 @@ namespace Org.BouncyCastle.Crypto.Macs
 		}
 #endif
 
-		public int DoFinal(
-			byte[]	output,
-			int		outOff)
+		public int DoFinal(byte[] output, int outOff)
 		{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+			return DoFinal(output.AsSpan(outOff));
+#else
 			int blockSize = cipher.GetBlockSize();
 
 			if (padding == null)
@@ -288,8 +289,53 @@ namespace Org.BouncyCastle.Crypto.Macs
 			Reset();
 
 			return macSize;
+#endif
 		}
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public int DoFinal(Span<byte> output)
+		{
+			int blockSize = cipher.GetBlockSize();
+
+			if (padding == null)
+			{
+				// pad with zeroes
+				while (bufOff < blockSize)
+				{
+					buf[bufOff++] = 0;
+				}
+			}
+			else
+			{
+				if (bufOff == blockSize)
+				{
+					cipher.ProcessBlock(buf, mac);
+					bufOff = 0;
+				}
+
+				padding.AddPadding(buf, bufOff);
+			}
+
+			cipher.ProcessBlock(buf, mac);
+
+			// Added to code from base class
+			DesEngine deseng = new DesEngine();
+
+			deseng.Init(false, this.lastKey2);
+			deseng.ProcessBlock(mac, mac);
+
+			deseng.Init(true, this.lastKey3);
+			deseng.ProcessBlock(mac, mac);
+			// ****
+
+			mac.AsSpan(0, macSize).CopyTo(output);
+
+			Reset();
+
+			return macSize;
+		}
+#endif
+
 		/**
 		* Reset the mac generator.
 		*/
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
index 65fb8bf01..eb90e387e 100644
--- a/crypto/src/crypto/macs/Poly1305.cs
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -328,7 +328,10 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         public int DoFinal(byte[] output, int outOff)
         {
-            Check.DataLength(output, outOff, BlockSize, "output buffer is too short.");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return DoFinal(output.AsSpan(outOff));
+#else
+            Check.OutputLength(output, outOff, BlockSize, "output buffer is too short.");
 
             if (currentBlockOffset > 0)
             {
@@ -344,11 +347,7 @@ 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);
@@ -372,8 +371,55 @@ namespace Org.BouncyCastle.Crypto.Macs
 
             Reset();
             return BlockSize;
+#endif
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            Check.OutputLength(output, BlockSize, "output buffer is too short.");
+
+            if (currentBlockOffset > 0)
+            {
+                // Process padded block
+                if (currentBlockOffset < BlockSize)
+                {
+                    currentBlock[currentBlockOffset++] = 1;
+                    while (currentBlockOffset < BlockSize)
+                    {
+                        currentBlock[currentBlockOffset++] = 0;
+                    }
+
+                    h4 -= (1 << 24);
+                }
+
+                ProcessBlock(currentBlock);
+            }
+
+            Debug.Assert(h4 >> 26 == 0);
+
+            //h0 += (h4 >> 26) * 5U + 5U; h4 &= 0x3ffffff;
+            h0 += 5U;
+            h1 += h0 >> 26; h0 &= 0x3ffffff;
+            h2 += h1 >> 26; h1 &= 0x3ffffff;
+            h3 += h2 >> 26; h2 &= 0x3ffffff;
+            h4 += h3 >> 26; h3 &= 0x3ffffff;
+
+            long c = ((int)(h4 >> 26) - 1) * 5;
+            c += (long)k0 + ((h0) | (h1 << 26));
+            Pack.UInt32_To_LE((uint)c, output); c >>= 32;
+            c += (long)k1 + ((h1 >> 6) | (h2 << 20));
+            Pack.UInt32_To_LE((uint)c, output[4..]); c >>= 32;
+            c += (long)k2 + ((h2 >> 12) | (h3 << 14));
+            Pack.UInt32_To_LE((uint)c, output[8..]); c >>= 32;
+            c += (long)k3 + ((h3 >> 18) | (h4 << 8));
+            Pack.UInt32_To_LE((uint)c, output[12..]);
+
+            Reset();
+            return BlockSize;
+        }
+#endif
+
         public void Reset()
         {
             currentBlockOffset = 0;
diff --git a/crypto/src/crypto/macs/SipHash.cs b/crypto/src/crypto/macs/SipHash.cs
index fc0a66ed1..2e8a89e3d 100644
--- a/crypto/src/crypto/macs/SipHash.cs
+++ b/crypto/src/crypto/macs/SipHash.cs
@@ -190,6 +190,15 @@ namespace Org.BouncyCastle.Crypto.Macs
             return 8;
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            long result = DoFinal();
+            Pack.UInt64_To_LE((ulong)result, output);
+            return 8;
+        }
+#endif
+
         public virtual void Reset()
         {
             v0 = k0 ^ 0x736f6d6570736575L;
diff --git a/crypto/src/crypto/macs/SkeinMac.cs b/crypto/src/crypto/macs/SkeinMac.cs
index 6adc93ef9..aaf5b312d 100644
--- a/crypto/src/crypto/macs/SkeinMac.cs
+++ b/crypto/src/crypto/macs/SkeinMac.cs
@@ -120,5 +120,12 @@ namespace Org.BouncyCastle.Crypto.Macs
 		{
 			return engine.DoFinal(output, outOff);
 		}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public int DoFinal(Span<byte> output)
+		{
+			return engine.DoFinal(output);
+		}
+#endif
 	}
 }
diff --git a/crypto/src/crypto/macs/VMPCMac.cs b/crypto/src/crypto/macs/VMPCMac.cs
index 76912f736..c2902179f 100644
--- a/crypto/src/crypto/macs/VMPCMac.cs
+++ b/crypto/src/crypto/macs/VMPCMac.cs
@@ -22,6 +22,9 @@ namespace Org.BouncyCastle.Crypto.Macs
 
 		public virtual int DoFinal(byte[] output, int outOff)
 		{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+			return DoFinal(output.AsSpan(outOff));
+#else
 			// Execute the Post-Processing Phase
 			for (int r = 1; r < 25; r++)
 			{
@@ -68,7 +71,60 @@ namespace Org.BouncyCastle.Crypto.Macs
 			Reset();
 
 			return M.Length;
+#endif
+		}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+		public virtual int DoFinal(Span<byte> output)
+        {
+			// 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);
+			}
+
+			// 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;
+			}
+
+			// 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];
+
+				byte temp = P[i & 0xff];
+				P[i & 0xff] = P[s & 0xff];
+				P[s & 0xff] = temp;
+			}
+
+			M.CopyTo(output);
+			Reset();
+
+			return M.Length;
 		}
+#endif
 
 		public virtual string AlgorithmName
 		{