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

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.Buffers.Binary; using System.Numerics; 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 ulong _ivUpper; private ulong _ivLower; 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(); _ivLower = BinaryPrimitives.ReadUInt64BigEndian(iv.AsSpan(8)); _ivUpper = BinaryPrimitives.ReadUInt64BigEndian(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) { for (int i = 0; i < buffer.Length; i += 16) { BinaryPrimitives.WriteUInt64BigEndian(buffer.AsSpan(i + 8), _ivLower); BinaryPrimitives.WriteUInt64BigEndian(buffer.AsSpan(i), _ivUpper); _ivLower++; _ivUpper += (ulong)((_ivLower == 0) ? 1 : 0); } } private static void ArrayXOR(byte[] buffer, byte[] data, int offset, int length) { int i = 0; for (int num = length - Vector<byte>.Count; i <= num; i += Vector<byte>.Count) { (new Vector<byte>(buffer, i) ^ new Vector<byte>(data, offset + i)).CopyTo(buffer, i); } for (; i < length; i++) { buffer[i] ^= data[offset + i]; } } 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); } } }