System.Web.Helpers.Crypto - 盐在哪里?

时间:2013-07-17 07:38:12

标签: c# asp.net cryptography

在过去处理密码时,我总是在我的数据存储中分别存储盐和散列密码。今天我想更新一些遗留代码以使用RFC 2898哈希值。我发现了来自Crypto.Hash的{​​{1}}方法。看起来这些将为我完成大部分繁重的工作。有System.Web.HelpersGenerateSalt()HashPassword()方法。 VerifyHashedPassword()HashPassword()方法不带盐值。 VerifyHashedPassword()方法的MSDN文档说:

“生成的哈希字节流的格式为{0x00,salt,subkey},在返回之前进行base-64编码。”

我需要担心盐吗?文档似乎说会自动生成一个salt并存储在base-64编码值中?它是否正确?我需要存储的是从HashPassword()返回的字符串?

2 个答案:

答案 0 :(得分:51)

答案

所有密码都需要加密,以便安全地哈希。但是,在这种情况下,你是对的。 System.Web.Helpers.Crypto负责为您创建一个salt。 不需要创建一个。它存储在Crypto.HashPassword()返回的字符串中。

实施例

你需要做的就是这样。

using System.Web.Helpers;

public void SavePassword(string unhashedPassword)
{
    string hashedPassword = Crypto.HashPassword(unhashedPassword);
    //Save hashedPassword somewhere that you can retrieve it again.
    //Don't save unhashedPassword! Just let it go.
}

public bool CheckPassword(string unhashedPassword)
{
    string savedHashedPassword = //get hashedPassword from where you saved it

    return Crypto.VerifyHashedPassword(savedHashedPassword, unhashedPassword)
}

更多信息

  • 如果您想查看加密类的源代码,可以查看here
  • here是一个关于课堂的好博客及其背后的一些想法。

答案 1 :(得分:-2)

只是想分享这篇文章:

http://forums.asp.net/t/1842429.aspx?System+Web+Helpers+Crypto+HashPassword

  

您好,
  我一直在查看System.Web.Helpers中新的Crypto HashPassword和VerifyMethod方法。
  这两种方法都使用Salt,但它们不会仅使用Hash返回Salt   我不需要Salt将其存储在数据库中吗?我错过了什么吗?   谢谢,
  米格尔

...

  

您在用户创建帐户时生成salt,然后生成   您在调用HashPassword之前将其附加到密码。你' d   然后在您的数据库中存储该salt和哈希密码。当你   验证凭据只需从数据库中读取盐并将其附加到   在调用VerifyHashedPassword之前登录的密码。   BrockAllen

...

  

不确定我是否理解...因为在HashPassword中,盐是   在方法内部生成:

     

米格尔

// Method in Crypto class
public static string HashPassword(string password)
{
    if (password == null)
    {
        throw new ArgumentNullException("password");
    }

    // Produce a version 0 (see comment above) password hash.
    byte[] salt;
    byte[] subkey;
    using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount))
    {
        salt = deriveBytes.Salt;
        subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
    }

    byte[] outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
    Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
    Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);
    return Convert.ToBase64String(outputBytes);
}

...

  

BrockAllen   2012年9月11日下午07:50

     

是的,忽略它 - 它是Rfc2898DeriveBytes的内部盐   并且它来自密码,所以它不是真正的盐   存储密码的上下文,因为它一直在重新创建   相同的密码。你会想要自己做自己的盐   密码字符串级别。所以像这样:

public void CreateAccount(string username, string password)
{
    var salt = Crypto.GenerateSalt();
    var saltedPassword = password + salt;
    var hashedPassword = Crypto.HashPassword(saltedPassword);
    CreateAccount(username, salt, hashedPassword);
}

public void Verify(string username, string password)
{
    var salt = GetSaltForUserFromDatabase(username);
    var hashedPassword = GetHashedPasswordForUserFromDatabase(username);
    var saltedPassword = password + salt;
    if (Crypto.VerifyHashedPassword(hashedPassword, saltedPassword))
    {
        // valid password for this username
    }
}

这将允许您将盐与散列盐渍密码一起存储在数据库中。

此帖子中有关使用salt进行密码哈希的其他信息: https://crackstation.net/hashing-security.htm

存储密码

  1. 使用CSPRNG生成长的随机盐。
  2. 将salt添加到密码中,并使用标准加密哈希函数(如SHA256)对其进行哈希处理。
  3. 将salt和hash都保存在用户的数据库记录中。
  4. 验证密码

    1. 从数据库中检索用户的salt和hash。
    2. 将salt添加到给定的密码并使用相同的哈希函数对其进行哈希。
    3. 将给定密码的哈希值与数据库中的哈希值进行比较。如果匹配,则密码正确。否则,密码不正确。
    4. 加密类的源代码:

      http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Helpers/Crypto.cs