using System; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; namespace Org.BouncyCastle.Crypto.Modes { /** * Implements the Segmented Integer Counter (SIC) mode on top of a simple * block cipher. */ public class SicBlockCipher : IBlockCipher { private readonly IBlockCipher cipher; private readonly int blockSize; private readonly byte[] IV; private readonly byte[] counter; private readonly byte[] counterOut; /** * Basic constructor. * * @param c the block cipher to be used. */ public SicBlockCipher(IBlockCipher cipher) { this.cipher = cipher; this.blockSize = cipher.GetBlockSize(); this.IV = new byte[blockSize]; this.counter = new byte[blockSize]; this.counterOut = new byte[blockSize]; } /** * return the underlying block cipher that we are wrapping. * * @return the underlying block cipher that we are wrapping. */ public IBlockCipher GetUnderlyingCipher() { return cipher; } public void Init( bool forEncryption, //ignored by this CTR mode ICipherParameters parameters) { if (parameters is ParametersWithIV) { ParametersWithIV ivParam = (ParametersWithIV) parameters; byte[] iv = ivParam.GetIV(); Array.Copy(iv, 0, IV, 0, IV.Length); Reset(); cipher.Init(true, ivParam.Parameters); } else { throw new ArgumentException("SIC mode requires ParametersWithIV", "parameters"); } } public string AlgorithmName { get { return cipher.AlgorithmName + "/SIC"; } } public bool IsPartialBlockOkay { get { return true; } } public int GetBlockSize() { return cipher.GetBlockSize(); } public int ProcessBlock( byte[] input, int inOff, byte[] output, int outOff) { cipher.ProcessBlock(counter, 0, counterOut, 0); // // XOR the counterOut with the plaintext producing the cipher text // for (int i = 0; i < counterOut.Length; i++) { output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]); } // Increment the counter int j = counter.Length; while (--j >= 0 && ++counter[j] == 0) { } return counter.Length; } public void Reset() { Array.Copy(IV, 0, counter, 0, counter.Length); cipher.Reset(); } } }