Click here to Skip to main content
15,867,453 members
Articles / Security

A Beginner's Tutorial for Understanding and Implementing Password Hashing and Salting

Rate me:
Please Sign up or sign in to vote.
4.87/5 (33 votes)
19 Jun 2013CPOL9 min read 122.6K   2.4K   101   19
In this article we will discuss about securing the user passwords by using hashing and salting on the user passwords.

Introduction

In this article we will discuss about securing user passwords by using hashing and salting on user passwords. We will first discuss about the theory of hashing and salting. We will then try to implement a simple library that can be used to perform hashing and salting.

Background 

I have seen many ASP.NET beginners making the mistake of storing the password as plain text in the database. The first question I ask them is why are they not using the ASP.NET Roles and Membership database and API. In most cases using the default Roles and Membership API will fulfill the needs of the application. In some cases the application really needs to have its own tables to save user credentials. All the applications where custom forms authentication is being used are probably storing user credentials in the application database in some application specific schema.

Note: Please refer these two articles to learn more about custom forms authentication:

  1. Understanding and Implementing ASP.NET Custom Forms Authentication[^]
  2. A Beginner's Tutorial on Custom Forms Authentication in ASP.NET MVC Application[^]

Passwords as Plain Text

For all scenarios where we need to store user credentials in application tables, storing the password in plain text is never a good idea. Anyone who has access to the database can easily get to know the password of all the users. Also, even a small part of application that is prone to SQL injection can reveal the password of all users. So what could be done to prevent this and store the password in a better way?

Storing Encrypted Passwords 

Encryption is the process of encoding the message in such a way that even if anyone get hold of the message, he should not be able to interpret anything from it. To encrypt a message we need two things. First we need an encryption algorithm and second we need a key which will be used for encryption.

So if the requirement is not to store the password in plain text then the First thought is to keep the passwords encrypted rather than as plain text. Well this approach is better than storing the passwords in plain text but it still has the some problem. If someone knows the encryption algorithm and the secret key that was used for encryption then he could decrypt the passwords easily.

Hashing - Storing Password Hashes 

Hashing is the process of generating a number or a unique string for a larger string message. The hash for every string message should be unique and there is no way the original message can be reproduced from its hash value. 

No matter how strong our encryption mechanism is, there is always a possibility of regenerating the original password if the algorithm and the secret key is known. So the even better approach would be to store the password hashes in the table. This way there is no way to regenerate the password from the hash. Whenever the user tries to log in, we will generate the hash for the password using the same hashing algorithm and then compare it with the hash stored in the database to check whether the password is correct or not.

Now this approach is a lot better than storing the password in encrypted form. But this also has few limitations. To understand the limitation let us look at the following example: 

User Password Hash 
user1  one  1234  
user2  two  2345 
user3 three 3456 
user4 one 1234 
user5 two 2345 

The above table shows some dummy data where 5 users have chosen there passwords and there corresponding hash values have been generated to store in the database. Now from this table we can clearly see the limitation associated with saving the hashed password. The problem here is that the

The above table shows some dummy data where 5 users have chosen there passwords and there corresponding hash values have been generated to store in the database. Now from this table we can clearly see the limitation associated with saving the hashed password. The problem here is that the user1 and user4 choose the same password and thus their generated password hash is also same. Same is the case with user2 and user5. So if I get hold of these password hashes and I know the password of user1, I actually know the password of all the users whose hash value is same as the hash value of user1's password.

Now this problem is less severe than the problem associated with the earlier approaches. But could we not device a technique which will store provide us all the benefits of hashing and will also remove the limitations associated with it. The answer to this is salting and hashing.

Salting and Hashing of Passwords

Salting is a technique in which we add a random string to the user entered password and then hash the resulting string. So even if two people have chosen the same password, the salt for them will be different. So there will never be case when the hash for two users will be same even if they choose the same password. Following table will illustrate the concept in more details.

UserPassword Random Salt Resultant Password StringHash
user1 one 12 one121234
user2two 23 two232345
user3three 34 three343456
user4one 45 one45 4567
user5two 56 two56 5678

Now if we look at the above table we can see that even though the user1 and user4 has chosen same password their salt value is different and thus the resultant hash value is also different. Now the important thing to note in this approach is that the salt value should always be random and secondly this should also be stored in the database so that it can be used while comparing the user entered password.

Using the code

Now we have seen the theory associated with the password hashing and salting and why is this technique preferred over saving plain text passwords, encrypted passwords or even saving password hashes. Now let us see how we can implement this salting and hashing in in .NET so that it can be used by the applications like ASP.NET or ASP.NET MVC websites during custom forms authentication.

Let us start with the salt creation process. We need to generate a random number, for this we can use RNGCryptoServiceProvider class. This class ensures that the generated number is always random and unique. So let us implement a simple class which will generate a random number using this RNGCryptoServiceProvider.

C#
public static class SaltGenerator
{
    private static RNGCryptoServiceProvider m_cryptoServiceProvider = null;
    private const int SALT_SIZE = 24;

