C# Salting and Hashing

Sometimes it is necessary to store passwords in a database, however, for security reasons, it isn't a good idea to store them in their plain text, original form. One solution is to use salting and hashing.

Hashing is the process of transforming a string of characters into another string of letters, numbers and non-alphanumeric characters that is unique to the original string. The problem with hashing on its own is that two user accounts, with the same password, will produce the same hash. This is where salting comes in.

Salting is the process of producing a random string of letters, numbers and other non-alphanumeric characters, which can then be concatenated, or joined, with the password, before a hash value is produced. Both the salt value and the hash are stored in the database. When a user logs in, the salt value, corresponding to the username, is used to produce a hash of the password entered and this is then compared to the hash stored in the database of the password.

In the example below, methods are used to produce both the salt value and the password hash. The hashing method uses the 'PBKDF2' hashing algorithm to produce the hash. The password would initially come from, for example, a sign-up form, however, for illustration purposes here, this is just assigned to a variable. Similarly, the password entered would be from a log in form, for example, but here has just been assigned to a variable. When checking for a valid password, the username would be used to retrieve the associated salt value from the database, which is stored in the salt variable here. The salt value is used to produce a hash of the entered password, which is then compared to the hash value that is stored.

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

namespace DemoConsole
{
    class Program
    {

        static void Main(string[] args)
        {

            // Produce a salt and hash value for the password.
            var password = "password123";
            var salt = GenerateSalt();
            var hashedPassword = ComputeHash(Encoding.UTF8.GetBytes(password), 
                                             Encoding.UTF8.GetBytes(salt));

            // Salt and hash value would then be stored against the user in the database.

            // Produce a hash value for the password entered, using the above salt value.
            var enteredPassword = "password124";
            var hashedEnteredPassword = ComputeHash(Encoding.UTF8.GetBytes(enteredPassword), 
                                                    Encoding.UTF8.GetBytes(salt));

            // Compare the password hash with the hash of the password entered.
            if (hashedPassword == hashedEnteredPassword)
            {
                Console.WriteLine("Password entered correctly.");
            }
            else
            {
                Console.WriteLine("Password entered incorrectly.");
            }

        }

        // Method to generate a salt value.
        private static string GenerateSalt()
        {
            var bytes = new byte[16];
            var rng = new RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            return Convert.ToBase64String(bytes);
        }

        // Method to produce a hash of a password.
        private static string ComputeHash(byte[] bytesToHash, byte[] salt)
        {
            var byteResult = new Rfc2898DeriveBytes(bytesToHash, salt, 10000);
            return Convert.ToBase64String(byteResult.GetBytes(24));
        }

    }

}

Further Resources