summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-08-30 13:21:28 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-08-30 13:21:28 +0700
commit198d760145c81f944ff9e3579d07bed14c58f7b7 (patch)
tree090876fffef9932c47ede311e602c56455b37ea7
parentSpan-based variant for ISP80090Drbg.Generate (diff)
downloadBouncyCastle.NET-ed25519-198d760145c81f944ff9e3579d07bed14c58f7b7.tar.xz
Span-based variant for IStreamCipher.ProcessBytes
-rw-r--r--crypto/src/crypto/IStreamCipher.cs45
-rw-r--r--crypto/src/crypto/StreamBlockCipher.cs22
-rw-r--r--crypto/src/crypto/engines/HC128Engine.cs15
-rw-r--r--crypto/src/crypto/engines/HC256Engine.cs15
-rw-r--r--crypto/src/crypto/engines/ISAACEngine.cs21
-rw-r--r--crypto/src/crypto/engines/RC4Engine.cs34
-rw-r--r--crypto/src/crypto/engines/Salsa20Engine.cs24
-rw-r--r--crypto/src/crypto/engines/VMPCEngine.cs21
8 files changed, 169 insertions, 28 deletions
diff --git a/crypto/src/crypto/IStreamCipher.cs b/crypto/src/crypto/IStreamCipher.cs
index 8e575a7e5..0408b33c9 100644
--- a/crypto/src/crypto/IStreamCipher.cs
+++ b/crypto/src/crypto/IStreamCipher.cs
@@ -22,24 +22,35 @@ namespace Org.BouncyCastle.Crypto
 		/// <returns>the result of processing the input byte.</returns>
         byte ReturnByte(byte input);
 
-		/// <summary>
-		/// Process a block of bytes from <c>input</c> putting the result into <c>output</c>.
-		/// </summary>
-		/// <param name="input">The input byte array.</param>
-		/// <param name="inOff">
-		/// The offset into <c>input</c> where the data to be processed starts.
-		/// </param>
-		/// <param name="length">The number of bytes to be processed.</param>
-		/// <param name="output">The output buffer the processed bytes go into.</param>
-		/// <param name="outOff">
-		/// The offset into <c>output</c> the processed data starts at.
-		/// </param>
-		/// <exception cref="DataLengthException">If the output buffer is too small.</exception>
+        /// <summary>
+        /// Process a block of bytes from <paramref name="input"/>, putting the result into <paramref name="output"/>.
+        /// </summary>
+        /// <param name="input">The input byte array.</param>
+        /// <param name="inOff">
+        /// The offset into <c>input</c> where the data to be processed starts.
+        /// </param>
+        /// <param name="length">The number of bytes to be processed.</param>
+        /// <param name="output">The output buffer the processed bytes go into.</param>
+        /// <param name="outOff">
+        /// The offset into <c>output</c> the processed data starts at.
+        /// </param>
+        /// <exception cref="DataLengthException">If the input buffer is too small.</exception>
+        /// <exception cref="OutputLengthException">If the output buffer is too small.</exception>
         void ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff);
 
-		/// <summary>
-		/// Reset the cipher to the same state as it was after the last init (if there was one).
-		/// </summary>
-		void Reset();
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        /// <summary>
+        /// Process a block of bytes from <paramref name="input"/>, putting the result into <paramref name="output"/>.
+        /// </summary>
+		/// <param name="input">The input span.</param>
+		/// <param name="output">The output span.</param>
+        /// <exception cref="OutputLengthException">If the output span is too small.</exception>
+        void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output);
+#endif
+
+        /// <summary>
+        /// Reset the cipher to the same state as it was after the last init (if there was one).
+        /// </summary>
+        void Reset();
     }
 }
diff --git a/crypto/src/crypto/StreamBlockCipher.cs b/crypto/src/crypto/StreamBlockCipher.cs
index ef2a8b68a..0cd9d110a 100644
--- a/crypto/src/crypto/StreamBlockCipher.cs
+++ b/crypto/src/crypto/StreamBlockCipher.cs
@@ -1,7 +1,5 @@
 using System;
 
-using Org.BouncyCastle.Crypto.Parameters;
-
 namespace Org.BouncyCastle.Crypto
 {
 	/**
@@ -88,8 +86,8 @@ namespace Org.BouncyCastle.Crypto
 			byte[]	output,
 			int		outOff)
 		{
-			if (outOff + length > output.Length)
-				throw new DataLengthException("output buffer too small in ProcessBytes()");
+			Check.DataLength(input, inOff, length, "input buffer too short");
+            Check.OutputLength(output, outOff, length, "output buffer too short");
 
 			for (int i = 0; i != length; i++)
 			{
@@ -97,11 +95,23 @@ namespace Org.BouncyCastle.Crypto
 			}
 		}
 
-		/**
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            Check.OutputLength(output, input.Length, "output buffer too short");
+
+            for (int i = 0; i != input.Length; i++)
+            {
+				cipher.ProcessBlock(input[i..], output[i..]);
+            }
+        }
+#endif
+
+        /**
 		* reset the underlying cipher. This leaves it in the same state
 		* it was at after the last init (if there was one).
 		*/
-		public void Reset()
+        public void Reset()
 		{
 			cipher.Reset();
 		}
diff --git a/crypto/src/crypto/engines/HC128Engine.cs b/crypto/src/crypto/engines/HC128Engine.cs
index b83eb7083..6971361dd 100644
--- a/crypto/src/crypto/engines/HC128Engine.cs
+++ b/crypto/src/crypto/engines/HC128Engine.cs
@@ -222,6 +222,21 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            if (!initialised)
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+            Check.OutputLength(output, input.Length, "output buffer too short");
+
+            for (int i = 0; i < input.Length; i++)
+            {
+                output[i] = (byte)(input[i] ^ GetByte());
+            }
+        }
+#endif
+
         public virtual void Reset()
 		{
 			Init();
diff --git a/crypto/src/crypto/engines/HC256Engine.cs b/crypto/src/crypto/engines/HC256Engine.cs
index d8d83a634..8a17af433 100644
--- a/crypto/src/crypto/engines/HC256Engine.cs
+++ b/crypto/src/crypto/engines/HC256Engine.cs
@@ -206,6 +206,21 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            if (!initialised)
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+            Check.OutputLength(output, input.Length, "output buffer too short");
+
+            for (int i = 0; i < input.Length; i++)
+            {
+                output[i] = (byte)(input[i] ^ GetByte());
+            }
+        }
+#endif
+
         public virtual void Reset()
 		{
 			Init();
diff --git a/crypto/src/crypto/engines/ISAACEngine.cs b/crypto/src/crypto/engines/ISAACEngine.cs
index b94ee6ed9..b0ab30263 100644
--- a/crypto/src/crypto/engines/ISAACEngine.cs
+++ b/crypto/src/crypto/engines/ISAACEngine.cs
@@ -94,6 +94,27 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            if (!initialised)
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+            Check.OutputLength(output, input.Length, "output buffer too short");
+
+            for (int i = 0; i < input.Length; i++)
+            {
+                if (index == 0)
+                {
+                    isaac();
+                    keyStream = Pack.UInt32_To_BE(results);
+                }
+                output[i] = (byte)(keyStream[index++] ^ input[i]);
+                index &= 1023;
+            }
+        }
+#endif
+
         public virtual string AlgorithmName
         {
             get { return "ISAAC"; }
diff --git a/crypto/src/crypto/engines/RC4Engine.cs b/crypto/src/crypto/engines/RC4Engine.cs
index a515bb04e..5ee07c766 100644
--- a/crypto/src/crypto/engines/RC4Engine.cs
+++ b/crypto/src/crypto/engines/RC4Engine.cs
@@ -83,16 +83,40 @@ namespace Org.BouncyCastle.Crypto.Engines
                 x = (x + 1) & 0xff;
                 y = (engineState[x] + y) & 0xff;
 
+                byte sx = engineState[x];
+                byte sy = engineState[y];
+
+                // swap
+                engineState[x] = sy;
+                engineState[y] = sx;
+
+                // xor
+                output[i+outOff] = (byte)(input[i + inOff] ^ engineState[(sx + sy) & 0xff]);
+            }
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            Check.OutputLength(output, input.Length, "output buffer too short");
+
+            for (int i = 0; i < input.Length; i++)
+            {
+                x = (x + 1) & 0xff;
+                y = (engineState[x] + y) & 0xff;
+
+                byte sx = engineState[x];
+                byte sy = engineState[y];
+
                 // swap
-                byte tmp = engineState[x];
-                engineState[x] = engineState[y];
-                engineState[y] = tmp;
+                engineState[x] = sy;
+                engineState[y] = sx;
 
                 // xor
-                output[i+outOff] = (byte)(input[i + inOff]
-                        ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+                output[i] = (byte)(input[i] ^ engineState[(sx + sy) & 0xff]);
             }
         }
+#endif
 
         public virtual void Reset()
         {
diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs
index 77b08f9fc..c3e44f645 100644
--- a/crypto/src/crypto/engines/Salsa20Engine.cs
+++ b/crypto/src/crypto/engines/Salsa20Engine.cs
@@ -181,6 +181,30 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            if (!initialised)
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+            Check.OutputLength(output, input.Length, "output buffer too short");
+
+            if (LimitExceeded((uint)input.Length))
+                throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV");
+
+            for (int i = 0; i < input.Length; i++)
+            {
+                if (index == 0)
+                {
+                    GenerateKeyStream(keyStream);
+                    AdvanceCounter();
+                }
+                output[i] = (byte)(keyStream[index++] ^ input[i]);
+                index &= 63;
+            }
+        }
+#endif
+
         public virtual void Reset()
 		{
 			index = 0;
diff --git a/crypto/src/crypto/engines/VMPCEngine.cs b/crypto/src/crypto/engines/VMPCEngine.cs
index 852901e36..d8974b6ce 100644
--- a/crypto/src/crypto/engines/VMPCEngine.cs
+++ b/crypto/src/crypto/engines/VMPCEngine.cs
@@ -110,6 +110,27 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            Check.OutputLength(output, input.Length, "output buffer too short");
+
+            for (int i = 0; i < input.Length; i++)
+            {
+                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
+                output[i] = (byte)(input[i] ^ z);
+            }
+        }
+#endif
+
         public virtual void Reset()
         {
             InitKey(this.workingKey, this.workingIV);