From 198d760145c81f944ff9e3579d07bed14c58f7b7 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Tue, 30 Aug 2022 13:21:28 +0700 Subject: Span-based variant for IStreamCipher.ProcessBytes --- crypto/src/crypto/IStreamCipher.cs | 45 +++++++++++++++++++----------- crypto/src/crypto/StreamBlockCipher.cs | 22 +++++++++++---- crypto/src/crypto/engines/HC128Engine.cs | 15 ++++++++++ crypto/src/crypto/engines/HC256Engine.cs | 15 ++++++++++ crypto/src/crypto/engines/ISAACEngine.cs | 21 ++++++++++++++ crypto/src/crypto/engines/RC4Engine.cs | 34 ++++++++++++++++++---- crypto/src/crypto/engines/Salsa20Engine.cs | 24 ++++++++++++++++ crypto/src/crypto/engines/VMPCEngine.cs | 21 ++++++++++++++ 8 files changed, 169 insertions(+), 28 deletions(-) (limited to 'crypto/src') 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 /// the result of processing the input byte. byte ReturnByte(byte input); - /// - /// Process a block of bytes from input putting the result into output. - /// - /// The input byte array. - /// - /// The offset into input where the data to be processed starts. - /// - /// The number of bytes to be processed. - /// The output buffer the processed bytes go into. - /// - /// The offset into output the processed data starts at. - /// - /// If the output buffer is too small. + /// + /// Process a block of bytes from , putting the result into . + /// + /// The input byte array. + /// + /// The offset into input where the data to be processed starts. + /// + /// The number of bytes to be processed. + /// The output buffer the processed bytes go into. + /// + /// The offset into output the processed data starts at. + /// + /// If the input buffer is too small. + /// If the output buffer is too small. void ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff); - /// - /// Reset the cipher to the same state as it was after the last init (if there was one). - /// - void Reset(); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// + /// Process a block of bytes from , putting the result into . + /// + /// The input span. + /// The output span. + /// If the output span is too small. + void ProcessBytes(ReadOnlySpan input, Span output); +#endif + + /// + /// Reset the cipher to the same state as it was after the last init (if there was one). + /// + 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 input, Span 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 input, Span 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 input, Span 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 input, Span 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 input, Span 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 input, Span 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 input, Span 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); -- cgit 1.5.1