    static SaltGenerator()
    {
        m_cryptoServiceProvider = new RNGCryptoServiceProvider();
    }

    public static string GetSaltString()
    {
        // Lets create a byte array to store the salt bytes
        byte[] saltBytes = new byte[SALT_SIZE];

        // lets generate the salt in the byte array
        m_cryptoServiceProvider.GetNonZeroBytes(saltBytes);

        // Let us get some string representation for this salt
        string saltString = Utility.GetString(saltBytes);

        // Now we have our salt string ready lets return it to the caller
        return saltString;
    }       
}

Now we have a class that will generate the random salt value for us. Let us now create a class that will take care of hashing a message. We will use SHA256CryptoServiceProvider class to generate the hash. There are quite a few algorithms that we can choose from. Let us see how a hash value can be generated for a string message.

C#
public class HashComputer
{
    public string GetPasswordHashAndSalt(string message)
    {   
        // Let us use SHA256 algorithm to 
        // generate the hash from this salted password
        SHA256 sha = new SHA256CryptoServiceProvider();
        byte[] dataBytes = Utility.GetBytes(message);
        byte[] resultBytes = sha.ComputeHash(dataBytes);

        // return the hash string to the caller
        return Utility.GetString(resultBytes);
    }
}

Now we have two classes with us:

  1. SaltGenerator: This class' responsibility is to generate a random and unique salt every time.
  2. HashComputer: This class' responsibility is to generate the SHA256 hash value for a given string message.

Now let us look at the salting and hashing process in form of algorithm.

User creation process: 

  1. User enters a password.
  2. A random salt value is generated for the user.
  3. The salt value is added to the password and a final string is generated.
  4. The hash for the final string is calculated.
  5. The hash and the salt is stored in the database for this user.

User tries to log in: 

  1. User enters his user ID.
  2. The user is used to retrieve the users password hash and salt stored in the database.
  3. The user enters his password.
  4. The retrieved salt is added to this password and a final string is generated.
  5. The hash for the final string is calculated.
  6. This calculated hash is compared with the hash value retrieved from the database.
  7. If it matches the password is correct otherwise not.

So let us create a facade class on top of these two classes which will do the major portion of these activities. it will take the users' id and password and then will take care of doing the rest. It will return the hash and salt to the user. In case of password retrieval, it will ask the user its password and salt and then checks if it matches or not.

C#
public class PasswordManager
{
    HashComputer m_hashComputer = new HashComputer();

    public string GeneratePasswordHash(string plainTextPassword, out string salt)
    {
        salt = SaltGenerator.GetSaltString();

        string finalString = plainTextPassword + salt;

        return m_hashComputer.GetPasswordHashAndSalt(finalString);
    }

    public bool IsPasswordMatch(string password, string salt, string hash)
    {
        string finalString = password + salt;
        return hash == m_hashComputer.GetPasswordHashAndSalt(finalString);
    }
}

Now we have a simple class library ready which is capable of salting and hashing the user passwords. using this library and saving the values in the database will be the applications responsibility. The class diagram of this class library looks like:

Image 1

Note: The Utility class contains 2 simple methods to convert string to byte[] and vice-verse.

Creating a Test Application

Let us now go ahead a create a simple test application to test this library. Let us create a simple console application. Let us first create a Model class that will hold the user login data.

C#
class User
{   
    public string UserId { get; set; }
    public string PasswordHash { get; set; }
    public string Salt { get; set; }
}

Note: This is a very rudimentary model for User login details. It is created only to explain the concepts of the article. Real world application will contain more detailed model.

This model class represent a user details for any user from the user login details table. We will use this model while creating a new user and while the user tries to log in.

Now let us try to simulate/mock the database functionality. let us create a simple repository class which will keep all the data in memory rather than pushing them to the database. The real repository class should push the data into the database in the respective operations.

C#
class MockUserRepository
{
    List<user> users = new List<user>();

    // Function to add the user to im memory dummy DB
    public void AddUser(User user)
    {
        users.Add(user);
    }

    // Function to retrieve the user based on user id
    public User GetUser(string userid)
    {
        return users.Single(u => u.UserId == userid);
    }
}

And finally let us write some code to simulate and test the user creation and password comparison functionality.

C#
class Program
{
    // Dummy repository class for DB operations
    static MockUserRepository userRepo = new MockUserRepository();

    // Let us use the Password manager class to generate the password ans salt
    static PasswordManager pwdManager = new PasswordManager();

    static void Main(string[] args)
    {
        // Let us first test the password hash creation i.e. User creation
        string salt = SimulateUserCreation();

        // Now let is simualte the password comparison
        SimulateLogin(salt);

        Console.ReadLine();
    }

