|  | @@ -22,53 +22,12 @@ using System.Text;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace Renci.SshNet.Security.Cryptography
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    /// <summary>BCrypt implementation.</summary>
 | 
	
		
			
				|  |  | -    /// <remarks>
 | 
	
		
			
				|  |  | -    ///  <para>
 | 
	
		
			
				|  |  | -    ///        BCrypt implements OpenBSD-style Blowfish password hashing using the scheme described in
 | 
	
		
			
				|  |  | -    ///        <a href="http://www.usenix.org/event/usenix99/provos/provos_html/index.html">"A Future-
 | 
	
		
			
				|  |  | -    ///        Adaptable Password Scheme"</a> by Niels Provos and David Mazieres.
 | 
	
		
			
				|  |  | -    ///  </para>
 | 
	
		
			
				|  |  | -    ///  <para>
 | 
	
		
			
				|  |  | -    ///        This password hashing system tries to thwart off-line password cracking using a
 | 
	
		
			
				|  |  | -    ///        computationally-intensive hashing algorithm, based on Bruce Schneier's Blowfish cipher.
 | 
	
		
			
				|  |  | -    ///        The work factor of the algorithm is parameterised, so it can be increased as computers
 | 
	
		
			
				|  |  | -    ///        get faster.
 | 
	
		
			
				|  |  | -    ///  </para>
 | 
	
		
			
				|  |  | -    ///  <para>
 | 
	
		
			
				|  |  | -    ///        Usage is really simple. To hash a password for the first time, call the <see
 | 
	
		
			
				|  |  | -    ///        cref="HashPassword(string)"/> method with a random salt, like this:
 | 
	
		
			
				|  |  | -    ///  </para>
 | 
	
		
			
				|  |  | -    ///  <code>string pw_hash = BCrypt.HashPassword(plain_password);</code>
 | 
	
		
			
				|  |  | -    ///  <para>
 | 
	
		
			
				|  |  | -    ///        To check whether a plaintext password matches one that has been hashed previously,
 | 
	
		
			
				|  |  | -    ///        use the <see cref="Verify"/> method:
 | 
	
		
			
				|  |  | -    ///  </para>
 | 
	
		
			
				|  |  | -    ///  <code>
 | 
	
		
			
				|  |  | -    ///     if (BCrypt.Verify(candidate_password, stored_hash))
 | 
	
		
			
				|  |  | -    ///         Console.WriteLine("It matches");
 | 
	
		
			
				|  |  | -    ///     else
 | 
	
		
			
				|  |  | -    ///         Console.WriteLine("It does not match");
 | 
	
		
			
				|  |  | -    ///   </code>
 | 
	
		
			
				|  |  | -    ///   <para>
 | 
	
		
			
				|  |  | -    ///         The <see cref="GenerateSalt()"/> method takes an optional parameter (workFactor) that
 | 
	
		
			
				|  |  | -    ///         determines the computational complexity of the hashing:
 | 
	
		
			
				|  |  | -    ///   </para>
 | 
	
		
			
				|  |  | -    ///   <code>
 | 
	
		
			
				|  |  | -    ///     string strong_salt = BCrypt.GenerateSalt(10);
 | 
	
		
			
				|  |  | -    ///     string stronger_salt = BCrypt.GenerateSalt(12);
 | 
	
		
			
				|  |  | -    ///   </code>
 | 
	
		
			
				|  |  | -    ///   <para>
 | 
	
		
			
				|  |  | -    ///         The amount of work increases exponentially (2^workFactor), so each increment is twice
 | 
	
		
			
				|  |  | -    ///         as much work. The default workFactor is 10, and the valid range is 4 to 31.
 | 
	
		
			
				|  |  | -    ///   </para>
 | 
	
		
			
				|  |  | -    /// </remarks>
 | 
	
		
			
				|  |  | +    /// <summary>
 | 
	
		
			
				|  |  | +    /// BCrypt Pbkdf implementation.
 | 
	
		
			
				|  |  | +    /// This was originally based on https://github.com/hierynomus/sshj/blob/master/src/main/java/com/hierynomus/sshj/userauth/keyprovider/bcrypt/BCrypt.java .
 | 
	
		
			
				|  |  | +    /// </summary>
 | 
	
		
			
				|  |  |      internal sealed class BCrypt
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  | -        // BCrypt parameters
 | 
	
		
			
				|  |  | -        private const int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
 | 
	
		
			
				|  |  | -        private const int BCRYPT_SALT_LEN = 16;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          // Blowfish parameters
 | 
	
		
			
				|  |  |          private const int BLOWFISH_NUM_ROUNDS = 16;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -346,299 +305,10 @@ namespace Renci.SshNet.Security.Cryptography
 | 
	
		
			
				|  |  |              0x66697368, 0x53776174, 0x44796e61, 0x6d697465,
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        // bcrypt IV: "OrpheanBeholderScryDoubt"
 | 
	
		
			
				|  |  | -        private static readonly uint[] _BfCryptCiphertext = {
 | 
	
		
			
				|  |  | -            0x4f727068, 0x65616e42, 0x65686f6c,
 | 
	
		
			
				|  |  | -            0x64657253, 0x63727944, 0x6f756274
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        // Table for Base64 encoding
 | 
	
		
			
				|  |  | -        private static readonly char[] _Base64Code = {
 | 
	
		
			
				|  |  | -            '.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
 | 
	
		
			
				|  |  | -            'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
 | 
	
		
			
				|  |  | -            'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
 | 
	
		
			
				|  |  | -            'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
 | 
	
		
			
				|  |  | -            'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
 | 
	
		
			
				|  |  | -            '6', '7', '8', '9'
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        // Table for Base64 decoding
 | 
	
		
			
				|  |  | -        private static readonly int[] _Index64 = {
 | 
	
		
			
				|  |  | -            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
	
		
			
				|  |  | -            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
	
		
			
				|  |  | -            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
	
		
			
				|  |  | -            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
	
		
			
				|  |  | -            -1, -1, -1, -1, -1, -1, 0, 1, 54, 55,
 | 
	
		
			
				|  |  | -            56, 57, 58, 59, 60, 61, 62, 63, -1, -1,
 | 
	
		
			
				|  |  | -            -1, -1, -1, -1, -1, 2, 3, 4, 5, 6,
 | 
	
		
			
				|  |  | -            7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
 | 
	
		
			
				|  |  | -            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
 | 
	
		
			
				|  |  | -            -1, -1, -1, -1, -1, -1, 28, 29, 30,
 | 
	
		
			
				|  |  | -            31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
 | 
	
		
			
				|  |  | -            41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
 | 
	
		
			
				|  |  | -            51, 52, 53, -1, -1, -1, -1, -1
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          // Expanded Blowfish key
 | 
	
		
			
				|  |  |          private uint[] _P;
 | 
	
		
			
				|  |  |          private uint[] _S;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        ///  Hash a string using the OpenBSD bcrypt scheme and a salt generated by <see
 | 
	
		
			
				|  |  | -        ///  cref="BCrypt.GenerateSalt()"/>.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <remarks>Just an alias for HashPassword.</remarks>
 | 
	
		
			
				|  |  | -        /// <param name="source">The string to hash.</param>
 | 
	
		
			
				|  |  | -        /// <returns>The hashed string.</returns>
 | 
	
		
			
				|  |  | -        public static string HashString(string source)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            return HashPassword(source);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        ///  Hash a string using the OpenBSD bcrypt scheme and a salt generated by <see
 | 
	
		
			
				|  |  | -        ///  cref="BCrypt.GenerateSalt()"/>.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <remarks>Just an alias for HashPassword.</remarks>
 | 
	
		
			
				|  |  | -        /// <param name="source">  The string to hash.</param>
 | 
	
		
			
				|  |  | -        /// <param name="workFactor">The log2 of the number of rounds of hashing to apply - the work
 | 
	
		
			
				|  |  | -        ///                          factor therefore increases as 2^workFactor.</param>
 | 
	
		
			
				|  |  | -        /// <returns>The hashed string.</returns>
 | 
	
		
			
				|  |  | -        public static string HashString(string source, int workFactor)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            return HashPassword(source, GenerateSalt(workFactor));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        ///  Hash a password using the OpenBSD bcrypt scheme and a salt generated by <see
 | 
	
		
			
				|  |  | -        ///  cref="BCrypt.GenerateSalt()"/>.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="input">The password to hash.</param>
 | 
	
		
			
				|  |  | -        /// <returns>The hashed password.</returns>
 | 
	
		
			
				|  |  | -        public static string HashPassword(string input)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            return HashPassword(input, GenerateSalt());
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        ///  Hash a password using the OpenBSD bcrypt scheme and a salt generated by <see
 | 
	
		
			
				|  |  | -        ///  cref="BCrypt.GenerateSalt(int)"/> using the given <paramref name="workFactor"/>.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="input">     The password to hash.</param>
 | 
	
		
			
				|  |  | -        /// <param name="workFactor">The log2 of the number of rounds of hashing to apply - the work
 | 
	
		
			
				|  |  | -        ///                          factor therefore increases as 2^workFactor.</param>
 | 
	
		
			
				|  |  | -        /// <returns>The hashed password.</returns>
 | 
	
		
			
				|  |  | -        public static string HashPassword(string input, int workFactor)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            return HashPassword(input, GenerateSalt(workFactor));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>Hash a password using the OpenBSD bcrypt scheme.</summary>
 | 
	
		
			
				|  |  | -        /// <exception cref="ArgumentException">Thrown when one or more arguments have unsupported or
 | 
	
		
			
				|  |  | -        ///                                     illegal values.</exception>
 | 
	
		
			
				|  |  | -        /// <param name="input">The password to hash.</param>
 | 
	
		
			
				|  |  | -        /// <param name="salt">    the salt to hash with (perhaps generated using BCrypt.gensalt).</param>
 | 
	
		
			
				|  |  | -        /// <returns>The hashed password</returns>
 | 
	
		
			
				|  |  | -        public static string HashPassword(string input, string salt)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            if (input == null)
 | 
	
		
			
				|  |  | -                throw new ArgumentNullException("input");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if (string.IsNullOrEmpty(salt))
 | 
	
		
			
				|  |  | -                throw new ArgumentException("Invalid salt", "salt");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // Determinthe starting offset and validate the salt
 | 
	
		
			
				|  |  | -            int startingOffset;
 | 
	
		
			
				|  |  | -            char minor = (char)0;
 | 
	
		
			
				|  |  | -            if (salt[0] != '$' || salt[1] != '2')
 | 
	
		
			
				|  |  | -                throw new SaltParseException("Invalid salt version");
 | 
	
		
			
				|  |  | -            if (salt[2] == '$')
 | 
	
		
			
				|  |  | -                startingOffset = 3;
 | 
	
		
			
				|  |  | -            else
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                minor = salt[2];
 | 
	
		
			
				|  |  | -                if (minor != 'a' || salt[3] != '$')
 | 
	
		
			
				|  |  | -                    throw new SaltParseException("Invalid salt revision");
 | 
	
		
			
				|  |  | -                startingOffset = 4;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // Extract number of rounds
 | 
	
		
			
				|  |  | -            if (salt[startingOffset + 2] > '$')
 | 
	
		
			
				|  |  | -                throw new SaltParseException("Missing salt rounds");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // Extract details from salt
 | 
	
		
			
				|  |  | -            int logRounds = Convert.ToInt32(salt.Substring(startingOffset, 2));
 | 
	
		
			
				|  |  | -            string extractedSalt = salt.Substring(startingOffset + 3, 22);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            byte[] inputBytes = Encoding.UTF8.GetBytes((input + (minor >= 'a' ? "\0" : "")));
 | 
	
		
			
				|  |  | -            byte[] saltBytes = DecodeBase64(extractedSalt, BCRYPT_SALT_LEN);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            BCrypt bCrypt = new BCrypt();
 | 
	
		
			
				|  |  | -            byte[] hashed = bCrypt.CryptRaw(inputBytes, saltBytes, logRounds);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // Generate result string
 | 
	
		
			
				|  |  | -            StringBuilder result = new StringBuilder();
 | 
	
		
			
				|  |  | -            result.Append("$2");
 | 
	
		
			
				|  |  | -            if (minor >= 'a')
 | 
	
		
			
				|  |  | -                result.Append(minor);
 | 
	
		
			
				|  |  | -            result.AppendFormat("${0:00}$", logRounds);
 | 
	
		
			
				|  |  | -            result.Append(EncodeBase64(saltBytes, saltBytes.Length));
 | 
	
		
			
				|  |  | -            result.Append(EncodeBase64(hashed, (_BfCryptCiphertext.Length * 4) - 1));
 | 
	
		
			
				|  |  | -            return result.ToString();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        ///  Generate a salt for use with the <see cref="BCrypt.HashPassword(string,string)"/> method.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="workFactor">The log2 of the number of rounds of hashing to apply - the work
 | 
	
		
			
				|  |  | -        ///                          factor therefore increases as 2**workFactor.</param>
 | 
	
		
			
				|  |  | -        /// <returns>A base64 encoded salt value.</returns>
 | 
	
		
			
				|  |  | -        public static string GenerateSalt(int workFactor)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            if (workFactor < 4 || workFactor > 31)
 | 
	
		
			
				|  |  | -                throw new ArgumentOutOfRangeException("workFactor", "The work factor must be between 4 and 31 (inclusive)");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            byte[] rnd = new byte[BCRYPT_SALT_LEN];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            RandomNumberGenerator rng = RandomNumberGenerator.Create();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            rng.GetBytes(rnd);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            StringBuilder rs = new StringBuilder();
 | 
	
		
			
				|  |  | -            rs.AppendFormat("$2a${0:00}$", workFactor);
 | 
	
		
			
				|  |  | -            rs.Append(EncodeBase64(rnd, rnd.Length));
 | 
	
		
			
				|  |  | -            return rs.ToString();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        ///  Generate a salt for use with the <see cref="BCrypt.HashPassword(string,string)"/> method
 | 
	
		
			
				|  |  | -        ///  selecting a reasonable default for the number of hashing rounds to apply.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <returns>A base64 encoded salt value.</returns>
 | 
	
		
			
				|  |  | -        public static string GenerateSalt()
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            return GenerateSalt(GENSALT_DEFAULT_LOG2_ROUNDS);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        ///  Verifies that the hash of the given <paramref name="text"/> matches the provided
 | 
	
		
			
				|  |  | -        ///  <paramref name="hash"/>
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="text">The text to verify.</param>
 | 
	
		
			
				|  |  | -        /// <param name="hash"> The previously-hashed password.</param>
 | 
	
		
			
				|  |  | -        /// <returns>true if the passwords match, false otherwise.</returns>
 | 
	
		
			
				|  |  | -        public static bool Verify(string text, string hash)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            return hash == HashPassword(text, hash);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        ///  Encode a byte array using bcrypt's slightly-modified base64 encoding scheme. Note that this
 | 
	
		
			
				|  |  | -        ///  is *not* compatible with the standard MIME-base64 encoding.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <exception cref="ArgumentException">Thrown when one or more arguments have unsupported or
 | 
	
		
			
				|  |  | -        ///                                     illegal values.</exception>
 | 
	
		
			
				|  |  | -        /// <param name="byteArray">The byte array to encode.</param>
 | 
	
		
			
				|  |  | -        /// <param name="length">   The number of bytes to encode.</param>
 | 
	
		
			
				|  |  | -        /// <returns>Base64-encoded string.</returns>
 | 
	
		
			
				|  |  | -        private static string EncodeBase64(byte[] byteArray, int length)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            if (length <= 0 || length > byteArray.Length)
 | 
	
		
			
				|  |  | -                throw new ArgumentException("Invalid length", "length");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            int off = 0;
 | 
	
		
			
				|  |  | -            StringBuilder rs = new StringBuilder();
 | 
	
		
			
				|  |  | -            while (off < length)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                int c1 = byteArray[off++] & 0xff;
 | 
	
		
			
				|  |  | -                rs.Append(_Base64Code[(c1 >> 2) & 0x3f]);
 | 
	
		
			
				|  |  | -                c1 = (c1 & 0x03) << 4;
 | 
	
		
			
				|  |  | -                if (off >= length)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    rs.Append(_Base64Code[c1 & 0x3f]);
 | 
	
		
			
				|  |  | -                    break;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                int c2 = byteArray[off++] & 0xff;
 | 
	
		
			
				|  |  | -                c1 |= (c2 >> 4) & 0x0f;
 | 
	
		
			
				|  |  | -                rs.Append(_Base64Code[c1 & 0x3f]);
 | 
	
		
			
				|  |  | -                c1 = (c2 & 0x0f) << 2;
 | 
	
		
			
				|  |  | -                if (off >= length)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    rs.Append(_Base64Code[c1 & 0x3f]);
 | 
	
		
			
				|  |  | -                    break;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                c2 = byteArray[off++] & 0xff;
 | 
	
		
			
				|  |  | -                c1 |= (c2 >> 6) & 0x03;
 | 
	
		
			
				|  |  | -                rs.Append(_Base64Code[c1 & 0x3f]);
 | 
	
		
			
				|  |  | -                rs.Append(_Base64Code[c2 & 0x3f]);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            return rs.ToString();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        ///  Decode a string encoded using bcrypt's base64 scheme to a byte array. Note that this is *not*
 | 
	
		
			
				|  |  | -        ///  compatible with the standard MIME-base64 encoding.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <exception cref="ArgumentException">Thrown when one or more arguments have unsupported or
 | 
	
		
			
				|  |  | -        ///                                     illegal values.</exception>
 | 
	
		
			
				|  |  | -        /// <param name="encodedstring">The string to decode.</param>
 | 
	
		
			
				|  |  | -        /// <param name="maximumBytes"> The maximum bytes to decode.</param>
 | 
	
		
			
				|  |  | -        /// <returns>The decoded byte array.</returns>
 | 
	
		
			
				|  |  | -        private static byte[] DecodeBase64(string encodedstring, int maximumBytes)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            int position = 0,
 | 
	
		
			
				|  |  | -                sourceLength = encodedstring.Length,
 | 
	
		
			
				|  |  | -                outputLength = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if (maximumBytes <= 0)
 | 
	
		
			
				|  |  | -                throw new ArgumentException("Invalid maximum bytes value", "maximumBytes");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // TODO: update to use a List<byte> - it's only ever 16 bytes, so it's not a big deal
 | 
	
		
			
				|  |  | -            StringBuilder rs = new StringBuilder();
 | 
	
		
			
				|  |  | -            while (position < sourceLength - 1 && outputLength < maximumBytes)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                int c1 = Char64(encodedstring[position++]);
 | 
	
		
			
				|  |  | -                int c2 = Char64(encodedstring[position++]);
 | 
	
		
			
				|  |  | -                if (c1 == -1 || c2 == -1)
 | 
	
		
			
				|  |  | -                    break;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                rs.Append((char)((c1 << 2) | ((c2 & 0x30) >> 4)));
 | 
	
		
			
				|  |  | -                if (++outputLength >= maximumBytes || position >= sourceLength)
 | 
	
		
			
				|  |  | -                    break;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                int c3 = Char64(encodedstring[position++]);
 | 
	
		
			
				|  |  | -                if (c3 == -1)
 | 
	
		
			
				|  |  | -                    break;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                rs.Append((char)(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2)));
 | 
	
		
			
				|  |  | -                if (++outputLength >= maximumBytes || position >= sourceLength)
 | 
	
		
			
				|  |  | -                    break;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                int c4 = Char64(encodedstring[position++]);
 | 
	
		
			
				|  |  | -                rs.Append((char)(((c3 & 0x03) << 6) | c4));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                ++outputLength;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            byte[] ret = new byte[outputLength];
 | 
	
		
			
				|  |  | -            for (position = 0; position < outputLength; position++)
 | 
	
		
			
				|  |  | -                ret[position] = (byte)rs[position];
 | 
	
		
			
				|  |  | -            return ret;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        ///  Look up the 3 bits base64-encoded by the specified character, range-checking against
 | 
	
		
			
				|  |  | -        ///  conversion table.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="character">The base64-encoded value.</param>
 | 
	
		
			
				|  |  | -        /// <returns>The decoded value of x.</returns>
 | 
	
		
			
				|  |  | -        private static int Char64(char character)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            if (character < 0 || character > _Index64.Length)
 | 
	
		
			
				|  |  | -                return -1;
 | 
	
		
			
				|  |  | -            return _Index64[character];
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          /// <summary>Blowfish encipher a single 64-bit block encoded as two 32-bit halves.</summary>
 | 
	
		
			
				|  |  |          /// <param name="blockArray">An array containing the two 32-bit half blocks.</param>
 | 
	
		
			
				|  |  |          /// <param name="offset">    The position in the array of the blocks.</param>
 | 
	
	
		
			
				|  | @@ -759,59 +429,11 @@ namespace Renci.SshNet.Security.Cryptography
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        /// <summary>Perform the central hashing step in the bcrypt scheme.</summary>
 | 
	
		
			
				|  |  | -        /// <exception cref="ArgumentException">Thrown when one or more arguments have unsupported or
 | 
	
		
			
				|  |  | -        ///                                     illegal values.</exception>
 | 
	
		
			
				|  |  | -        /// <param name="inputBytes">The input byte array to hash.</param>
 | 
	
		
			
				|  |  | -        /// <param name="saltBytes"> The salt byte array to hash with.</param>
 | 
	
		
			
				|  |  | -        /// <param name="logRounds"> The binary logarithm of the number of rounds of hashing to apply.</param>
 | 
	
		
			
				|  |  | -        /// <returns>A byte array containing the hashed result.</returns>
 | 
	
		
			
				|  |  | -        private byte[] CryptRaw(byte[] inputBytes, byte[] saltBytes, int logRounds)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            uint[] cdata = new uint[_BfCryptCiphertext.Length];
 | 
	
		
			
				|  |  | -            Array.Copy(_BfCryptCiphertext, cdata, _BfCryptCiphertext.Length);
 | 
	
		
			
				|  |  | -            int clen = cdata.Length;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if (logRounds < 4 || logRounds > 31)
 | 
	
		
			
				|  |  | -                throw new ArgumentException("Bad number of rounds", "logRounds");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if (saltBytes.Length != BCRYPT_SALT_LEN)
 | 
	
		
			
				|  |  | -                throw new ArgumentException("Bad salt Length", "saltBytes");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            uint rounds = 1u << logRounds;
 | 
	
		
			
				|  |  | -            Debug.Assert(rounds > 0, "Rounds must be > 0"); // We overflowed rounds at 31 - added safety check
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            InitializeKey();
 | 
	
		
			
				|  |  | -            EKSKey(saltBytes, inputBytes);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            for (int i = 0; i < rounds; i++)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                Key(inputBytes);
 | 
	
		
			
				|  |  | -                Key(saltBytes);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            for (int i = 0; i < 64; i++)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                for (int j = 0; j < (clen >> 1); j++)
 | 
	
		
			
				|  |  | -                    Encipher(cdata, j << 1);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            byte[] ret = new byte[clen * 4];
 | 
	
		
			
				|  |  | -            for (int i = 0, j = 0; i < clen; i++)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                ret[j++] = (byte)((cdata[i] >> 24) & 0xff);
 | 
	
		
			
				|  |  | -                ret[j++] = (byte)((cdata[i] >> 16) & 0xff);
 | 
	
		
			
				|  |  | -                ret[j++] = (byte)((cdata[i] >> 8) & 0xff);
 | 
	
		
			
				|  |  | -                ret[j++] = (byte)(cdata[i] & 0xff);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            return ret;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          /**
 | 
	
		
			
				|  |  |           * Compatibility with new OpenBSD function.
 | 
	
		
			
				|  |  |           * Ported from SSHJ library (https://github.com/hierynomus/sshj)
 | 
	
		
			
				|  |  |           */
 | 
	
		
			
				|  |  | -        public void Hash(byte[] hpass, byte[] hsalt, byte[] output)
 | 
	
		
			
				|  |  | +        private void Hash(byte[] hpass, byte[] hsalt, byte[] output)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              InitializeKey();
 | 
	
		
			
				|  |  |              EKSKey(hsalt, hpass);
 | 
	
	
		
			
				|  | @@ -924,29 +546,5 @@ namespace Renci.SshNet.Security.Cryptography
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              return result;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>Exception for signalling parse errors. </summary>
 | 
	
		
			
				|  |  | -        public class SaltParseException : Exception
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            /// <summary>Default constructor. </summary>
 | 
	
		
			
				|  |  | -            public SaltParseException()
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            /// <summary>Initializes a new instance of <see cref="SaltParseException"/>.</summary>
 | 
	
		
			
				|  |  | -            /// <param name="message">The message.</param>
 | 
	
		
			
				|  |  | -            public SaltParseException(string message)
 | 
	
		
			
				|  |  | -                : base(message)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            /// <summary>Initializes a new instance of <see cref="SaltParseException"/>.</summary>
 | 
	
		
			
				|  |  | -            /// <param name="message">       The message.</param>
 | 
	
		
			
				|  |  | -            /// <param name="innerException">The inner exception.</param>
 | 
	
		
			
				|  |  | -            public SaltParseException(string message, Exception innerException)
 | 
	
		
			
				|  |  | -                : base(message, innerException)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |