summary refs log tree commit diff
path: root/crypto/src/crypto/BufferedBlockCipher.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/crypto/BufferedBlockCipher.cs')
-rw-r--r--crypto/src/crypto/BufferedBlockCipher.cs72
1 files changed, 62 insertions, 10 deletions
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). */