< Summary

Information
Class: Renci.SshNet.Security.Cryptography.Ciphers.Arc4Cipher
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\Ciphers\Arc4Cipher.cs
Line coverage
77%
Covered lines: 49
Uncovered lines: 14
Coverable lines: 63
Total lines: 184
Line coverage: 77.7%
Branch coverage
78%
Covered branches: 11
Total branches: 14
Branch coverage: 78.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
get_MinimumSize()100%10%
.ctor(...)50%262.5%
EncryptBlock(...)100%10%
DecryptBlock(...)100%10%
Encrypt(...)100%1100%
Decrypt(...)100%1100%
Decrypt(...)100%1100%
ProcessBytes(...)66.66%677.77%
SetKey(...)100%6100%

File(s)

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

#LineLine coverage
 1using System;
 2
 3namespace Renci.SshNet.Security.Cryptography.Ciphers
 4{
 5    /// <summary>
 6    /// Implements ARCH4 cipher algorithm.
 7    /// </summary>
 8    public sealed class Arc4Cipher : StreamCipher
 9    {
 10#pragma warning disable SA1310 // Field names should not contain underscore
 11        private const int STATE_LENGTH = 256;
 12#pragma warning restore SA1310 // Field names should not contain underscore
 13
 14        /// <summary>
 15        /// Holds the state of the RC4 engine.
 16        /// </summary>
 17        private byte[] _engineState;
 18
 19        private int _x;
 20
 21        private int _y;
 22
 23        /// <summary>
 24        /// Gets the minimum data size.
 25        /// </summary>
 26        /// <value>
 27        /// The minimum data size.
 28        /// </value>
 29        public override byte MinimumSize
 30        {
 031            get { return 0; }
 32        }
 33
 34        /// <summary>
 35        /// Initializes a new instance of the <see cref="Arc4Cipher" /> class.
 36        /// </summary>
 37        /// <param name="key">The key.</param>
 38        /// <param name="dischargeFirstBytes">if set to <see langword="true"/> will disharged first 1536 bytes.</param>
 39        /// <exception cref="ArgumentNullException"><paramref name="key" /> is <see langword="null"/>.</exception>
 40        public Arc4Cipher(byte[] key, bool dischargeFirstBytes)
 1841            : base(key)
 1842        {
 1843            SetKey(key);
 44
 45            // The first 1536 bytes of keystream generated by the cipher MUST be discarded, and the first byte of the
 46            // first encrypted packet MUST be encrypted using the 1537th byte of keystream.
 1847            if (dischargeFirstBytes)
 048            {
 049                _ = Encrypt(new byte[1536]);
 050            }
 1851        }
 52
 53        /// <summary>
 54        /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region 
 55        /// </summary>
 56        /// <param name="inputBuffer">The input data to encrypt.</param>
 57        /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 58        /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 59        /// <param name="outputBuffer">The output to which to write encrypted data.</param>
 60        /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 61        /// <returns>
 62        /// The number of bytes encrypted.
 63        /// </returns>
 64        public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int o
 065        {
 066            return ProcessBytes(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
 067        }
 68
 69        /// <summary>
 70        /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region 
 71        /// </summary>
 72        /// <param name="inputBuffer">The input data to decrypt.</param>
 73        /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 74        /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 75        /// <param name="outputBuffer">The output to which to write decrypted data.</param>
 76        /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 77        /// <returns>
 78        /// The number of bytes decrypted.
 79        /// </returns>
 80        public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int o
 081        {
 082            return ProcessBytes(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
 083        }
 84
 85        /// <summary>
 86        /// Encrypts the specified input.
 87        /// </summary>
 88        /// <param name="input">The input.</param>
 89        /// <param name="offset">The zero-based offset in <paramref name="input"/> at which to begin encrypting.</param>
 90        /// <param name="length">The number of bytes to encrypt from <paramref name="input"/>.</param>
 91        /// <returns>
 92        /// Encrypted data.
 93        /// </returns>
 94        public override byte[] Encrypt(byte[] input, int offset, int length)
 1895        {
 1896            var output = new byte[length];
 1897            _ = ProcessBytes(input, offset, length, output, 0);
 1898            return output;
 1899        }
 100
 101        /// <summary>
 102        /// Decrypts the specified input.
 103        /// </summary>
 104        /// <param name="input">The input.</param>
 105        /// <returns>
 106        /// The decrypted data.
 107        /// </returns>
 108        public override byte[] Decrypt(byte[] input)
 6109        {
 6110            return Decrypt(input, 0, input.Length);
 6111        }
 112
 113        /// <summary>
 114        /// Decrypts the specified input.
 115        /// </summary>
 116        /// <param name="input">The input.</param>
 117        /// <param name="offset">The zero-based offset in <paramref name="input"/> at which to begin decrypting.</param>
 118        /// <param name="length">The number of bytes to decrypt from <paramref name="input"/>.</param>
 119        /// <returns>
 120        /// The decrypted data.
 121        /// </returns>
 122        public override byte[] Decrypt(byte[] input, int offset, int length)
 9123        {
 9124            return Encrypt(input, offset, length);
 9125        }
 126
 127        private int ProcessBytes(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOff
 18128        {
 18129            if ((inputOffset + inputCount) > inputBuffer.Length)
 0130            {
 0131                throw new ArgumentException("input buffer too short");
 132            }
 133
 18134            if ((outputOffset + inputCount) > outputBuffer.Length)
 0135            {
 0136                throw new ArgumentException("output buffer too short");
 137            }
 138
 288139            for (var i = 0; i < inputCount; i++)
 126140            {
 126141                _x = (_x + 1) & 0xff;
 126142                _y = (_engineState[_x] + _y) & 0xff;
 143
 144                // swap
 126145                var tmp = _engineState[_x];
 126146                _engineState[_x] = _engineState[_y];
 126147                _engineState[_y] = tmp;
 148
 149                // xor
 126150                outputBuffer[i + outputOffset] = (byte)(inputBuffer[i + inputOffset] ^ _engineState[(_engineState[_x] + 
 126151            }
 152
 18153            return inputCount;
 18154        }
 155
 156        private void SetKey(byte[] keyBytes)
 18157        {
 18158            _x = 0;
 18159            _y = 0;
 160
 18161            _engineState ??= new byte[STATE_LENGTH];
 162
 163            // reset the state of the engine
 9252164            for (var i = 0; i < STATE_LENGTH; i++)
 4608165            {
 4608166                _engineState[i] = (byte) i;
 4608167            }
 168
 18169            var i1 = 0;
 18170            var i2 = 0;
 171
 9252172            for (var i = 0; i < STATE_LENGTH; i++)
 4608173            {
 4608174                i2 = ((keyBytes[i1] & 0xff) + _engineState[i] + i2) & 0xff;
 175
 176                // do the byte-swap inline
 4608177                var tmp = _engineState[i];
 4608178                _engineState[i] = _engineState[i2];
 4608179                _engineState[i2] = tmp;
 4608180                i1 = (i1 + 1) % keyBytes.Length;
 4608181            }
 18182        }
 183    }
 184}