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;
}
}
}