diff --git a/crypto/src/crypto/BufferedAeadBlockCipher.cs b/crypto/src/crypto/BufferedAeadBlockCipher.cs
index 7ba41090f..92eab9dd4 100644
--- a/crypto/src/crypto/BufferedAeadBlockCipher.cs
+++ b/crypto/src/crypto/BufferedAeadBlockCipher.cs
@@ -172,7 +172,14 @@ namespace Org.BouncyCastle.Crypto
return cipher.ProcessBytes(input, inOff, length, output, outOff);
}
- public override byte[] DoFinal()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ return cipher.ProcessBytes(input, output);
+ }
+#endif
+
+ public override byte[] DoFinal()
{
byte[] outBytes = new byte[GetOutputSize(0)];
@@ -235,11 +242,25 @@ namespace Org.BouncyCastle.Crypto
return cipher.DoFinal(output, outOff);
}
- /**
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ return cipher.DoFinal(output);
+ }
+
+ public override int DoFinal(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int len = cipher.ProcessBytes(input, output);
+ len += cipher.DoFinal(output[len..]);
+ return len;
+ }
+#endif
+
+ /**
* Reset the buffer and cipher. After resetting the object is in the same
* state as it was after the last init (if there was one).
*/
- public override void Reset()
+ public override void Reset()
{
cipher.Reset();
}
diff --git a/crypto/src/crypto/BufferedAeadCipher.cs b/crypto/src/crypto/BufferedAeadCipher.cs
index c689c1eab..aba64f0f4 100644
--- a/crypto/src/crypto/BufferedAeadCipher.cs
+++ b/crypto/src/crypto/BufferedAeadCipher.cs
@@ -171,6 +171,13 @@ namespace Org.BouncyCastle.Crypto
return cipher.ProcessBytes(input, inOff, length, output, outOff);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ return cipher.ProcessBytes(input, output);
+ }
+#endif
+
public override byte[] DoFinal()
{
byte[] outBytes = new byte[GetOutputSize(0)];
@@ -234,6 +241,20 @@ namespace Org.BouncyCastle.Crypto
return cipher.DoFinal(output, outOff);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ return cipher.DoFinal(output);
+ }
+
+ public override int DoFinal(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int len = cipher.ProcessBytes(input, output);
+ len += cipher.DoFinal(output[len..]);
+ return len;
+ }
+#endif
+
/**
* Reset the buffer and cipher. After resetting the object is in the same
* state as it was after the last init (if there was one).
diff --git a/crypto/src/crypto/BufferedAsymmetricBlockCipher.cs b/crypto/src/crypto/BufferedAsymmetricBlockCipher.cs
index bf00f3ece..83c2fe70c 100644
--- a/crypto/src/crypto/BufferedAsymmetricBlockCipher.cs
+++ b/crypto/src/crypto/BufferedAsymmetricBlockCipher.cs
@@ -1,7 +1,4 @@
using System;
-using System.Diagnostics;
-
-using Org.BouncyCastle.Crypto.Engines;
namespace Org.BouncyCastle.Crypto
{
@@ -111,7 +108,18 @@ namespace Org.BouncyCastle.Crypto
return null;
}
- /**
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ Check.DataLength(input, buffer.Length - bufOff, "attempt to process message too long for cipher");
+
+ input.CopyTo(buffer.AsSpan(bufOff));
+ bufOff += input.Length;
+ return 0;
+ }
+#endif
+
+ /**
* process the contents of the buffer using the underlying
* cipher.
*
@@ -139,7 +147,24 @@ namespace Org.BouncyCastle.Crypto
return DoFinal();
}
- /// <summary>Reset the buffer</summary>
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ int result = 0;
+ if (bufOff > 0)
+ {
+ byte[] outBytes = cipher.ProcessBlock(buffer, 0, bufOff);
+ outBytes.CopyTo(output);
+ result = outBytes.Length;
+ }
+
+ Reset();
+
+ return result;
+ }
+#endif
+
+ /// <summary>Reset the buffer</summary>
public override void Reset()
{
if (buffer != null)
diff --git a/crypto/src/crypto/BufferedBlockCipher.cs b/crypto/src/crypto/BufferedBlockCipher.cs
index c87d2daf9..3b000ed59 100644
--- a/crypto/src/crypto/BufferedBlockCipher.cs
+++ b/crypto/src/crypto/BufferedBlockCipher.cs
@@ -1,5 +1,4 @@
using System;
-using System.Diagnostics;
using Org.BouncyCastle.Crypto.Parameters;
@@ -228,14 +227,14 @@ namespace Org.BouncyCastle.Crypto
int resultLen = 0;
int gapLen = buf.Length - bufOff;
- if (length > gapLen)
+ if (length >= gapLen)
{
Array.Copy(input, inOff, buf, bufOff, gapLen);
resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
bufOff = 0;
length -= gapLen;
inOff += gapLen;
- while (length > buf.Length)
+ while (length >= buf.Length)
{
resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen);
length -= blockSize;
@@ -244,15 +243,44 @@ namespace Org.BouncyCastle.Crypto
}
Array.Copy(input, inOff, buf, bufOff, length);
bufOff += length;
- if (bufOff == buf.Length)
- {
- resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
- bufOff = 0;
- }
return resultLen;
}
- public override byte[] DoFinal()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (input.IsEmpty)
+ return 0;
+
+ int blockSize = GetBlockSize();
+ int outLength = GetUpdateOutputSize(input.Length);
+
+ if (outLength > 0)
+ {
+ Check.OutputLength(output, outLength, "output buffer too short");
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.Length - bufOff;
+ if (input.Length >= gapLen)
+ {
+ input[..gapLen].CopyTo(buf.AsSpan(bufOff));
+ resultLen += cipher.ProcessBlock(buf, output);
+ bufOff = 0;
+ input = input[gapLen..];
+ while (input.Length >= buf.Length)
+ {
+ resultLen += cipher.ProcessBlock(input, output[resultLen..]);
+ input = input[blockSize..];
+ }
+ }
+ input.CopyTo(buf.AsSpan(bufOff));
+ bufOff += input.Length;
+ return resultLen;
+ }
+#endif
+
+ public override byte[] DoFinal()
{
byte[] outBytes = EmptyBuffer;
@@ -352,7 +380,31 @@ namespace Org.BouncyCastle.Crypto
}
}
- /**
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ try
+ {
+ if (bufOff != 0)
+ {
+ Check.DataLength(!cipher.IsPartialBlockOkay, "data not block size aligned");
+ Check.OutputLength(output, bufOff, "output buffer too short for DoFinal()");
+
+ // NB: Can't copy directly, or we may write too much output
+ cipher.ProcessBlock(buf, buf);
+ buf.AsSpan(0, bufOff).CopyTo(output);
+ }
+
+ return bufOff;
+ }
+ finally
+ {
+ Reset();
+ }
+ }
+#endif
+
+ /**
* Reset the buffer and cipher. After resetting the object is in the same
* state as it was after the last init (if there was one).
*/
diff --git a/crypto/src/crypto/BufferedCipherBase.cs b/crypto/src/crypto/BufferedCipherBase.cs
index 9d8610211..4b3069d0d 100644
--- a/crypto/src/crypto/BufferedCipherBase.cs
+++ b/crypto/src/crypto/BufferedCipherBase.cs
@@ -64,6 +64,10 @@ namespace Org.BouncyCastle.Crypto
return outBytes.Length;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public abstract int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output);
+#endif
+
public abstract byte[] DoFinal();
public virtual byte[] DoFinal(
@@ -108,6 +112,17 @@ namespace Org.BouncyCastle.Crypto
return len;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public abstract int DoFinal(Span<byte> output);
+
+ public virtual int DoFinal(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int len = ProcessBytes(input, output);
+ len += DoFinal(output[len..]);
+ return len;
+ }
+#endif
+
public abstract void Reset();
}
}
diff --git a/crypto/src/crypto/BufferedIesCipher.cs b/crypto/src/crypto/BufferedIesCipher.cs
index b0330e416..1aff47ab4 100644
--- a/crypto/src/crypto/BufferedIesCipher.cs
+++ b/crypto/src/crypto/BufferedIesCipher.cs
@@ -2,8 +2,6 @@ using System;
using System.IO;
using Org.BouncyCastle.Crypto.Engines;
-using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto
{
@@ -87,7 +85,15 @@ namespace Org.BouncyCastle.Crypto
return null;
}
- public override byte[] DoFinal()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ buffer.Write(input);
+ return 0;
+ }
+#endif
+
+ public override byte[] DoFinal()
{
byte[] buf = buffer.ToArray();
@@ -105,7 +111,20 @@ namespace Org.BouncyCastle.Crypto
return DoFinal();
}
- public override void Reset()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ byte[] buf = buffer.ToArray();
+
+ Reset();
+
+ byte[] block = engine.ProcessBlock(buf, 0, buf.Length);
+ block.CopyTo(output);
+ return block.Length;
+ }
+#endif
+
+ public override void Reset()
{
buffer.SetLength(0);
}
diff --git a/crypto/src/crypto/BufferedStreamCipher.cs b/crypto/src/crypto/BufferedStreamCipher.cs
index 2d4987bba..8307429cb 100644
--- a/crypto/src/crypto/BufferedStreamCipher.cs
+++ b/crypto/src/crypto/BufferedStreamCipher.cs
@@ -101,6 +101,14 @@ namespace Org.BouncyCastle.Crypto
return length;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ cipher.ProcessBytes(input, output);
+ return input.Length;
+ }
+#endif
+
public override byte[] DoFinal()
{
Reset();
@@ -123,7 +131,22 @@ namespace Org.BouncyCastle.Crypto
return output;
}
- public override void Reset()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Reset();
+ return 0;
+ }
+
+ public virtual int DoFinal(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int len = ProcessBytes(input, output);
+ Reset();
+ return len;
+ }
+#endif
+
+ public override void Reset()
{
cipher.Reset();
}
diff --git a/crypto/src/crypto/IBufferedCipher.cs b/crypto/src/crypto/IBufferedCipher.cs
index 69dec9596..ddfb524c9 100644
--- a/crypto/src/crypto/IBufferedCipher.cs
+++ b/crypto/src/crypto/IBufferedCipher.cs
@@ -28,6 +28,10 @@ namespace Org.BouncyCastle.Crypto
int ProcessBytes(byte[] input, byte[] output, int outOff);
int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output);
+#endif
+
byte[] DoFinal();
byte[] DoFinal(byte[] input);
byte[] DoFinal(byte[] input, int inOff, int length);
@@ -35,6 +39,11 @@ namespace Org.BouncyCastle.Crypto
int DoFinal(byte[] input, byte[] output, int outOff);
int DoFinal(byte[] input, int inOff, int length, byte[] output, int outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ int DoFinal(Span<byte> output);
+ int DoFinal(ReadOnlySpan<byte> input, Span<byte> output);
+#endif
+
/// <summary>
/// Reset the cipher. After resetting the cipher is in the same state
/// as it was after the last init (if there was one).
|