使用 PBKDF2,以字节为单位的最佳哈希大小是多少?盐的大小呢?

信息安全 密码 哈希 pbkdf2
2021-09-05 02:22:57

使用 PBKDF2 创建散列时,它允许开发人员选择散列的大小。越长越好吗?另外,随机盐的大小如何?它应该与哈希大小相同吗?

编辑:特别是在散列密码中。

3个回答

对于散列函数,您希望使用最有效的平台类型(每秒和每美元产生更多散列计算的平台类型)是您打算使用的机器(即 PC)的函数。那是因为您正在与攻击者进行武器竞赛,而攻击者可以购买其他类型的硬件来获得优势(例如 GPU)。GPU 非常擅长 32 位算术,但不擅长 64 位算术,而 PC(在 64 位模式下)在后者方面会非常快。

因此,请使用在 64 位算术运算上运行的散列函数。这指向SHA-512

PBKDF2 是一个密钥派生函数:它产生一个可配置大小的输出。对于密码散列,您希望大小足够大以阻止通用原像攻击(即尝试随机密码直到找到匹配项),因此这将需要至少 80 位的输出。如果只是为了让粗心的人对安全性更有说服力,也为了美观,请选择 2 的下一个幂:128 位输出超出这个范围是没有用的。

盐必须是唯一的——尽可能唯一。实现唯一盐值的一种简单方法是生成具有加密强 PRNG的盐:如果这些随机盐足够大,重用盐值的概率将足够低以至于可以忽略不计,并且“足够大”意味着“128 位”。所以使用随机的 128 位 salts

就个人而言,我更喜欢 bcrypt而不是 PBKDF2 进行密码散列。

根据 PBKDF2 标准,salt 的最小推荐大小为 64 位,尽管我个人建议使用 128 位或更高以获得不错的安全裕度。盐的大小与您选择的哈希无关。

就安全性而言,我建议选择至少与 salt 输出大小相同的派生密钥长度,至少256 位。无论如何,任何小于 256 位的散列大小都低于大多数现代散列函数的安全边界。

选择小于散列函数输出长度的派生密钥长度几乎没有意义,除非您将密钥用于无法处理该大小密钥的分组密码。

就最佳安全性而言,我建议将 SHA-512 作为 PRF,使用 512 位派生密钥、128 位盐和尽可能多的迭代,只要您的情况允许。

如果您选择的平台是 .NET,则有一篇专门针对其Rfc2898DeriveBytes类的 OWASP 文章。特别注意(强调我的):

Rfc2898DeriveBytes 的内置 .NET 实现将用户限制为一个伪随机函数 -带有 SHA-1 的 HMAC这在今天的大多数场景中是可以接受的,但在未来,可能需要更复杂的散列函数。

使用 PBKDF2 进行密码存储,输出的位数永远不应超过基本哈希函数的大小。对于 PBKDF2-SHA1,这是160 位或 20 字节输出更多位不会使哈希更安全,但它会花费防御者更多的时间,而不会花费攻击者。攻击者将只比较第一个散列函数大小的输出,从而节省他们生成 PBKDF2 输出重置的时间。

他们还有一个代码示例,我根据其他答案的指导对其进行了调整:

public static string Hash(string str)
{
    // Generate the hash, with an automatic 16 byte salt
    using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(str, 16))
    {
        rfc2898DeriveBytes .IterationCount = 10000 // or whatever you can afford
        byte[] hash = rfc2898DeriveBytes.GetBytes(20);
        byte[] salt = rfc2898DeriveBytes.Salt;
        return Convert.ToBase64String(salt) + "|" + Convert.ToBase64String(hash);
    }
}