C# 将哈希密码与salt进行比较总是失败的

C# 将哈希密码与salt进行比较总是失败的,c#,.net,C#,.net,我看到了很多关于密码散列和salt的问题,但它们似乎对我来说都失败了。我使用此函数对其进行哈希/加盐,然后将其放入数据库: public string HashPassword(string password) { byte[] salt; new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]); var pbkdf2 = new Rfc2898DeriveBytes

我看到了很多关于密码散列和salt的问题,但它们似乎对我来说都失败了。我使用此函数对其进行哈希/加盐,然后将其放入数据库:

    public string HashPassword(string password)
    {
        byte[] salt;
        new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
        var pbkdf2 = new Rfc2898DeriveBytes(PasswordTextbox.Password, salt, 10000);
        byte[] hash = pbkdf2.GetBytes(20);
        byte[] hashBytes = new byte[36];
        Array.Copy(salt, 0, hashBytes, 0, 16);
        Array.Copy(hash, 0, hashBytes, 16, 20);
        string savedPasswordHash = Convert.ToBase64String(hashBytes);
        return savedPasswordHash;
    }
然后我尝试使用此函数将其与用户输入进行比较:

    public static void UnhashPassword(string hashedPassword, string hashedPasswordFromDatabase)
    {
        byte[] hashBytes = Convert.FromBase64String(hashedPasswordFromDatabase);
        byte[] salt = new byte[16];
        Array.Copy(hashBytes, 0, salt, 0, 16);
        var pbkdf2 = new Rfc2898DeriveBytes(hashedPassword, salt, 10000);
        byte[] hash = pbkdf2.GetBytes(20);
        for (int i = 0; i < 20; i++)
            if (hashBytes[i + 16] != hash[i])
                throw new UnauthorizedAccessException();
    }
第二个函数总是抛出异常。不确定原因是什么,因为这个答案似乎对其他问题中的每个人都适用。

如果没有可靠地重现问题的好方法,就不可能确定出什么是错的。但是,以下代码示例的工作方式与预期完全相同,即调用ValidatePassword初始化后,result的值为true:

上述代码与原始代码之间唯一的实质性变化是HashPassword方法使用传入的密码值,而不是PasswordTextbox.password

根据这一观察结果,我只能推测,在您自己的场景中,您并没有在稍后验证时真正散列相同的密码。无论这是因为PasswordTextbox.Password从来没有正确的密码,还是您稍后传递的是不同的密码,我不能说


如果上面的代码示例没有为您指明正确的方向,以便您可以使用代码,请改进您的问题,使其包含一个好的。

两件事:1您将密码传递到第一个函数中,并且从不使用它。2检查密码匹配的方法是以与原始密码完全相同的方式对提供的密码进行散列,然后查看是否得到相同的结果。我不确定你是不是搞错了,但你的密码名unhashPassword表明你搞错了。您无法解除密码的锁定。散列是单向过程,这就是关键所在-你无法从散列中获取密码。@克里斯:请注意,虽然第二个方法的命名有误导性,但该方法中的代码实际上与你在2点中描述的完全一样,事实上,当提供正确的数据时,工作正常…请参阅下面。请更新您的问题,以及您收到的异常类型和在哪一行。除了@PeterDuniho已经写的内容之外,你不应该在实际项目中真正使用自己的加密。我建议您查看MembershipProvider类@Igor:可能引发的异常是UnauthorizedAccessException,即当密码验证失败时方法显式引发的异常。至于使用您自己的加密,虽然这个建议通常是好的,但我不清楚OP是否违反了它。该建议主要是指实际实现加密。OP的代码正确地将所有实际的加密任务委托给框架。如果一个人可以完全避免这个问题,并使用一个从开始到结束管理密码的库,那就更好了,但对于OP来说,这可能是不可能的。@Chris:OP真的应该使用更好的名称——没有异议。但通常情况下,缺乏经验和/或糟糕的编码习惯与需要他人的帮助密切相关。幸运的是,好名字与代码的实际工作无关。看到了足够多的名字不好的代码,或者在某些情况下,仅仅是我不理解的外国名字,我已经习惯于看到过去的名字来了解代码的实际功能。这是一项我不时发现非常有用的技能
static void Main(string[] args)
{
    string password = "password";
    string hashedPassword = HashPassword(password);
    bool result = ValidatePassword(password, hashedPassword);
}

static string HashPassword(string password)
{
    byte[] salt;
    new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
    var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000);
    byte[] hash = pbkdf2.GetBytes(20);
    byte[] hashBytes = new byte[36];
    Array.Copy(salt, 0, hashBytes, 0, 16);
    Array.Copy(hash, 0, hashBytes, 16, 20);
    string savedPasswordHash = Convert.ToBase64String(hashBytes);
    return savedPasswordHash;
}

static bool ValidatePassword(string password, string hashedPasswordFromDatabase)
{
    byte[] hashBytes = Convert.FromBase64String(hashedPasswordFromDatabase);
    byte[] salt = new byte[16];
    Array.Copy(hashBytes, 0, salt, 0, 16);
    var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000);
    byte[] hash = pbkdf2.GetBytes(20);
    for (int i = 0; i < 20; i++)
    {
        if (hashBytes[i + 16] != hash[i])
        {
            return false;
        }
    }

    return true;
}