using System; using Renci.SshNet.Security.Cryptography.Ciphers; namespace Renci.SshNet.Security.Cryptography { /// /// Base class for block cipher implementations. /// public abstract class BlockCipher : SymmetricCipher { private readonly CipherMode _mode; private readonly CipherPadding _padding; /// /// Gets the size of the block in bytes. /// /// /// The size of the block in bytes. /// private readonly byte _blockSize; /// /// Gets the minimum data size. /// /// /// The minimum data size. /// public override byte MinimumSize { get { return BlockSize; } } /// /// Gets the size of the block. /// /// /// The size of the block. /// public byte BlockSize { get { return _blockSize; } } /// /// Initializes a new instance of the class. /// /// The key. /// Size of the block. /// Cipher mode. /// Cipher padding. /// is null. protected BlockCipher(byte[] key, byte blockSize, CipherMode mode, CipherPadding padding) : base(key) { _blockSize = blockSize; _mode = mode; _padding = padding; _mode?.Init(this); } /// /// Encrypts the specified data. /// /// The data. /// The zero-based offset in at which to begin encrypting. /// The number of bytes to encrypt from . /// Encrypted data public override byte[] Encrypt(byte[] input, int offset, int length) { if (length % _blockSize > 0) { if (_padding is null) { throw new ArgumentException("data"); } var paddingLength = _blockSize - (length % _blockSize); input = _padding.Pad(input, offset, length, paddingLength); length += paddingLength; offset = 0; } var output = new byte[length]; var writtenBytes = 0; for (var i = 0; i < length / _blockSize; i++) { if (_mode is null) { writtenBytes += EncryptBlock(input, offset + (i * _blockSize), _blockSize, output, i * _blockSize); } else { writtenBytes += _mode.EncryptBlock(input, offset + (i * _blockSize), _blockSize, output, i * _blockSize); } } if (writtenBytes < length) { throw new InvalidOperationException("Encryption error."); } return output; } /// /// Decrypts the specified data. /// /// The data. /// Decrypted data public override byte[] Decrypt(byte[] input) { return Decrypt(input, 0, input.Length); } /// /// Decrypts the specified input. /// /// The input. /// The zero-based offset in at which to begin decrypting. /// The number of bytes to decrypt from . /// /// The decrypted data. /// public override byte[] Decrypt(byte[] input, int offset, int length) { if (length % _blockSize > 0) { if (_padding is null) { throw new ArgumentException("data"); } input = _padding.Pad(_blockSize, input, offset, length); offset = 0; length = input.Length; } var output = new byte[length]; var writtenBytes = 0; for (var i = 0; i < length / _blockSize; i++) { if (_mode is null) { writtenBytes += DecryptBlock(input, offset + (i * _blockSize), _blockSize, output, i * _blockSize); } else { writtenBytes += _mode.DecryptBlock(input, offset + (i * _blockSize), _blockSize, output, i * _blockSize); } } if (writtenBytes < length) { throw new InvalidOperationException("Encryption error."); } return output; } } }