< Summary

Line coverage
82%
Covered lines: 202
Uncovered lines: 42
Coverable lines: 244
Total lines: 480
Line coverage: 82.7%
Branch coverage
79%
Covered branches: 43
Total branches: 54
Branch coverage: 79.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\Ciphers\AesCipher.BclImpl.cs

#LineLine coverage
 1using System;
 2using System.Security.Cryptography;
 3
 4using Renci.SshNet.Common;
 5
 6namespace Renci.SshNet.Security.Cryptography.Ciphers
 7{
 8    public partial class AesCipher
 9    {
 10        private sealed class BclImpl : BlockCipher, IDisposable
 11        {
 12            private readonly Aes _aes;
 13            private readonly ICryptoTransform _encryptor;
 14            private readonly ICryptoTransform _decryptor;
 15
 16            public BclImpl(
 17                byte[] key,
 18                byte[] iv,
 19                System.Security.Cryptography.CipherMode cipherMode,
 20                PaddingMode paddingMode)
 19721                : base(key, 16, mode: null, padding: null)
 19722            {
 19723                var aes = Aes.Create();
 19724                aes.Key = key;
 25
 19726                if (cipherMode != System.Security.Cryptography.CipherMode.ECB)
 14327                {
 14328                    if (iv is null)
 029                    {
 030                        throw new ArgumentNullException(nameof(iv));
 31                    }
 32
 14333                    aes.IV = iv.Take(16);
 14334                }
 35
 19736                aes.Mode = cipherMode;
 19737                aes.Padding = paddingMode;
 19738                aes.FeedbackSize = 128; // We use CFB128
 19739                _aes = aes;
 19740                _encryptor = aes.CreateEncryptor();
 19741                _decryptor = aes.CreateDecryptor();
 19742            }
 43
 44            public override byte[] Encrypt(byte[] input, int offset, int length)
 15345            {
 15346                if (_aes.Padding != PaddingMode.None)
 047                {
 48                    // If padding has been specified, call TransformFinalBlock to apply
 49                    // the padding and reset the state.
 050                    return _encryptor.TransformFinalBlock(input, offset, length);
 51                }
 52
 53                // Otherwise, (the most important case) assume this instance is
 54                // used for one direction of an SSH connection, whereby the
 55                // encrypted data in all packets are considered a single data
 56                // stream i.e. we do not want to reset the state between calls to Encrypt.
 15357                var output = new byte[length];
 15358                _ = _encryptor.TransformBlock(input, offset, length, output, 0);
 15359                return output;
 15360            }
 61
 62            public override byte[] Decrypt(byte[] input, int offset, int length)
 26363            {
 26364                if (_aes.Padding != PaddingMode.None)
 3265                {
 66                    // If padding has been specified, call TransformFinalBlock to apply
 67                    // the padding and reset the state.
 3268                    return _decryptor.TransformFinalBlock(input, offset, length);
 69                }
 70
 71                // Otherwise, (the most important case) assume this instance is
 72                // used for one direction of an SSH connection, whereby the
 73                // encrypted data in all packets are considered a single data
 74                // stream i.e. we do not want to reset the state between calls to Decrypt.
 23175                var output = new byte[length];
 23176                _ = _decryptor.TransformBlock(input, offset, length, output, 0);
 23177                return output;
 26378            }
 79
 80            public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, i
 081            {
 082                throw new NotImplementedException($"Invalid usage of {nameof(EncryptBlock)}.");
 83            }
 84
 85            public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, i
 086            {
 087                throw new NotImplementedException($"Invalid usage of {nameof(DecryptBlock)}.");
 88            }
 89
 90            private void Dispose(bool disposing)
 1891            {
 1892                if (disposing)
 1893                {
 1894                    _aes.Dispose();
 1895                    _encryptor.Dispose();
 1896                    _decryptor.Dispose();
 1897                }
 1898            }
 99
 100            public void Dispose()
 18101            {
 102                // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 18103                Dispose(disposing: true);
 18104                GC.SuppressFinalize(this);
 18105            }
 106        }
 107    }
 108}

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\Ciphers\AesCipher.BlockImpl.cs

