C# 使用Pbkdf2加密使用Salt加密和验证哈希密码

C# 使用Pbkdf2加密使用Salt加密和验证哈希密码,c#,encoding,asp.net-core,cryptography,passwords,C#,Encoding,Asp.net Core,Cryptography,Passwords,我正在使用以下代码创建哈希密码和salt: // generate a 128-bit salt using a secure PRNG byte[] salt = new byte[128 / 8]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(salt); } // derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations) strin

我正在使用以下代码创建哈希密码和salt:

// generate a 128-bit salt using a secure PRNG
byte[] salt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
    rng.GetBytes(salt);
}

// derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
string hashedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2(
    password: password,
    salt: salt,
    prf: KeyDerivationPrf.HMACSHA1,
    iterationCount: 10000,
    numBytesRequested: 256 / 8));
我正在数据库中存储HashedPassword和Salt

现在我想验证用户登录时的密码:

public bool VerifyPassword(string userEnteredPassword, string dbPasswordHash, string dbPasswordSalt)
{
    string hashedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2(
        password: userEnteredPassword,
        salt: Encoding.ASCII.GetBytes(dbPasswordSalt),
        prf: KeyDerivationPrf.HMACSHA1,
        iterationCount: 10000,
        numBytesRequested: 256 / 8));

    return dbPasswordHash == hashedPassword;
}

这不起作用,我得到的哈希密码与数据库中存储的密码完全不同。据我所知,您应该在用户登录时输入的密码前加上salt,然后运行相同的Hash password函数。难道上述情况不等同于此吗?

正如马丁·博德维斯所提到的,ASCII是问题所在。下面的代码返回true。我所做的所有更改都是
salt:Encoding.ASCII.GetBytes(dbPasswordSalt),
salt:System.Convert.FromBase64String(dbPasswordSalt),


正如Maarten Bodewes提到的,ASCII是问题所在。下面的代码返回true。我所做的所有更改都是
salt:Encoding.ASCII.GetBytes(dbPasswordSalt),
salt:System.Convert.FromBase64String(dbPasswordSalt),

  • 创建密码
  • 使用以下代码创建一个salt:

        byte[] salt = new byte[128 / 8];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(salt);
        }
        return Convert.ToBase64String(salt);
    
    然后使用该salt创建哈希密码

    string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
            password: password,
            salt: salt,
            prf: KeyDerivationPrf.HMACSHA1,
            iterationCount: 10000,
            numBytesRequested: 256 / 8));
    
    保存在某处使用的盐(例如:数据库) 保存该用户的哈希密码

  • 验证密码
    • 检索该用户的salt和哈希密码
    • 使用检索到的salt和用户输入的密码创建哈希密码
    • 检查新哈希密码和存储的密码是否相同
  • 创建密码
  • 使用以下代码创建一个salt:

        byte[] salt = new byte[128 / 8];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(salt);
        }
        return Convert.ToBase64String(salt);
    
    然后使用该salt创建哈希密码

    string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
            password: password,
            salt: salt,
            prf: KeyDerivationPrf.HMACSHA1,
            iterationCount: 10000,
            numBytesRequested: 256 / 8));
    
    保存在某处使用的盐(例如:数据库) 保存该用户的哈希密码

  • 验证密码
    • 检索该用户的salt和哈希密码
    • 使用检索到的salt和用户输入的密码创建哈希密码
    • 检查新哈希密码和存储的密码是否相同

  • 看起来不错;我会确保你的盐分在两种食物之间是一样的two@BradleyDotNET我在想字节[]到字符串和字符串到字节[]的转换可能发生了一些问题。您的salt是一个随机缓冲区,而不是字符串,因此
    string dbPasswordSalt
    不是您想要的。将其作为varbinary存储在数据库中,并将其读回
    字节[]
    以供
    salt:
    使用。如果使用varbinary,则不需要base64往返,并且存储大小更小。这两个因素都不太重要,所以取决于您。一个小建议:使用UTF-8作为密码和其他要散列的参数。它们在Android、BSDs、Unix、Linux、iOS、OSX和Windows上是一致的。东西:只要工作“.ASCII、UTF-16和UTF-32将使您在某些时候在某些平台上执行转换。它看起来是正确的;我将确保您的盐在不同的平台之间实际上是相同的two@BradleyDotNET我在想,字节[]到字符串和字符串到字节[]可能发生了什么事情转换。您的salt是一个随机缓冲区,不是字符串,因此
    string dbPasswordSalt
    不是您想要的。将其作为varbinary存储在数据库中,并将其读回
    字节[]
    对于
    salt:
    如果你使用varbinary,你不需要base64往返,而且存储空间也更小。这两个因素都不太重要,所以取决于你。一个小建议:使用UTF-8作为密码和其他要散列的参数。它们在Android、BSDs、Unix、Linux、iOS、OS X和Windows上是一致的。注意事项:j“工作”。ASCII、UTF-16和UTF-32将使您有时在某些平台上执行转换。