<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" />

BufferedBlockCipher

using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto { public class BufferedBlockCipher : BufferedCipherBase { internal byte[] buf; internal int bufOff; internal bool forEncryption; internal IBlockCipherMode m_cipherMode; public override string AlgorithmName => m_cipherMode.AlgorithmName; protected BufferedBlockCipher() { } public BufferedBlockCipher(IBlockCipher cipher) : this(EcbBlockCipher.GetBlockCipherMode(cipher)) { } public BufferedBlockCipher(IBlockCipherMode cipherMode) { if (cipherMode == null) throw new ArgumentNullException("cipherMode"); int blockSize = cipherMode.GetBlockSize(); if (blockSize < 1) throw new ArgumentException("must have a positive block size", "cipherMode"); m_cipherMode = cipherMode; buf = new byte[blockSize]; bufOff = 0; } public override void Init(bool forEncryption, ICipherParameters parameters) { this.forEncryption = forEncryption; parameters = ParameterUtilities.IgnoreRandom(parameters); Reset(); m_cipherMode.Init(forEncryption, parameters); } public override int GetBlockSize() { return m_cipherMode.GetBlockSize(); } public override int GetOutputSize(int length) { return bufOff + length; } public override int GetUpdateOutputSize(int length) { return BufferedCipherBase.GetFullBlocksSize(bufOff + length, buf.Length); } public override byte[] ProcessByte(byte input) { int updateOutputSize = GetUpdateOutputSize(1); byte[] array = (updateOutputSize > 0) ? new byte[updateOutputSize] : null; int num = ProcessByte(input, array, 0); if (updateOutputSize > 0 && num < updateOutputSize) return Arrays.CopyOf(array, num); return array; } public override int ProcessByte(byte input, byte[] output, int outOff) { return ProcessByte(input, Spans.FromNullable(output, outOff)); } public override int ProcessByte(byte input, Span<byte> output) { buf[bufOff++] = input; if (bufOff == buf.Length) { Check.OutputLength(output, buf.Length, "output buffer too short"); bufOff = 0; return m_cipherMode.ProcessBlock(buf, output); } return 0; } public override byte[] ProcessBytes(byte[] input, int inOff, int length) { if (input == null) throw new ArgumentNullException("input"); if (length < 1) return null; int updateOutputSize = GetUpdateOutputSize(length); byte[] array = (updateOutputSize > 0) ? new byte[updateOutputSize] : null; int num = ProcessBytes(input, inOff, length, array, 0); if (updateOutputSize > 0 && num < updateOutputSize) return Arrays.CopyOf(array, num); return array; } public override int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff) { if (length < 1) { if (length < 0) throw new ArgumentException("Can't have a negative input length!"); return 0; } return ProcessBytes(input.AsSpan(inOff, length), Spans.FromNullable(output, outOff)); } public override int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output) { int num = 0; int num2 = buf.Length; int num3 = num2 - bufOff; if (input.Length >= num3) { int updateOutputSize = GetUpdateOutputSize(input.Length); Check.OutputLength(output, updateOutputSize, "output buffer too short"); input.Slice(0, num3).CopyTo(buf.AsSpan(bufOff)); int num4 = num3; input = input.Slice(num4, input.Length - num4); if (output.Slice(0, num2).Overlaps(input)) { byte[] array = new byte[input.Length]; input.CopyTo(array); input = array; } num = m_cipherMode.ProcessBlock(buf, output); bufOff = 0; while (input.Length >= num2) { int num5 = num; IBlockCipherMode cipherMode = m_cipherMode; ReadOnlySpan<byte> input2 = input; num4 = num; num = num5 + cipherMode.ProcessBlock(input2, output.Slice(num4, output.Length - num4)); num4 = num2; input = input.Slice(num4, input.Length - num4); } } input.CopyTo(buf.AsSpan(bufOff)); bufOff += input.Length; return num; } public override byte[] DoFinal() { int outputSize = GetOutputSize(0); if (outputSize < 1) { Reset(); return BufferedCipherBase.EmptyBuffer; } byte[] array = new byte[outputSize]; int num = DoFinal(array, 0); if (num < outputSize) return Arrays.CopyOf(array, num); return array; } public override byte[] DoFinal(byte[] input, int inOff, int inLen) { if (input == null) throw new ArgumentNullException("input"); int outputSize = GetOutputSize(inLen); if (outputSize < 1) { Reset(); return BufferedCipherBase.EmptyBuffer; } byte[] array = new byte[outputSize]; int num = (inLen > 0) ? ProcessBytes(input, inOff, inLen, array, 0) : 0; num += DoFinal(array, num); if (num < outputSize) return Arrays.CopyOf(array, num); return array; } public override int DoFinal(byte[] output, int outOff) { return DoFinal(Spans.FromNullable(output, outOff)); } public override int DoFinal(Span<byte> output) { try { if (bufOff != 0) { Check.DataLength(!m_cipherMode.IsPartialBlockOkay, "data not block size aligned"); Check.OutputLength(output, bufOff, "output buffer too short for DoFinal()"); m_cipherMode.ProcessBlock(buf, buf); buf.AsSpan(0, bufOff).CopyTo(output); } return bufOff; } finally { Reset(); } } public override void Reset() { Array.Clear(buf, 0, buf.Length); bufOff = 0; m_cipherMode.Reset(); } } }