从一个密码派生多个密钥是否安全?

时间:2013-12-04 17:30:20

标签: c# security encryption hash

问题

我的应用程序(我将用C#编写)使用密钥派生方法(Rfc2898DeriveBytes,4000次迭代)和salt来生成密码的“哈希”。然后将此哈希发送到数据库,以便用户以后可以使用该密码对其帐户进行身份验证。

到目前为止应该是安全的,但在此之后,我想在相同的密码上使用Rfc2898DeriveBytes来生成一个密钥,然后可以使用进行加密。现在,我要这样做的方法是使用相同方法的5000次迭代来获得不同的密钥,但我担心如果存储在数据库中的哈希被泄露(或者我被迫透露它),那么它将是可能以某种方式得出第二个密钥。这可能吗?

潜在解决方案

  • 理想情况下,我想使用相同的盐,但会使用 不同的人解决了这个问题?
  • 如何使用SHA作为数据库哈希,使用Rfc进行加密 键?
  • 在导出密钥之前,为每个字符串附加一个唯一但硬编码的字符串(分别为“网站”和“加密”)。 (Damien_the_Unbeliever)
  • 生成双倍长度的密钥,并使用派生密钥的前半部分进行身份验证,后半部分进行加密。 (埃里克森)

对于如何最好地改进这一过程,我将不胜感激。我会发布代码,但我还没写过。

3 个答案:

答案 0 :(得分:3)

您可以从一个密码派生多个密钥。

您是否为不同目的使用不同的盐,或生成更长的密钥并将其中的一部分用于不同目的,取决于您是否需要同时使用不同的密钥。例如,假设用户登录,然后希望能够加密和解密内容而无需重新输入密码。在这种情况下,生成双长度密钥更有效,并使用派生密钥的前半部分进行身份验证,将后半部分用于加密。使用不同的盐生成两个密钥需要大约两倍的时间。

另一方面,如果要求用户输入密码进行身份验证,然后再进行其他加密时间,则不妨选择两种盐。

根据您的提议,泄露存储在数据库中的身份验证哈希不会立即导致泄密。也就是说,你不能简单地迭代哈希函数; PBKDF2的每次迭代都使用密码作为输入。但它确实意味着只需要1000次迭代就可以将密码作为加密密钥进行测试,而且几乎不会受到字典攻击的保护。

顺便说一下,5000次迭代还不够。 50000次迭代将是一个良好的开端。

答案 1 :(得分:3)

为了便于参考,我正在编写一个答案的建议。

迭代次数

虽然这不是我的问题的一部分,但erickson指出,对于Rfc2898DeriveBytes(C#的PBKDF2方法)的5000次迭代太少,建议至少50,000次。

在寻找更多信息之后,似乎50,000到1,000,000之间的迭代次数很多,但请记住,速度和安全性之间存在反比关系:随着迭代次数的增加,安全性也会提高,导出密钥所需的时间(这就是为什么它更安全)。

<强>解决方案

虽然根据erickson的说法,第一把钥匙不能用于确定第二把钥匙,但它确实使蛮力攻击变得更容易。因此,可以使用以下任何解决方案来解决此问题:

  • 生成双倍长度的密钥,并使用派生密钥的前半部分进行身份验证,后半部分进行加密。 (埃里克森)
  • 为每把钥匙使用单独的盐。
  • 在导出密钥之前,为每个添加唯一但硬编码的盐(分别为“网站”和“加密”)。此外还应使用独特的盐。(Damien_the_Unbeliever)

拒绝解决方案

  • SHA_512太快,不能保证我的安全(对于大多数使用哈希的用途)。使用多次迭代可能有所帮助,但使用诸如Rfc2898DeriveBytes之类的PBKDF2方法要安全得多。

<强>结论

感谢大家的帮助,如果您有任何进一步的见解请发表评论,我会尽力添加。

答案 2 :(得分:2)

Rfc2898DeriveBytes的两次调用之间使用不同的盐可以解决您的问题。

这样想,两个不同的用户使用相同的密码,知道一个人的哈希值是另一个吗?只有两个用户使用相同的盐!

你正在做的事情没有什么不同,只需使用两种好的盐来同时使用Rfc2898DeriveBytes,你就可以了。无需更改两种方法的迭代次数,只需更改盐即可。

没有理由需要重新使用盐,盐不是秘密信息。大多数文件加密实现都将盐(也称为IV)放在加密blob的前面。


对于您的其他解决方案“如何使用SHA作为数据库哈希,使用Rfc作为加密密钥?”这是一个非常坏主意。对数据库使用SHA意味着它们更容易获得原始密码,然后他们可以使用更简单的任务来完成解密基于Rfc的更难的任务。