考虑到今天(2012 年)的最佳实践,这里的大多数其他答案都有些过时了。
.NET 中原生可用的最强大的密码哈希算法是 PBKDF2,由Rfc2898DeriveBytes
班级。
以下代码位于本文的独立类中:如何存储加盐密码哈希的另一个示例 http://csharptest.net/470/another-example-of-how-to-store-a-salted-password-hash/。基础知识非常简单,所以这里分为:
STEP 1使用加密 PRNG 创建盐值:
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
STEP 2创建 Rfc2898DeriveBytes 并获取哈希值:
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000);
byte[] hash = pbkdf2.GetBytes(20);
STEP 3合并盐和密码字节以供以后使用:
byte[] hashBytes = new byte[36];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 20);
STEP 4将组合的 salt+hash 变成字符串进行存储
string savedPasswordHash = Convert.ToBase64String(hashBytes);
DBContext.AddUser(new User { ..., Password = savedPasswordHash });
STEP 5根据存储的密码验证用户输入的密码
/* Fetch the stored value */
string savedPasswordHash = DBContext.GetUser(u => u.UserName == user).Password;
/* Extract the bytes */
byte[] hashBytes = Convert.FromBase64String(savedPasswordHash);
/* Get the salt */
byte[] salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
/* Compute the hash on the password the user entered */
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000);
byte[] hash = pbkdf2.GetBytes(20);
/* Compare the results */
for (int i=0; i < 20; i++)
if (hashBytes[i+16] != hash[i])
throw new UnauthorizedAccessException();
注意:根据具体应用的性能要求,该值100000
可以减少。最小值应约为10000
.