Click here to Skip to main content
15,881,423 members
Articles / Programming Languages / C#

Use BCrypt to Hash Your Passwords: Example for C# and SQL Server

Rate me:
Please Sign up or sign in to vote.
5.00/5 (16 votes)
12 Oct 2012CPOL3 min read 108K   23   12
Some implementation details

By now, you know passwords should be stored using a hash. Given your decision to do the right thing and hash your passwords, you still have to decide on some implementation details.

First, choose a hashing algorithm. Choose BCrypt. Why BCrypt? I’ll give you two reasons:

  1. It is slow, and slow is good because it thwarts brute-force attacks (read more here).
  2. The output from BCrypt is a Base-64 alphabet (http://tools.ietf.org/html/rfc4648#section-4) which means there are no characters that are tricksy to store in a simple character field; CodePage is irrelevant.

Second, find a reliable implementation of BCrypt. I am going to show an example of using C#.NET and SQL Server, but here is a good reference I found using PHP and MySQL (http://oscarm.org/2012/6/using-bcrypt-store-passwords). I also say a “reliable implementation” because there are flaws in some implementations, such as one discovered in 2011 and discussed in these articles (http://en.wikipedia.org/wiki/Crypt_(Unix), http://www.digipedia.pl/usenet/thread/16234/200/ (Search for $2y$) in this second article. – $2y$ indicates you are using a version of BCrypt for Unix that does not contain this bug).

I am using Derek Slager’s C# implementation of BCrypt downloaded from here. Based on a little testing I did myself, I believe it does not contain the flaw cited in the above article, but I am no expert at this. Even if the bug discovered in 2011 exists in this implementation of BCrypt, it is of little concern to me as all of my users are located within the U.S. and are extremely unlikely to be using password characters that cannot be directly entered from a standard keyboard (characters with ASCII values greater than 127). And even if a user does have such a password, the attack vector remains incredibly tiny for exploitation.

Third, understand the inputs and outputs. BCrypt includes a method to generate a salt. When the salt is applied to the password, the resulting hash holds the original salt and the hashed password. You can store the salt and password combined in a CHAR(60) field in your database. You don’t need to store the hashed password separately from the salt, nor should you, since the BCrypt class contains a method that expects the salt and password combined to be passed in as a parameter when later confirming the correctness of the user-entered password.

Note, the salt always begins with something like $2a$10$ meaning version 2a of BCrypt and 10 rounds of computations. 10 rounds is the default. You can choose larger numbers to make it slower, or smaller numbers to make it faster, but 10 is a really good choice for most of us. Since the rest of the salt is 22 bytes, and the $2a$10$ is 7 bytes for a total of 29 bytes, the hashed password is always the remaining 31 bytes. The total length of the output that you will store in the database is always 60 bytes long.

C#
string myPassword = "password";
string mySalt = BCrypt.GenerateSalt();
//mySalt == "$2a$10$rBV2JDeWW3.vKyeQcM8fFO"
string myHash = BCrypt.HashPassword(myPassword, mySalt);
//myHash == "$2a$10$rBV2JDeWW3.vKyeQcM8fFO4777l4bVeQgDL6VIkxqlzQ7TCalQvla"
bool doesPasswordMatch = BCrypt.CheckPassword(myPassword, myHash);

Each password stored will have a different salt, and every time a user changes their password you will generate a new salt for the user. I also encourage you to add a little hard-coded salt to the password. This hard-coded salt adds a little more challenge to brute force attacks from hackers that steal your database, but have not stolen your code and don’t have the hard-coded salt.

C#
private void SetPassword(string user, string userPassword)
{
   string pwdToHash = userPassword + "^Y8~JJ"; // ^Y8~JJ is my hard-coded salt
   string hashToStoreInDatabase = BCrypt.HashPassword(pwdToHash, BCrypt.GenerateSalt());
   using (SqlConnection sqlConn = new System.Data.SqlClient.SqlConnection(...)
   {
     sqlConn.Open();
     SqlCommand cmSql = sqlConn.CreateCommand();
     cmSql.CommandText = "UPDATE LOGINS SET PASSWORD=@parm1 WHERE USERNAME=@parm2";
     cmSql.Parameters.Add("@parm1", SqlDbType.Char);
     cmSql.Parameters.Add("@parm2", SqlDbType.VarChar);
     cmSql.Parameters["@parm1"].Value = hashToStoreInDatabase;
     cmSql.Parameters["@parm2"].Value = user;
     cmSql.ExecuteNonQuery();
   }
 }

private bool DoesPasswordMatch(string hashedPwdFromDatabase, string userEnteredPassword)
{
    return BCrypt.CheckPassword(userEnteredPassword + "^Y8~JJ", hashedPwdFromDatabase);
}

Another reference to BCrypt compared to SHA512: http://stackoverflow.com/questions/1561174/sha512-vs-blowfish-and-bcrypt.

License

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


Written By
Software Developer (Senior) Kraft Software LLC
United States United States
Rob Kraft is an independent software developer for Kraft Software LLC. He has been a software developer since the mid 80s and has a Master's Degree in Project Management. Rob lives near Kansas City, Missouri.

Comments and Discussions

 
QuestionWhat namespace do I use? Pin
The Magical Magikarp8-Feb-20 19:55
The Magical Magikarp8-Feb-20 19:55 
AnswerRe: What namespace do I use? Pin
Rob Kraft9-Feb-20 3:21
professionalRob Kraft9-Feb-20 3:21 
GeneralRe: What namespace do I use? Pin
The Magical Magikarp9-Feb-20 12:41
The Magical Magikarp9-Feb-20 12:41 
GeneralRe: What namespace do I use? Pin
The Magical Magikarp9-Feb-20 12:54
The Magical Magikarp9-Feb-20 12:54 
GeneralRe: What namespace do I use? Pin
Rob Kraft9-Feb-20 14:31
professionalRob Kraft9-Feb-20 14:31 
QuestionSalt?? Pin
roland_h4-Dec-16 16:39
roland_h4-Dec-16 16:39 
AnswerRe: Salt?? Pin
Rob Kraft5-Dec-16 2:10
professionalRob Kraft5-Dec-16 2:10 
GeneralMy vote of 5 Pin
DiponRoy26-May-15 0:45
DiponRoy26-May-15 0:45 
GeneralRe: My vote of 5 Pin
Rob Kraft26-May-15 2:29
professionalRob Kraft26-May-15 2:29 
GeneralVery helpful Pin
Wakabajashij14-Aug-14 20:56
Wakabajashij14-Aug-14 20:56 
GeneralRe: Very helpful Pin
Rob Kraft15-Aug-14 2:20
professionalRob Kraft15-Aug-14 2:20 
GeneralMy vote of 5 Pin
Alan Ball4-Sep-13 6:12
Alan Ball4-Sep-13 6:12 

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.