AesCipher
AES cipher implementation.
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography.Ciphers.Modes;
using Renci.SshNet.Security.Cryptography.Ciphers.Paddings;
using System;
using System.Security.Cryptography;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
public sealed class AesCipher : BlockCipher, IDisposable
{
private sealed class BclImpl : BlockCipher, IDisposable
{
private readonly Aes _aes;
private readonly ICryptoTransform _encryptor;
private readonly ICryptoTransform _decryptor;
public BclImpl(byte[] key, byte[] iv, System.Security.Cryptography.CipherMode cipherMode, PaddingMode paddingMode)
: base(key, 16, null, null)
{
Aes aes = Aes.Create();
aes.Key = key;
if (cipherMode != System.Security.Cryptography.CipherMode.ECB) {
if (iv == null)
throw new ArgumentNullException("iv");
aes.IV = iv.Take(16);
}
aes.Mode = cipherMode;
aes.Padding = paddingMode;
aes.FeedbackSize = 128;
_aes = aes;
_encryptor = aes.CreateEncryptor();
_decryptor = aes.CreateDecryptor();
}
public override byte[] Encrypt(byte[] input, int offset, int length)
{
if (_aes.Padding != PaddingMode.None)
return _encryptor.TransformFinalBlock(input, offset, length);
byte[] array = new byte[length];
_encryptor.TransformBlock(input, offset, length, array, 0);
return array;
}
public override byte[] Decrypt(byte[] input, int offset, int length)
{
if (_aes.Padding != PaddingMode.None)
return _decryptor.TransformFinalBlock(input, offset, length);
byte[] array = new byte[length];
_decryptor.TransformBlock(input, offset, length, array, 0);
return array;
}
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
throw new NotImplementedException("Invalid usage of EncryptBlock.");
}
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
throw new NotImplementedException("Invalid usage of DecryptBlock.");
}
private void Dispose(bool disposing)
{
if (disposing) {
_aes.Dispose();
_encryptor.Dispose();
_decryptor.Dispose();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
private sealed class BlockImpl : BlockCipher, IDisposable
{
private readonly Aes _aes;
private readonly ICryptoTransform _encryptor;
private readonly ICryptoTransform _decryptor;
public BlockImpl(byte[] key, CipherMode mode, CipherPadding padding)
: base(key, 16, mode, padding)
{
Aes aes = Aes.Create();
aes.Key = key;
aes.Mode = System.Security.Cryptography.CipherMode.ECB;
aes.Padding = PaddingMode.None;
_aes = aes;
_encryptor = aes.CreateEncryptor();
_decryptor = aes.CreateDecryptor();
}
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
return _encryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
return _decryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
private void Dispose(bool disposing)
{
if (disposing) {
_aes.Dispose();
_encryptor.Dispose();
_decryptor.Dispose();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
private sealed class CtrImpl : BlockCipher, IDisposable
{
private readonly Aes _aes;
private readonly ICryptoTransform _encryptor;
private readonly uint[] _packedIV;
public CtrImpl(byte[] key, byte[] iv)
: base(key, 16, null, null)
{
Aes aes = Aes.Create();
aes.Key = key;
aes.Mode = System.Security.Cryptography.CipherMode.ECB;
aes.Padding = PaddingMode.None;
_aes = aes;
_encryptor = aes.CreateEncryptor();
_packedIV = GetPackedIV(iv);
}
public override byte[] Encrypt(byte[] input, int offset, int length)
{
return CTREncryptDecrypt(input, offset, length);
}
public override byte[] Decrypt(byte[] input, int offset, int length)
{
return CTREncryptDecrypt(input, offset, length);
}
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
throw new NotImplementedException("Invalid usage of DecryptBlock.");
}
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
throw new NotImplementedException("Invalid usage of EncryptBlock.");
}
private byte[] CTREncryptDecrypt(byte[] data, int offset, int length)
{
int num = length / (int)base.BlockSize;
if (length % (int)base.BlockSize != 0)
num++;
byte[] array = new byte[num * base.BlockSize];
CTRCreateCounterArray(array);
_encryptor.TransformBlock(array, 0, array.Length, array, 0);
ArrayXOR(array, data, offset, length);
if (array.Length > length)
Array.Resize(ref array, length);
return array;
}
private void CTRCreateCounterArray(byte[] buffer)
{
int num = buffer.Length / 4;
uint[] array = new uint[num];
for (int i = 0; i < num; i += 4) {
array[i] = _packedIV[0];
array[i + 1] = _packedIV[1];
array[i + 2] = _packedIV[2];
array[i + 3] = _packedIV[3];
if (_packedIV[3] < 4278190080)
_packedIV[3] += 16777216;
else {
int num2 = 3;
do {
_packedIV[num2] = SwapEndianness(SwapEndianness(_packedIV[num2]) + 1);
} while (_packedIV[num2] == 0 && --num2 >= 0);
}
}
Buffer.BlockCopy(array, 0, buffer, 0, buffer.Length);
}
private static void ArrayXOR(byte[] buffer, byte[] data, int offset, int length)
{
int num = length / 4;
if (length % 4 != 0)
num++;
uint[] array = new uint[num];
Buffer.BlockCopy(data, offset, array, 0, length);
uint[] array2 = new uint[num];
Buffer.BlockCopy(buffer, 0, array2, 0, length);
for (int i = 0; i < num; i++) {
array2[i] ^= array[i];
}
Buffer.BlockCopy(array2, 0, buffer, 0, length);
}
private static uint[] GetPackedIV(byte[] iv)
{
return new uint[4] {
BitConverter.ToUInt32(iv, 0),
BitConverter.ToUInt32(iv, 4),
BitConverter.ToUInt32(iv, 8),
BitConverter.ToUInt32(iv, 12)
};
}
private static uint SwapEndianness(uint x)
{
x = ((x >> 16) | (x << 16));
return ((uint)((int)x & -16711936) >> 8) | ((x & 16711935) << 8);
}
private void Dispose(bool disposing)
{
if (disposing) {
_aes.Dispose();
_encryptor.Dispose();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
private readonly BlockCipher _impl;
public AesCipher(byte[] key, byte[] iv, AesCipherMode mode, bool pkcs7Padding = false)
: base(key, 16, null, null)
{
switch (mode) {
case AesCipherMode.OFB:
_impl = new BlockImpl(key, new OfbCipherMode(iv), pkcs7Padding ? new PKCS7Padding() : null);
break;
case AesCipherMode.CFB:
_impl = new BlockImpl(key, new CfbCipherMode(iv), pkcs7Padding ? new PKCS7Padding() : null);
break;
case AesCipherMode.CTR:
_impl = new CtrImpl(key, iv);
break;
default:
_impl = new BclImpl(key, iv, (System.Security.Cryptography.CipherMode)mode, (!pkcs7Padding) ? PaddingMode.None : PaddingMode.PKCS7);
break;
}
}
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
return _impl.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
return _impl.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
public override byte[] Encrypt(byte[] input, int offset, int length)
{
return _impl.Encrypt(input, offset, length);
}
public override byte[] Decrypt(byte[] input, int offset, int length)
{
return _impl.Decrypt(input, offset, length);
}
public void Dispose(bool disposing)
{
if (disposing)
(_impl as IDisposable)?.Dispose();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}