There are seveal ways (even here in SO) and they all mention that the best way to keep password on database is to save, not the password, not the hased password, but to store the hash of a salted password.
My question is simple, putting some code on it, is this the correct way?
string username = "myUsr";
string password = "myPwd";
DateTime createDate = DateTime.UtcNow;
// Salt it
string saltedPwd = String.Concat(password, createDate.Ticks.ToString());
// Hash it
HMACSHA1 hash = new HMACSHA1(Encoding.Unicode.GetBytes(Helper.EncryptKey));
string encodedPwd = Convert.ToBase64String(
hash.ComputeHash(Encoding.Unicode.GetBytes(saltedPwd)));
// Create User in the database
db.CreateUser(username, encodedPwd, createDate);
Database User Table
user_id | username | password | create_date | last_access | active
and upon Login use do the process again and check if the encodedPwd
is the same as the salted, hased password that was provided.
My only concern is, is this the best way to salt a password? Is it ok to use the Created Date (as that will always change, and I read that it is best to use always a different salt
every time we encode a password...
Or should be the salt
a completely different variable?
Your implementation is probably good enough, but it would be better to use a salt with more entropy: the ticks value that you're currently using will always be in a relatively small range.
I would suggest using something like PBKDF2 to do the work for you, via Rfc2898DeriveBytes
:
string username = "myUsr";
string password = "myPwd";
using (var deriveBytes = new Rfc2898DeriveBytes(password, 20)) // 20-byte salt
{
byte[] salt = deriveBytes.Salt;
byte[] key = deriveBytes.GetBytes(20); // 20-byte key
string encodedSalt = Convert.ToBase64String(salt);
string encodedKey = Convert.ToBase64String(key);
// store encodedSalt and encodedKey in database
// you could optionally skip the encoding and store the byte arrays directly
db.CreateUser(username, encodedSalt, encodedKey);
}
And to authenticate...
string username = "myUsr";
string password = "myPwd";
string encodedSalt, encodedKey;
// load encodedSalt and encodedKey from database for the given username
byte[] salt = Convert.FromBase64String(encodedSalt);
byte[] key = Convert.FromBase64String(encodedKey);
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
byte[] testKey = deriveBytes.GetBytes(20); // 20-byte key
if (!testKey.SequenceEqual(key))
throw new InvalidOperationException("Password is invalid!");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With