< Summary

Information
Class: Renci.SshNet.Security.Cryptography.Ciphers.RsaCipher
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\Ciphers\RsaCipher.cs
Line coverage
91%
Covered lines: 64
Uncovered lines: 6
Coverable lines: 70
Total lines: 158
Line coverage: 91.4%
Branch coverage
72%
Covered branches: 16
Total branches: 22
Branch coverage: 72.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)50%271.42%
Encrypt(...)75%4100%
Decrypt(...)100%1100%
Decrypt(...)62.5%886.66%
Transform(...)100%1100%
Transform(...)87.5%893.54%

File(s)

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

#LineLine coverage
 1using System;
 2using Renci.SshNet.Common;
 3
 4namespace Renci.SshNet.Security.Cryptography.Ciphers
 5{
 6    /// <summary>
 7    /// Implements RSA cipher algorithm.
 8    /// </summary>
 9    public class RsaCipher : AsymmetricCipher
 10    {
 11        private readonly RsaKey _key;
 12
 13        /// <summary>
 14        /// Initializes a new instance of the <see cref="RsaCipher"/> class.
 15        /// </summary>
 16        /// <param name="key">The RSA key.</param>
 276817        public RsaCipher(RsaKey key)
 276818        {
 276819            if (key is null)
 020            {
 021                throw new ArgumentNullException(nameof(key));
 22            }
 23
 276824            _key = key;
 276825        }
 26
 27        /// <summary>
 28        /// Encrypts the specified data.
 29        /// </summary>
 30        /// <param name="input">The data.</param>
 31        /// <param name="offset">The zero-based offset in <paramref name="input"/> at which to begin encrypting.</param>
 32        /// <param name="length">The number of bytes to encrypt from <paramref name="input"/>.</param>
 33        /// <returns>Encrypted data.</returns>
 34        public override byte[] Encrypt(byte[] input, int offset, int length)
 69635        {
 36            // Calculate signature
 69637            var bitLength = _key.Modulus.BitLength;
 38
 69639            var paddedBlock = new byte[(bitLength / 8) + (bitLength % 8 > 0 ? 1 : 0) - 1];
 40
 69641            paddedBlock[0] = 0x01;
 23944042            for (var i = 1; i < paddedBlock.Length - length - 1; i++)
 11902443            {
 11902444                paddedBlock[i] = 0xFF;
 11902445            }
 46
 69647            Buffer.BlockCopy(input, offset, paddedBlock, paddedBlock.Length - length, length);
 48
 69649            return Transform(paddedBlock);
 69650        }
 51
 52        /// <summary>
 53        /// Decrypts the specified data.
 54        /// </summary>
 55        /// <param name="input">The data.</param>
 56        /// <returns>
 57        /// The decrypted data.
 58        /// </returns>
 59        /// <exception cref="NotSupportedException">Only block type 01 or 02 are supported.</exception>
 60        /// <exception cref="NotSupportedException">Thrown when decrypted block type is not supported.</exception>
 61        public override byte[] Decrypt(byte[] input)
 121062        {
 121063            return Decrypt(input, 0, input.Length);
 121064        }
 65
 66        /// <summary>
 67        /// Decrypts the specified input.
 68        /// </summary>
 69        /// <param name="input">The input.</param>
 70        /// <param name="offset">The zero-based offset in <paramref name="input"/> at which to begin decrypting.</param>
 71        /// <param name="length">The number of bytes to decrypt from <paramref name="input"/>.</param>
 72        /// <returns>
 73        /// The decrypted data.
 74        /// </returns>
 75        /// <exception cref="NotSupportedException">Only block type 01 or 02 are supported.</exception>
 76        /// <exception cref="NotSupportedException">Thrown when decrypted block type is not supported.</exception>
 77        public override byte[] Decrypt(byte[] input, int offset, int length)
 121078        {
 121079            var paddedBlock = Transform(input, offset, length);
 80
 121081            if (paddedBlock[0] is not 1 and not 2)
 082            {
 083                throw new NotSupportedException("Only block type 01 or 02 are supported.");
 84            }
 85
 121086            var position = 1;
 87
 36020688            while (position < paddedBlock.Length && paddedBlock[position] != 0)
 35899689            {
 35899690                position++;
 35899691            }
 92
 121093            position++;
 94
 121095            var result = new byte[paddedBlock.Length - position];
 121096            Buffer.BlockCopy(paddedBlock, position, result, 0, result.Length);
 121097            return result;
 121098        }
 99
 100        private byte[] Transform(byte[] data)
 696101        {
 696102            return Transform(data, 0, data.Length);
 696103        }
 104
 105        private byte[] Transform(byte[] data, int offset, int length)
 1906106        {
 1906107            Array.Reverse(data, offset, length);
 108
 1906109            var inputBytes = new byte[length + 1];
 1906110            Buffer.BlockCopy(data, offset, inputBytes, 0, length);
 111
 1906112            var input = new BigInteger(inputBytes);
 113
 114            BigInteger result;
 115
 1906116            var isPrivate = !_key.D.IsZero;
 117
 1906118            if (isPrivate)
 696119            {
 696120                var random = BigInteger.One;
 696121                var max = _key.Modulus - 1;
 696122                var bitLength = _key.Modulus.BitLength;
 123
 696124                if (max < BigInteger.One)
 0125                {
 0126                    throw new SshException("Invalid RSA key.");
 127                }
 128
 1392129                while (random <= BigInteger.One || random >= max)
 696130                {
 696131                    random = BigInteger.Random(bitLength);
 696132                }
 133
 696134                var blindedInput = BigInteger.PositiveMod(BigInteger.ModPow(random, _key.Exponent, _key.Modulus) * input
 135
 136                // mP = ((input Mod p) ^ dP)) Mod p
 696137                var mP = BigInteger.ModPow(blindedInput % _key.P, _key.DP, _key.P);
 138
 139                // mQ = ((input Mod q) ^ dQ)) Mod q
 696140                var mQ = BigInteger.ModPow(blindedInput % _key.Q, _key.DQ, _key.Q);
 141
 696142                var h = BigInteger.PositiveMod((mP - mQ) * _key.InverseQ, _key.P);
 143
 696144                var m = (h * _key.Q) + mQ;
 145
 696146                var rInv = BigInteger.ModInverse(random, _key.Modulus);
 147
 696148                result = BigInteger.PositiveMod(m * rInv, _key.Modulus);
 696149            }
 150            else
 1210151            {
 1210152                result = BigInteger.ModPow(input, _key.Exponent, _key.Modulus);
 1210153            }
 154
 1906155            return result.ToByteArray().Reverse();
 1906156        }
 157    }
 158}