C# 为什么我的密码散列函数使用相同的盐生成不同的散列?

C# 为什么我的密码散列函数使用相同的盐生成不同的散列?,c#,encryption,asp.net-core-mvc,password-encryption,C#,Encryption,Asp.net Core Mvc,Password Encryption,存储在我的数据库中的密码按如下方式加密: 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) { /

存储在我的数据库中的密码按如下方式加密:

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;
}
当用户尝试登录系统时,我使用相同的哈希函数和相同的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=

您从数据库中获取的salt是ASCII,而示例中的salt显然是Base64。您只需将Encoding.ASCII.GetBytesau.PasswordSalt替换为Convert.FromBase64Stringau.PasswordSalt,然后结束

byte[] salt = Encoding.ASCII.GetBytes("Cda6ZgNVluChtzseyq9uMQ==");
string encryptedPassword = EncryptPassword("1234", salt);
Console.WriteLine(encryptedPassword);
将为您提供wwyuzqv1gfurkeitpdkdjtmegwy+1nYzpkWI+eZPB0=,而


给出pkze3rr9cgggmvw3ujs1n7mqrxmzni3hsqyctp8lrehe=。

您从数据库获取的salt是ASCII,而示例中的salt显然是Base64。您只需将Encoding.ASCII.GetBytesau.PasswordSalt替换为Convert.FromBase64Stringau.PasswordSalt,然后结束

byte[] salt = Encoding.ASCII.GetBytes("Cda6ZgNVluChtzseyq9uMQ==");
string encryptedPassword = EncryptPassword("1234", salt);
Console.WriteLine(encryptedPassword);
将为您提供wwyuzqv1gfurkeitpdkdjtmegwy+1nYzpkWI+eZPB0=,而


PKzE3rr9CGGmVW3UJS1N7mqrXmzni3hsqyCtP8lrehE=。

没有回答您的问题,但我希望您有理由存储加密密码,而不是密码哈希。提到这一点是因为,出于您问题中概述的目的,散列是更好的选择。@not2savy我的印象是,对加密进行散列只是同一事物的两个不同名称。我刚刚将我的加密方法命名为EncryptPassword。我可以叫它HashPassword。还是我错过了什么?哦,是的,那么你确实错过了什么。散列就像校验和,它是不可逆的。因此,它的优点是,如果有人入侵您的数据库或在MITM攻击中,密码无法解密,但它仍然非常适合用于身份验证。但是,看起来您实际上是在进行散列,而不是加密,所以您的方法名有误导性。@not2savy我明白了。我现在已经改变了名字。谢谢你的洞察力!:这不是对您问题的回答,但我希望您有理由存储加密的密码,而不是密码哈希。提到这一点是因为,出于您问题中概述的目的,散列是更好的选择。@not2savy我的印象是,对加密进行散列只是同一事物的两个不同名称。我刚刚将我的加密方法命名为EncryptPassword。我可以叫它HashPassword。还是我错过了什么?哦,是的,那么你确实错过了什么。散列就像校验和,它是不可逆的。因此,它的优点是,如果有人入侵您的数据库或在MITM攻击中,密码无法解密,但它仍然非常适合用于身份验证。但是,看起来您实际上是在进行散列,而不是加密,所以您的方法名有误导性。@not2savy我明白了。我现在已经改变了名字。谢谢你的洞察力!: