PBKDF2
在http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx的示例中,当您到达“Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1, salt1, myIterations); ", k1 是哈希值。该示例用于加密的原因是 Rfc2898DeriveBytes 最初旨在创建加密密钥。
如果您不提供盐,Rfc2898DeriveBytes 将创建它自己的,但我不知道 RNGCryptoServiceProvider 在加密随机方面是否做得更好。
根据 OWASP ( https://www.owasp.org/index.php/Using_Rfc2898DeriveBytes_for_PBKDF2 ),Rfc2898DeriveBytes 对 SHA1 的底层使用意味着它只适用于长度不超过 160 位的哈希。如果您创建更长的散列,攻击者仍然只需要担心前 160 位,但是您已经使密码散列/身份验证对您自己来说更加昂贵而没有任何收益。
这是 Rfc2898DeriveBytes 密码散列的一些示例代码(将散列、盐和迭代存储在数据库中):
public class Rfc2898PasswordEncoder
{
private int _byteLength = 160 / 8; // 160 bit hash length
public class EncodedPassword
{
public byte[] Hash { get; set; }
public byte[] Salt { get; set; }
public int Iterations { get; set; }
}
public EncodedPassword EncodePassword(string password, int iterations)
{
var populatedPassword = new EncodedPassword
{
Salt = CreateSalt(),
Iterations = iterations
};
// Add Hash
populatedPassword.Hash = CreateHash(password, populatedPassword.Salt, iterations);
return populatedPassword;
}
public bool ValidatePassword(string password, EncodedPassword encodedPassword)
{
// Create Hash
var testHash = CreateHash(password, encodedPassword.Salt, encodedPassword.Iterations);
return testHash == encodedPassword.Hash;
}
public byte[] CreateSalt()
{
var salt = new byte[_byteLength]; // Salt should be same length as hash
using (var saltGenerator = new RNGCryptoServiceProvider())
{
saltGenerator.GetBytes(salt);
}
return salt;
}
private byte[] CreateHash(string password, byte[] salt, long iterations)
{
byte[] hash;
using (var hashGenerator = new Rfc2898DeriveBytes(password, salt, (int)iterations))
{
hash = hashGenerator.GetBytes(_byteLength);
}
return hash;
}
}