    public static string SimulateUserCreation()
    {
        Console.WriteLine("Let us first test the password hash creation i.e. User creation");
        Console.WriteLine("Please enter user id");
        string userid = Console.ReadLine();

        Console.WriteLine("Please enter password");
        string password = Console.ReadLine();

        string salt = null;

        string passwordHash = pwdManager.GeneratePasswordHash(password, out salt);

        // Let us save the values in the database
        User user = new User
        {
            UserId = userid,
            PasswordHash = passwordHash,
            Salt = salt
        };

        // Lets Add the User to the database
        userRepo.AddUser(user);

        return salt;
    }

    public static void SimulateLogin(string salt)
    {            
        Console.WriteLine("Now let is simulate the password comparison");

        Console.WriteLine("Please enter user id");
        string userid = Console.ReadLine();

        Console.WriteLine("Please enter password");
        string password = Console.ReadLine();

        // Let us retrieve the values from the database
        User user2 = userRepo.GetUser(userid);
            
        bool result = pwdManager.IsPasswordMatch(password, user2.Salt, user2.PasswordHash);

        if (result == true)
        {
            Console.WriteLine("Password Matched");
        }
        else
        {
            Console.WriteLine("Password not Matched");
        }
    }
}

Let us now try to create a user and then enter a valid password:

Image 2

And let us now try to check with wrong password once:

Image 3

And so we have seen the basics of password salting and hashing and have created a simple reusable class library that can be used to create achieve this.

Point of interest

In this article we have discussed the recommended way to saving the user passwords by using salting and hashing on user passwords. We have created a simple reusable class library that can be used to generate the salt and hashes user passwords. I really recommend using this technique whenever we are using custom forms authentication.

This article has been written from a beginner's perspective. I Hope this has been informative.

History

  • 19 June 2013: First version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India

I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals and Data driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to Computer Science/Information Systems. IMO, C# is the best programming language and I love working with C# and other Microsoft Technologies.

  • Microsoft Certified Technology Specialist (MCTS): Web Applications Development with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Accessing Data with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Windows Communication Foundation Development with Microsoft .NET Framework 4

If you like my articles, please visit my website for more: www.rahulrajatsingh.com[^]

  • Microsoft MVP 2015

Comments and Discussions

 
QuestionSALT Pin
ManuVanWinkel7-Feb-19 2:09
ManuVanWinkel7-Feb-19 2:09 
PraiseThanks Pin
Member 1259161217-Jan-18 15:41
Member 1259161217-Jan-18 15:41 
QuestionPassword mismatch issue Pin
anilchoonad24-May-17 2:09
anilchoonad24-May-17 2:09 
GeneralMy vote of 5 Pin
Santhakumar M13-Jan-16 20:08
professionalSanthakumar M13-Jan-16 20:08 
GeneralMy vote of 5 Pin
Daniel Miller31-Dec-15 11:52
professionalDaniel Miller31-Dec-15 11:52 
Questionincorrect result Pin
Member 1125220718-Nov-15 23:30
Member 1125220718-Nov-15 23:30 
QuestionThis topic was great Pin
Member 1044260930-Oct-14 2:05
Member 1044260930-Oct-14 2:05 
QuestionWhat is 'Utility' in the Salt Generator? Pin
ortund23-Apr-14 2:10
ortund23-Apr-14 2:10 
AnswerRe: What is 'Utility' in the Salt Generator? Pin
Garth J Lancaster12-Sep-14 2:36
professionalGarth J Lancaster12-Sep-14 2:36 
GeneralMy vote of 5 Pin
♥…ЯҠ…♥7-Jan-14 2:18
professional♥…ЯҠ…♥7-Jan-14 2:18 
Questionreg: Salt Pin
Rockstar_16-Jul-13 21:33
professionalRockstar_16-Jul-13 21:33 
AnswerRe: reg: Salt Pin
Rahul Rajat Singh16-Jul-13 22:30
professionalRahul Rajat Singh16-Jul-13 22:30 
you will have to differentiate between login and registration process. In registration you will have to generate the salt append it to the password and calculate hash. store this hash and salt in the database.

during login, take the username from user, extract the salt for this username. append this salt to user entered password and then generate hash. then compare it with the hash stored in the database. this should work fine.
Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore, Dream. Discover.

QuestionHashComputer Class Pin
Member 42368651-Jul-13 10:48
Member 42368651-Jul-13 10:48 
QuestionExcellent article Pin
AuzetteCodeProject25-Jun-13 9:40
AuzetteCodeProject25-Jun-13 9:40 
AnswerRe: Excellent article Pin
♥…ЯҠ…♥7-Jan-14 2:15
professional♥…ЯҠ…♥7-Jan-14 2:15 
SuggestionRecord hash type also? Pin
Chad3F24-Jun-13 16:26
Chad3F24-Jun-13 16:26 
GeneralMy vote of 5 Pin
Hal Angseesing24-Jun-13 2:38
professionalHal Angseesing24-Jun-13 2:38 
GeneralMy vote of 5 Pin
JosepLluis20-Jun-13 8:08
JosepLluis20-Jun-13 8:08 
GeneralRe: My vote of 5 Pin
Rahul Rajat Singh20-Jun-13 18:17
professionalRahul Rajat Singh20-Jun-13 18:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.