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; if (_mode != null) _mode.Init(this); } /// /// Encrypts the specified data. /// /// The data. /// Encrypted data public override byte[] Encrypt(byte[] data) { var output = new byte[data.Length]; if (data.Length % _blockSize > 0) { if (_padding == null) { throw new ArgumentException("data"); } data = _padding.Pad(_blockSize, data); } var writtenBytes = 0; for (int i = 0; i < data.Length / _blockSize; i++) { if (_mode == null) { writtenBytes += EncryptBlock(data, i * _blockSize, _blockSize, output, i * _blockSize); } else { writtenBytes += _mode.EncryptBlock(data, i * _blockSize, _blockSize, output, i * _blockSize); } } if (writtenBytes < data.Length) { throw new InvalidOperationException("Encryption error."); } return output; } /// /// Decrypts the specified data. /// /// The data. /// Decrypted data public override byte[] Decrypt(byte[] data) { if (data.Length % _blockSize > 0) { if (_padding == null) { throw new ArgumentException("data"); } data = _padding.Pad(_blockSize, data); } var output = new byte[data.Length]; var writtenBytes = 0; for (var i = 0; i < data.Length / _blockSize; i++) { if (_mode == null) { writtenBytes += DecryptBlock(data, i * _blockSize, _blockSize, output, i * _blockSize); } else { writtenBytes += _mode.DecryptBlock(data, i * _blockSize, _blockSize, output, i * _blockSize); } } if (writtenBytes < data.Length) { throw new InvalidOperationException("Encryption error."); } return output; } } }