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

PaddedBufferedBlockCipher

using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Paddings { public class PaddedBufferedBlockCipher : BufferedBlockCipher { private readonly IBlockCipherPadding m_padding; public PaddedBufferedBlockCipher(IBlockCipher cipher, IBlockCipherPadding padding) : this(EcbBlockCipher.GetBlockCipherMode(cipher), padding) { } public PaddedBufferedBlockCipher(IBlockCipherMode cipherMode, IBlockCipherPadding padding) : base(cipherMode) { m_padding = padding; } public PaddedBufferedBlockCipher(IBlockCipherMode cipherMode) : this(cipherMode, new Pkcs7Padding()) { } public override void Init(bool forEncryption, ICipherParameters parameters) { base.forEncryption = forEncryption; SecureRandom random = null; ParametersWithRandom parametersWithRandom = parameters as ParametersWithRandom; if (parametersWithRandom != null) { random = parametersWithRandom.Random; parameters = parametersWithRandom.Parameters; } Reset(); m_padding.Init(random); m_cipherMode.Init(forEncryption, parameters); } public override int GetOutputSize(int length) { int num = bufOff + length; int num2 = buf.Length; if (!forEncryption) return BufferedCipherBase.GetFullBlocksSize(num + num2 - 1, num2); return BufferedCipherBase.GetFullBlocksSize(num, num2) + num2; } public override int GetUpdateOutputSize(int length) { return BufferedCipherBase.GetFullBlocksSize(bufOff + length - 1, buf.Length); } 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) { int result = 0; if (bufOff == buf.Length) { Check.OutputLength(output, buf.Length, "output buffer too short"); result = m_cipherMode.ProcessBlock(buf, output); bufOff = 0; } buf[bufOff++] = input; return result; } 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 int DoFinal(byte[] output, int outOff) { return DoFinal(Spans.FromNullable(output, outOff)); } public override int DoFinal(Span<byte> output) { try { int num = 0; int num2 = buf.Length; if (forEncryption) { if (bufOff == num2) { Check.OutputLength(output, num2 * 2, "output buffer too short"); num = m_cipherMode.ProcessBlock(buf, output); bufOff = 0; } else Check.OutputLength(output, num2, "output buffer too short"); m_padding.AddPadding(buf, bufOff); int num3 = num; IBlockCipherMode cipherMode = m_cipherMode; ReadOnlySpan<byte> input = buf; int num4 = num; num = num3 + cipherMode.ProcessBlock(input, output.Slice(num4, output.Length - num4)); } else { Check.DataLength(bufOff != num2, "last block incomplete in decryption"); num = m_cipherMode.ProcessBlock(buf, buf); num -= m_padding.PadCount(buf); Check.OutputLength(output, num, "output buffer too short"); buf.AsSpan(0, num).CopyTo(output); } return num; } finally { Reset(); } } } }