为什么我的密码哈希函数使用相同的盐生成不同的哈希值?
Why is my password hashing function producing different hashes with the same salt?
存储在我的数据库中的密码是这样加密的:
byte[] salt = NewSalt();
string hashedPassword = HashPassword("passwordInTheClear", salt);
// Add/update the admin-user with hashed password and salt.
哈希函数:
public static string HashPassword(string password, byte[] salt)
{
// derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
return Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA1,
iterationCount: 10000,
numBytesRequested: 256 / 8));
}
盐生成器:
public static byte[] NewSalt()
{
// generate a 128-bit salt using a secure PRNG
byte[] salt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
return salt;
}
当用户尝试登录系统时,我使用相同的散列函数和相同的盐对登录表单中输入的密码进行散列处理,并将其与存储在数据库中的散列密码进行比较:
// (I have separated out the password check from the linq query just for debugging purposes)
AdminUser au = await db.AdminUsers
.Where(u =>
u.Email1 == loginForm.UserName)
.FirstOrDefaultAsync().ConfigureAwait(false);
byte[] salt = Encoding.ASCII.GetBytes(au.PasswordSalt);
string hashedEnteredPassword = HashPassword(loginForm.Password, salt);
if (au.Password == hashedEnteredPassword)
{
// Success!
}
但是存储的密码和输入的密码不匹配。
示例:
In the database:
Unhashed password: 1234
Salt: Cda6ZgNVluChtzseyq9uMQ==
Hashed password: PKzE3rr9CGGmVW3UJS1N7mqrXmzni3hsqyCtP8lrehE=
In the login form:
Entered, unhashed password: 1234
Salt: Cda6ZgNVluChtzseyq9uMQ==
Hashed password: WwYUZqV1GfuRKEitpRdKDjTMEGWy+1nYzpkWI+eZPB0=
您正在从数据库中以 ASCII 格式获取 salt,而您示例中的 salt 显然是 Base64。您只需将 Encoding.ASCII.GetBytes(au.PasswordSalt)
替换为 Convert.FromBase64String(au.PasswordSalt)
并收工。
byte[] salt = Encoding.ASCII.GetBytes("Cda6ZgNVluChtzseyq9uMQ==");
string encryptedPassword = EncryptPassword("1234", salt);
Console.WriteLine(encryptedPassword);
会给你WwYUZqV1GfuRKEitpRdKDjTMEGWy+1nYzpkWI+eZPB0=
,而
byte[] salt = Convert.FromBase64String("Cda6ZgNVluChtzseyq9uMQ==");
string encryptedPassword = EncryptPassword("1234", salt);
Console.WriteLine(encryptedPassword);
给出 PKzE3rr9CGGmVW3UJS1N7mqrXmzni3hsqyCtP8lrehE=
.
存储在我的数据库中的密码是这样加密的:
byte[] salt = NewSalt();
string hashedPassword = HashPassword("passwordInTheClear", salt);
// Add/update the admin-user with hashed password and salt.
哈希函数:
public static string HashPassword(string password, byte[] salt)
{
// derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
return Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA1,
iterationCount: 10000,
numBytesRequested: 256 / 8));
}
盐生成器:
public static byte[] NewSalt()
{
// generate a 128-bit salt using a secure PRNG
byte[] salt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
return salt;
}
当用户尝试登录系统时,我使用相同的散列函数和相同的盐对登录表单中输入的密码进行散列处理,并将其与存储在数据库中的散列密码进行比较:
// (I have separated out the password check from the linq query just for debugging purposes)
AdminUser au = await db.AdminUsers
.Where(u =>
u.Email1 == loginForm.UserName)
.FirstOrDefaultAsync().ConfigureAwait(false);
byte[] salt = Encoding.ASCII.GetBytes(au.PasswordSalt);
string hashedEnteredPassword = HashPassword(loginForm.Password, salt);
if (au.Password == hashedEnteredPassword)
{
// Success!
}
但是存储的密码和输入的密码不匹配。
示例:
In the database:
Unhashed password: 1234
Salt: Cda6ZgNVluChtzseyq9uMQ==
Hashed password: PKzE3rr9CGGmVW3UJS1N7mqrXmzni3hsqyCtP8lrehE=
In the login form:
Entered, unhashed password: 1234
Salt: Cda6ZgNVluChtzseyq9uMQ==
Hashed password: WwYUZqV1GfuRKEitpRdKDjTMEGWy+1nYzpkWI+eZPB0=
您正在从数据库中以 ASCII 格式获取 salt,而您示例中的 salt 显然是 Base64。您只需将 Encoding.ASCII.GetBytes(au.PasswordSalt)
替换为 Convert.FromBase64String(au.PasswordSalt)
并收工。
byte[] salt = Encoding.ASCII.GetBytes("Cda6ZgNVluChtzseyq9uMQ==");
string encryptedPassword = EncryptPassword("1234", salt);
Console.WriteLine(encryptedPassword);
会给你WwYUZqV1GfuRKEitpRdKDjTMEGWy+1nYzpkWI+eZPB0=
,而
byte[] salt = Convert.FromBase64String("Cda6ZgNVluChtzseyq9uMQ==");
string encryptedPassword = EncryptPassword("1234", salt);
Console.WriteLine(encryptedPassword);
给出 PKzE3rr9CGGmVW3UJS1N7mqrXmzni3hsqyCtP8lrehE=
.