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)
        {
            buf[bufOff++] = input;
            if (bufOff == buf.Length) {
                Check.OutputLength(output, outOff, buf.Length, "output buffer too short");
                bufOff = 0;
                return m_cipherMode.ProcessBlock(buf, 0, output, outOff);
            }
            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;
            }
            int num = 0;
            int num2 = buf.Length;
            int num3 = num2 - bufOff;
            if (length >= num3) {
                int updateOutputSize = GetUpdateOutputSize(length);
                Check.OutputLength(output, outOff, updateOutputSize, "output buffer too short");
                Array.Copy(input, inOff, buf, bufOff, num3);
                inOff += num3;
                length -= num3;
                if (output == input && BufferedCipherBase.SegmentsOverlap(outOff, num2, inOff, length)) {
                    input = new byte[length];
                    Array.Copy(output, inOff, input, 0, length);
                    inOff = 0;
                }
                num = m_cipherMode.ProcessBlock(buf, 0, output, outOff);
                bufOff = 0;
                while (length >= num2) {
                    num += m_cipherMode.ProcessBlock(input, inOff, output, outOff + num);
                    inOff += num2;
                    length -= num2;
                }
            }
            Array.Copy(input, inOff, buf, bufOff, length);
            bufOff += 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)
        {
            try {
                if (bufOff != 0) {
                    Check.DataLength(!m_cipherMode.IsPartialBlockOkay, "data not block size aligned");
                    Check.OutputLength(output, outOff, bufOff, "output buffer too short for DoFinal()");
                    m_cipherMode.ProcessBlock(buf, 0, buf, 0);
                    Array.Copy(buf, 0, output, outOff, bufOff);
                }
                return bufOff;
            } finally {
                Reset();
            }
        }
        public override void Reset()
        {
            Array.Clear(buf, 0, buf.Length);
            bufOff = 0;
            m_cipherMode.Reset();
        }
    }
}