using System; using System.Globalization; namespace Renci.SshNet.Security.Cryptography.Ciphers.Modes { /// /// Implements CTR cipher mode /// public class CtrCipherMode : CipherMode { private readonly byte[] _ivOutput; /// /// Initializes a new instance of the class. /// /// The iv. public CtrCipherMode(byte[] iv) : base(iv) { _ivOutput = new byte[iv.Length]; } /// /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array. /// /// The input data to encrypt. /// The offset into the input byte array from which to begin using data. /// The number of bytes in the input byte array to use as data. /// The output to which to write encrypted data. /// The offset into the output byte array from which to begin writing data. /// /// The number of bytes encrypted. /// public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer.Length - inputOffset < _blockSize) { throw new ArgumentException("Invalid input buffer"); } if (outputBuffer.Length - outputOffset < _blockSize) { throw new ArgumentException("Invalid output buffer"); } if (inputCount != _blockSize) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); } _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); for (var i = 0; i < _blockSize; i++) { outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); } var j = IV.Length; while (--j >= 0 && ++IV[j] == 0) { // Intentionally empty block } return _blockSize; } /// /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array. /// /// The input data to decrypt. /// The offset into the input byte array from which to begin using data. /// The number of bytes in the input byte array to use as data. /// The output to which to write decrypted data. /// The offset into the output byte array from which to begin writing data. /// /// The number of bytes decrypted. /// public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer.Length - inputOffset < _blockSize) { throw new ArgumentException("Invalid input buffer"); } if (outputBuffer.Length - outputOffset < _blockSize) { throw new ArgumentException("Invalid output buffer"); } if (inputCount != _blockSize) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); } _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); for (var i = 0; i < _blockSize; i++) { outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); } var j = IV.Length; while (--j >= 0 && ++IV[j] == 0) { // Intentionally empty block } return _blockSize; } } }