#LineLine coverage
 1using System;
 2using System.Security.Cryptography;
 3
 4namespace Renci.SshNet.Security.Cryptography.Ciphers
 5{
 6    public partial class AesCipher
 7    {
 8        private sealed class BlockImpl : BlockCipher, IDisposable
 9        {
 10            private readonly Aes _aes;
 11            private readonly ICryptoTransform _encryptor;
 12            private readonly ICryptoTransform _decryptor;
 13
 14            public BlockImpl(byte[] key, CipherMode mode, CipherPadding padding)
 7215                : base(key, 16, mode, padding)
 7216            {
 7217                var aes = Aes.Create();
 7218                aes.Key = key;
 7219                aes.Mode = System.Security.Cryptography.CipherMode.ECB;
 7220                aes.Padding = PaddingMode.None;
 7221                _aes = aes;
 7222                _encryptor = aes.CreateEncryptor();
 7223                _decryptor = aes.CreateDecryptor();
 7224            }
 25
 26            public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, i
 16827            {
 16828                return _encryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
 16829            }
 30
 31            public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, i
 032            {
 033                return _decryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
 034            }
 35
 36            private void Dispose(bool disposing)
 037            {
 038                if (disposing)
 039                {
 040                    _aes.Dispose();
 041                    _encryptor.Dispose();
 042                    _decryptor.Dispose();
 043                }
 044            }
 45
 46            public void Dispose()
 047            {
 48                // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 049                Dispose(disposing: true);
 050                GC.SuppressFinalize(this);
 051            }
 52        }
 53    }
 54}

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\Ciphers\AesCipher.cs

#LineLine coverage
 1using System;
 2using System.Security.Cryptography;
 3
 4using Renci.SshNet.Security.Cryptography.Ciphers.Modes;
 5using Renci.SshNet.Security.Cryptography.Ciphers.Paddings;
 6
 7namespace Renci.SshNet.Security.Cryptography.Ciphers
 8{
 9    /// <summary>
 10    /// AES cipher implementation.
 11    /// </summary>
 12    public sealed partial class AesCipher : BlockCipher, IDisposable
 13    {
 14        private readonly BlockCipher _impl;
 15
 16        /// <summary>
 17        /// Initializes a new instance of the <see cref="AesCipher"/> class.
 18        /// </summary>
 19        /// <param name="key">The key.</param>
 20        /// <param name="mode">The mode.</param>
 21        /// <param name="iv">The IV.</param>
 22        /// <param name="pkcs7Padding">Enable PKCS7 padding.</param>
 23        /// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/>.</exception>
 24        /// <exception cref="ArgumentException">Keysize is not valid for this algorithm.</exception>
 25        public AesCipher(byte[] key, byte[] iv, AesCipherMode mode, bool pkcs7Padding = false)
 273426            : base(key, 16, mode: null, padding: null)
 273427        {
 273428            if (mode == AesCipherMode.OFB)
 5429            {
 30                // OFB is not supported on modern .NET
 5431                _impl = new BlockImpl(key, new OfbCipherMode(iv), pkcs7Padding ? new PKCS7Padding() : null);
 5432            }
 33#if !NET6_0_OR_GREATER
 9534            else if (mode == AesCipherMode.CFB)
 1835            {
 36                // CFB not supported on NetStandard 2.1
 1837                _impl = new BlockImpl(key, new CfbCipherMode(iv), pkcs7Padding ? new PKCS7Padding() : null);
 1838            }
 39#endif
 266240            else if (mode == AesCipherMode.CTR)
 246541            {
 42                // CTR not supported by the BCL, use an optimized implementation
 246543                _impl = new CtrImpl(key, iv);
 246544            }
 45            else
 19746            {
 19747                _impl = new BclImpl(
 19748                    key,
 19749                    iv,
 19750                    (System.Security.Cryptography.CipherMode) mode,
 19751                    pkcs7Padding ? PaddingMode.PKCS7 : PaddingMode.None);
 19752            }
 273453        }
 54
 55        /// <inheritdoc/>
 56        public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int o
 057        {
 058            return _impl.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
 059        }
 60
 61        /// <inheritdoc/>
 62        public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int o
 063        {
 064            return _impl.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
 065        }
 66
 67        /// <inheritdoc/>
 68        public override byte[] Encrypt(byte[] input, int offset, int length)
 4868769        {
 4868770            return _impl.Encrypt(input, offset, length);
 4868771        }
 72
 73        /// <inheritdoc/>
 74        public override byte[] Decrypt(byte[] input, int offset, int length)
 9982875        {
 9982876            return _impl.Decrypt(input, offset, length);
 9982877        }
 78
 79        /// <summary>
 80        /// Dispose the instance.
 81        /// </summary>
 82        /// <param name="disposing">Set to True to dispose of resouces.</param>
 83        public void Dispose(bool disposing)
 240884        {
 240885            if (disposing && _impl is IDisposable disposableImpl)
 240886            {
 240887                disposableImpl.Dispose();
 240888            }
 240889        }
 90
 91        /// <inheritdoc/>
 92        public void Dispose()
 240893        {
 94            // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 240895            Dispose(disposing: true);
 240896            GC.SuppressFinalize(this);
 240897        }
 98    }
 99}

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\Ciphers\AesCipher.CtrImpl.cs

