You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
5.3 KiB
C#
167 lines
5.3 KiB
C#
using System;
|
|
using Renci.SshNet.Security.Cryptography.Ciphers;
|
|
|
|
namespace Renci.SshNet.Security.Cryptography
|
|
{
|
|
/// <summary>
|
|
/// Base class for block cipher implementations.
|
|
/// </summary>
|
|
public abstract class BlockCipher : SymmetricCipher
|
|
{
|
|
private readonly CipherMode _mode;
|
|
|
|
private readonly CipherPadding _padding;
|
|
|
|
/// <summary>
|
|
/// Gets the size of the block in bytes.
|
|
/// </summary>
|
|
/// <value>
|
|
/// The size of the block in bytes.
|
|
/// </value>
|
|
private readonly byte _blockSize;
|
|
|
|
/// <summary>
|
|
/// Gets the minimum data size.
|
|
/// </summary>
|
|
/// <value>
|
|
/// The minimum data size.
|
|
/// </value>
|
|
public override byte MinimumSize
|
|
{
|
|
get { return BlockSize; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the size of the block.
|
|
/// </summary>
|
|
/// <value>
|
|
/// The size of the block.
|
|
/// </value>
|
|
public byte BlockSize
|
|
{
|
|
get
|
|
{
|
|
return _blockSize;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="BlockCipher"/> class.
|
|
/// </summary>
|
|
/// <param name="key">The key.</param>
|
|
/// <param name="blockSize">Size of the block.</param>
|
|
/// <param name="mode">Cipher mode.</param>
|
|
/// <param name="padding">Cipher padding.</param>
|
|
/// <exception cref="ArgumentNullException"><paramref name="key"/> is <c>null</c>.</exception>
|
|
protected BlockCipher(byte[] key, byte blockSize, CipherMode mode, CipherPadding padding)
|
|
: base(key)
|
|
{
|
|
_blockSize = blockSize;
|
|
_mode = mode;
|
|
_padding = padding;
|
|
|
|
if (_mode != null)
|
|
_mode.Init(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Encrypts the specified data.
|
|
/// </summary>
|
|
/// <param name="data">The data.</param>
|
|
/// <param name="offset">The zero-based offset in <paramref name="data"/> at which to begin encrypting.</param>
|
|
/// <param name="length">The number of bytes to encrypt from <paramref name="data"/>.</param>
|
|
/// <returns>Encrypted data</returns>
|
|
public override byte[] Encrypt(byte[] data, int offset, int length)
|
|
{
|
|
if (length % _blockSize > 0)
|
|
{
|
|
if (_padding == null)
|
|
{
|
|
throw new ArgumentException("data");
|
|
}
|
|
var paddingLength = _blockSize - (length % _blockSize);
|
|
data = _padding.Pad(data, 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 == null)
|
|
{
|
|
writtenBytes += EncryptBlock(data, offset + (i * _blockSize), _blockSize, output, i * _blockSize);
|
|
}
|
|
else
|
|
{
|
|
writtenBytes += _mode.EncryptBlock(data, offset + (i * _blockSize), _blockSize, output, i * _blockSize);
|
|
}
|
|
}
|
|
|
|
if (writtenBytes < length)
|
|
{
|
|
throw new InvalidOperationException("Encryption error.");
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decrypts the specified data.
|
|
/// </summary>
|
|
/// <param name="data">The data.</param>
|
|
/// <returns>Decrypted data</returns>
|
|
public override byte[] Decrypt(byte[] data)
|
|
{
|
|
return Decrypt(data, 0, data.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decrypts the specified input.
|
|
/// </summary>
|
|
/// <param name="data">The input.</param>
|
|
/// <param name="offset">The zero-based offset in <paramref name="data"/> at which to begin decrypting.</param>
|
|
/// <param name="length">The number of bytes to decrypt from <paramref name="data"/>.</param>
|
|
/// <returns>
|
|
/// The decrypted data.
|
|
/// </returns>
|
|
public override byte[] Decrypt(byte[] data, int offset, int length)
|
|
{
|
|
if (length % _blockSize > 0)
|
|
{
|
|
if (_padding == null)
|
|
{
|
|
throw new ArgumentException("data");
|
|
}
|
|
data = _padding.Pad(_blockSize, data, offset, length);
|
|
offset = 0;
|
|
length = data.Length;
|
|
}
|
|
|
|
var output = new byte[length];
|
|
|
|
var writtenBytes = 0;
|
|
for (var i = 0; i < length / _blockSize; i++)
|
|
{
|
|
if (_mode == null)
|
|
{
|
|
writtenBytes += DecryptBlock(data, offset + (i * _blockSize), _blockSize, output, i * _blockSize);
|
|
}
|
|
else
|
|
{
|
|
writtenBytes += _mode.DecryptBlock(data, offset + (i * _blockSize), _blockSize, output, i * _blockSize);
|
|
}
|
|
}
|
|
|
|
if (writtenBytes < length)
|
|
{
|
|
throw new InvalidOperationException("Encryption error.");
|
|
}
|
|
|
|
return output;
|
|
}
|
|
}
|
|
}
|