In the past when dealing with passwords I\'ve always stored a salt and a hashed password separately in my data store. Today I was looking to update some legacy code to use a RFC
All passwords need to be salted in order to hash them securely. In this case, however, you are correct. System.Web.Helpers.Crypto takes care of creating a salt for you. You don't need to create one. It is stored in the string returned by Crypto.HashPassword().
All you need to do is something like this.
using System.Web.Helpers;
public void SavePassword(string unhashedPassword)
{
string hashedPassword = Crypto.HashPassword(unhashedPassword);
//Save hashedPassword somewhere that you can retrieve it again.
//Don't save unhashedPassword! Just let it go.
}
public bool CheckPassword(string unhashedPassword)
{
string savedHashedPassword = //get hashedPassword from where you saved it
return Crypto.VerifyHashedPassword(savedHashedPassword, unhashedPassword)
}
Just wanted to share this post:
http://forums.asp.net/t/1842429.aspx?System+Web+Helpers+Crypto+HashPassword
Hello,
I have been looking at the new Crypto HashPassword and VerifyMethod method in System.Web.Helpers.
Both methods use a Salt but they do not return the Salt only the Hash.
Don't I need the Salt to store it in the database? Am I missing something?
Thank you,
Miguel
..
You'd generate the salt when the user creates the account, and then you'd append it to the password before you call HashPassword. You'd then store that salt and the hashed password in your DB. When you validate credentials just read the salt from the DB and appends it to the password from the login before calling VerifyHashedPassword. BrockAllen
..
Not sure if I understood it ... Because in HashPassword a Salt is generated inside the method:
Miguel
// Method in Crypto class
public static string HashPassword(string password)
{
if (password == null)
{
throw new ArgumentNullException("password");
}
// Produce a version 0 (see comment above) password hash.
byte[] salt;
byte[] subkey;
using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount))
{
salt = deriveBytes.Salt;
subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
byte[] outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);
return Convert.ToBase64String(outputBytes);
}
..
BrockAllen Sep 11, 2012 07:50 PM
Yea, ignore that -- it's an internal salt for the Rfc2898DeriveBytes and it's derived from the password so it's not a true salt in the context of storing passwords since it's consistently re-created for the same password. You will want to still do your own salt at the password string level. So something like this:
public void CreateAccount(string username, string password)
{
var salt = Crypto.GenerateSalt();
var saltedPassword = password + salt;
var hashedPassword = Crypto.HashPassword(saltedPassword);
CreateAccount(username, salt, hashedPassword);
}
public void Verify(string username, string password)
{
var salt = GetSaltForUserFromDatabase(username);
var hashedPassword = GetHashedPasswordForUserFromDatabase(username);
var saltedPassword = password + salt;
if (Crypto.VerifyHashedPassword(hashedPassword, saltedPassword))
{
// valid password for this username
}
}
This will allow you to store your salt in the database along with the hashed salted password.
Additional info on password hashing with salt in general from this post: https://crackstation.net/hashing-security.htm
To Store a Password
To Validate a Password
Source Code for Crypto class:
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Helpers/Crypto.cs