#LineLine coverage
 1using System;
 2#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
 3using System.Buffers.Binary;
 4using System.Numerics;
 5#endif
 6using System.Security.Cryptography;
 7
 8namespace Renci.SshNet.Security.Cryptography.Ciphers
 9{
 10    public partial class AesCipher
 11    {
 12        private sealed class CtrImpl : BlockCipher, IDisposable
 13        {
 14            private readonly Aes _aes;
 15
 16            private readonly ICryptoTransform _encryptor;
 17
 18#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
 19            private ulong _ivUpper; // The upper 64 bits of the IV
 20            private ulong _ivLower; // The lower 64 bits of the IV
 21#else
 22            // The same on netfx
 23            private readonly uint[] _packedIV;
 24#endif
 25
 26            public CtrImpl(
 27                byte[] key,
 28                byte[] iv)
 246529                : base(key, 16, mode: null, padding: null)
 246530            {
 246531                var aes = Aes.Create();
 246532                aes.Key = key;
 246533                aes.Mode = System.Security.Cryptography.CipherMode.ECB;
 246534                aes.Padding = PaddingMode.None;
 246535                _aes = aes;
 246536                _encryptor = aes.CreateEncryptor();
 37
 38#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
 243539                _ivLower = BinaryPrimitives.ReadUInt64BigEndian(iv.AsSpan(8));
 243540                _ivUpper = BinaryPrimitives.ReadUInt64BigEndian(iv);
 41#else
 3042                _packedIV = GetPackedIV(iv);
 43#endif
 246544            }
 45
 46            public override byte[] Encrypt(byte[] input, int offset, int length)
 4849847            {
 4849848                return CTREncryptDecrypt(input, offset, length);
 4849849            }
 50
 51            public override byte[] Decrypt(byte[] input, int offset, int length)
 9952952            {
 9952953                return CTREncryptDecrypt(input, offset, length);
 9952954            }
 55
 56            public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, i
 057            {
 058                throw new NotImplementedException($"Invalid usage of {nameof(DecryptBlock)}.");
 59            }
 60
 61            public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, i
 062            {
 063                throw new NotImplementedException($"Invalid usage of {nameof(EncryptBlock)}.");
 64            }
 65
 66            private byte[] CTREncryptDecrypt(byte[] data, int offset, int length)
 14802767            {
 14802768                var count = length / BlockSize;
 14802769                if (length % BlockSize != 0)
 070                {
 071                    count++;
 072                }
 73
 14802774                var buffer = new byte[count * BlockSize];
 14802775                CTRCreateCounterArray(buffer);
 14802776                _ = _encryptor.TransformBlock(buffer, 0, buffer.Length, buffer, 0);
 14802777                ArrayXOR(buffer, data, offset, length);
 78
 79                // adjust output for non-blocksized lengths
 14802780                if (buffer.Length > length)
 081                {
 082                    Array.Resize(ref buffer, length);
 083                }
 84
 14802785                return buffer;
 14802786            }
 87
 88#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
 89
 90             // creates the Counter array filled with incrementing copies of IV
 91            private void CTRCreateCounterArray(byte[] buffer)
 14799592            {
 4645330293                for (var i = 0; i < buffer.Length; i += 16)
 2307865694                {
 2307865695                    BinaryPrimitives.WriteUInt64BigEndian(buffer.AsSpan(i + 8), _ivLower);
 2307865696                    BinaryPrimitives.WriteUInt64BigEndian(buffer.AsSpan(i), _ivUpper);
 97
 2307865698                    _ivLower += 1;
 2307865699                    _ivUpper += (_ivLower == 0) ? 1UL : 0UL;
 23078656100                }
 147995101            }
 102
 103            // XOR 2 arrays using Vector<byte>
 104            private static void ArrayXOR(byte[] buffer, byte[] data, int offset, int length)
 147995105            {
 147995106                var i = 0;
 107
 147995108                var oneVectorFromEnd = length - Vector<byte>.Count;
 23118317109                for (; i <= oneVectorFromEnd; i += Vector<byte>.Count)
 11485161110                {
 11485161111                    var v = new Vector<byte>(buffer, i) ^ new Vector<byte>(data, offset + i);
 11485161112                    v.CopyTo(buffer, i);
 11485161113                }
 114
 3614683115                for (; i < length; i++)
 1733344116                {
 1733344117                    buffer[i] ^= data[offset + i];
 1733344118                }
 147995119            }
 120
 121#else
 122            // creates the Counter array filled with incrementing copies of IV
 123            private void CTRCreateCounterArray(byte[] buffer)
 32124            {
 125                // fill array with IV, increment by 1 for each copy
 32126                var words = buffer.Length / 4;
 32127                var counter = new uint[words];
 432128                for (var i = 0; i < words; i += 4)
 184129                {
 130                    // write IV to buffer (big endian)
 184131                    counter[i] = _packedIV[0];
 184132                    counter[i + 1] = _packedIV[1];
 184133                    counter[i + 2] = _packedIV[2];
 184134                    counter[i + 3] = _packedIV[3];
 135
 136                    // increment IV (little endian)
 184137                    if (_packedIV[3] < 0xFF000000u)
 182138                    {
 182139                        _packedIV[3] += 0x01000000u;
 182140                    }
 141                    else
 2142                    {
 2143                        var j = 3;
 144                        do
 8145                        {
 8146                            _packedIV[j] = SwapEndianness(SwapEndianness(_packedIV[j]) + 1);
 8147                        }
 8148                        while (_packedIV[j] == 0 && --j >= 0);
 2149                    }
 184150                }
 151
 152                // copy uint[] to byte[]
 32153                Buffer.BlockCopy(counter, 0, buffer, 0, buffer.Length);
 32154            }
 155
 156            // XOR 2 arrays using Uint[] and blockcopy
 157            private static void ArrayXOR(byte[] buffer, byte[] data, int offset, int length)
 32158            {
 32159                var words = length / 4;
 32160                if (length % 4 != 0)
 0161                {
 0162                    words++;
 0163                }
 164
 165                // convert original data to words
 32166                var datawords = new uint[words];
 32167                Buffer.BlockCopy(data, offset, datawords, 0, length);
 168
 169                // convert encrypted IV counter to words
 32170                var bufferwords = new uint[words];
 32171                Buffer.BlockCopy(buffer, 0, bufferwords, 0, length);
 172
 173                // XOR encrypted Counter with input data
 1536174                for (var i = 0; i < words; i++)
 736175                {
 736176                    bufferwords[i] = bufferwords[i] ^ datawords[i];
 736177                }
 178
 179                // copy uint[] to byte[]
 32180                Buffer.BlockCopy(bufferwords, 0, buffer, 0, length);
 32181            }
 182
 183            // pack the IV into an array of uint[4]
 184            private static uint[] GetPackedIV(byte[] iv)
 30185            {
 30186                var packedIV = new uint[4];
 30187                packedIV[0] = BitConverter.ToUInt32(iv, 0);
 30188                packedIV[1] = BitConverter.ToUInt32(iv, 4);
 30189                packedIV[2] = BitConverter.ToUInt32(iv, 8);
 30190                packedIV[3] = BitConverter.ToUInt32(iv, 12);
 191
 30192                return packedIV;
 30193            }
 194
 195            private static uint SwapEndianness(uint x)
 16196            {
 16197                x = (x >> 16) | (x << 16);
 16198                return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
 16199            }
 200#endif
 201
 202            private void Dispose(bool disposing)
 2390203            {
 2390204                if (disposing)
 2390205                {
 2390206                    _aes.Dispose();
 2390207                    _encryptor.Dispose();
 2390208                }
 2390209            }
 210
 211            public void Dispose()
 2390212            {
 213                // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 2390214                Dispose(disposing: true);
 2390215                GC.SuppressFinalize(this);
 2390216            }
 217        }
 218    }
 219}

