<PackageReference Include="SSH.NET" Version="2023.0.1" />

AesCipher

public sealed class AesCipher : BlockCipher, IDisposable
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); } } }