How to hash a password stored in a securestring?

977 views Asked by At

My C# console app actually prompts the user for a password and process the password as a string:

Console.Write("Please enter your password: ");
string password = GetPassword();
var hashedPassword = HashPasswordWithSalt(Encoding.UTF8.GetBytes(password), salt);

Is there a way to modify the code to use a secure password (reducing the risk of having the password be exposed throught a memory dump)?

I would like something like:

Console.Write("Please enter your password: ");
SecureString password = GetSecurePassword();
securePassword = GetSecurePassword();
var hashedPassword = HashPasswordWithSalt(Encoding.UTF8.GetBytes(password), salt);
password.Dispose();

Below a complete sample the compiles under Visual Studio 2015:

using System;
using System.Security;
using System.Security.Cryptography;
using System.Text;

namespace PasswordTest
{
    internal class Program
    {
        public static byte[] GenerateSalt()
        {
            const int saltLength = 32;

            using (var randomNumberGenerator = new RNGCryptoServiceProvider())
            {
                var randomNumber = new byte[saltLength];
                randomNumberGenerator.GetBytes(randomNumber);

                return randomNumber;
            }
        }

        private static byte[] Combine(byte[] first, byte[] second)
        {
            var ret = new byte[first.Length + second.Length];

            Buffer.BlockCopy(first, 0, ret, 0, first.Length);
            Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);

            return ret;
        }

        public static byte[] HashPasswordWithSalt(byte[] toBeHashed, byte[] salt)
        {
            using (var sha256 = SHA256.Create())
            {
                return sha256.ComputeHash(Combine(toBeHashed, salt));
            }
        }

        private static string GetPassword()
        {
            // skip here the code that prompts the password
            // to make simple test that just return a password
            return "mypa55w0rd";
        }

        // Here the code that would normally be used to prompt for a password 
        // and return a SecureString
        public static SecureString GetSecurePassword()
        {
            var password = new SecureString();

            // get the first character of the password
            var nextKey = Console.ReadKey(true);

            while (nextKey.Key != ConsoleKey.Enter)
            {
                if (nextKey.Key == ConsoleKey.Backspace)
                {
                    if (password.Length > 0)
                    {
                        password.RemoveAt(password.Length - 1);

                        // erase the last * as well
                        Console.Write(nextKey.KeyChar);
                        Console.Write(" ");
                        Console.Write(nextKey.KeyChar);
                    }
                }
                else
                {
                    password.AppendChar(nextKey.KeyChar);
                    Console.Write("*");
                }

                nextKey = Console.ReadKey(true);
            }

            Console.WriteLine();

            // lock the password down
            password.MakeReadOnly();
            return password;
        }

        private static void Main(string[] args)
        {
            // Generate the salt
            var salt = GenerateSalt();

            // Hash a password stored in a string variable 
            // Issue: can be exposed through a memory dump
            var password = GetPassword();
            var hashedPassword = HashPasswordWithSalt(Encoding.UTF8.GetBytes(password), salt);

            // How to hash a password stored in a securestring so that the code could become
            // something like:
            /*
            Console.Write("Please enter your password: ");
            SecureString password = GetSecurePassword();
            var hashedPassword = HashPasswordWithSalt(Encoding.UTF8.GetBytes(password), salt);
            password.Dispose();
            */

            Console.WriteLine("Hashed Password = " + Convert.ToBase64String(hashedPassword));
            Console.ReadLine();
        }
    }
}
0

There are 0 answers