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);
|