Methods/Properties

.ctor(System.Byte[],System.Byte[],System.Security.Cryptography.CipherMode,System.Security.Cryptography.PaddingMode)
Encrypt(System.Byte[],System.Int32,System.Int32)
Decrypt(System.Byte[],System.Int32,System.Int32)
EncryptBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)
DecryptBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)
Dispose(System.Boolean)
Dispose()
.ctor(System.Byte[],Renci.SshNet.Security.Cryptography.Ciphers.CipherMode,Renci.SshNet.Security.Cryptography.Ciphers.CipherPadding)
EncryptBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)
DecryptBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)
Dispose(System.Boolean)
Dispose()
.ctor(System.Byte[],System.Byte[],Renci.SshNet.Security.Cryptography.Ciphers.AesCipherMode,System.Boolean)
EncryptBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)
DecryptBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)
Encrypt(System.Byte[],System.Int32,System.Int32)
Decrypt(System.Byte[],System.Int32,System.Int32)
Dispose(System.Boolean)
Dispose()
.ctor(System.Byte[],System.Byte[])
Encrypt(System.Byte[],System.Int32,System.Int32)
Decrypt(System.Byte[],System.Int32,System.Int32)
DecryptBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)
EncryptBlock(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)
CTREncryptDecrypt(System.Byte[],System.Int32,System.Int32)
CTRCreateCounterArray(System.Byte[])
ArrayXOR(System.Byte[],System.Byte[],System.Int32,System.Int32)
CTRCreateCounterArray(System.Byte[])
ArrayXOR(System.Byte[],System.Byte[],System.Int32,System.Int32)
GetPackedIV(System.Byte[])
SwapEndianness(System.UInt32)
Dispose(System.Boolean)
Dispose()