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

CbcBlockCipher

using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Modes { public sealed class CbcBlockCipher : IBlockCipherMode, IBlockCipher { private byte[] IV; private byte[] cbcV; private byte[] cbcNextV; private int blockSize; private IBlockCipher cipher; private bool encrypting; public IBlockCipher UnderlyingCipher => cipher; public string AlgorithmName => cipher.AlgorithmName + "/CBC"; public bool IsPartialBlockOkay => false; public CbcBlockCipher(IBlockCipher cipher) { this.cipher = cipher; blockSize = cipher.GetBlockSize(); IV = new byte[blockSize]; cbcV = new byte[blockSize]; cbcNextV = new byte[blockSize]; } public void Init(bool forEncryption, ICipherParameters parameters) { bool flag = encrypting; encrypting = forEncryption; ParametersWithIV parametersWithIV = parameters as ParametersWithIV; if (parametersWithIV != null) { if (parametersWithIV.IVLength != blockSize) throw new ArgumentException("initialisation vector must be the same length as block size"); parametersWithIV.CopyIVTo(IV, 0, blockSize); parameters = parametersWithIV.Parameters; } else Arrays.Fill(IV, 0); Reset(); if (parameters != null) cipher.Init(encrypting, parameters); else if (flag != encrypting) { throw new ArgumentException("cannot change encrypting state without providing key."); } } public int GetBlockSize() { return cipher.GetBlockSize(); } public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff) { if (!encrypting) return DecryptBlock(input, inOff, output, outOff); return EncryptBlock(input, inOff, output, outOff); } public void Reset() { Array.Copy(IV, 0, cbcV, 0, IV.Length); Array.Clear(cbcNextV, 0, cbcNextV.Length); } private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff) { Check.DataLength(input, inOff, blockSize, "input buffer too short"); Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short"); for (int i = 0; i < blockSize; i++) { cbcV[i] ^= input[inOff + i]; } int result = cipher.ProcessBlock(cbcV, 0, outBytes, outOff); Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length); return result; } private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff) { Check.DataLength(input, inOff, blockSize, "input buffer too short"); Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short"); Array.Copy(input, inOff, cbcNextV, 0, blockSize); int result = cipher.ProcessBlock(input, inOff, outBytes, outOff); for (int i = 0; i < blockSize; i++) { outBytes[outOff + i] ^= cbcV[i]; } byte[] array = cbcV; cbcV = cbcNextV; cbcNextV = array; return result; } } }