PasswordDeriveBytes 与 Rfc2898DeriveBytes,已过时但速度更快

Posted

技术标签:

【中文标题】PasswordDeriveBytes 与 Rfc2898DeriveBytes,已过时但速度更快【英文标题】:PasswordDeriveBytes vs Rfc2898DeriveBytes, Obsolete but way faster 【发布时间】:2010-11-24 07:43:13 【问题描述】:

我正在开发基于继承自 SymmetricAlgorithm 的类(例如 TripleDes、DES 等)的加密功能。

基本上有两个选项可以为我的算法类PasswordDeriveBytesRfc2898DeriveBytes 生成一致的密钥和IV,它们都继承自DeriveBytes 抽象类。

PasswordDeriveBytes.GetBytes() 方法在 .NET 框架中被标记为已过时,而推荐使用 Rfc2898DeriveBytes.GetBytes(),因为它符合 PBKDF2 标准。但是,根据我的测试,在 Rfc2898DeriveBytes 类中调用相同的 GetBytes() 方法几乎比在 PasswordDeriveBytes 类中慢 15 倍,这会导致意外的 CPU 使用率(总是高于 50%)。

以下是一些测试数据:

迭代次数:100 算法类型:DES 原文:“我是测试密钥,请给我加密” 时间: PasswordDeriveBytes:99 毫秒 Rfc2898DeriveBytes:1,373 毫秒

经测试,Rfc2898DeriveBytes 的不良性能在生产环境中是不能接受的。

以前有人注意到这个问题吗?任何解决方案我仍然可以使用标准解决方案而不会影响性能?使用过时的方法是否有风险(可能在未来的版本中删除)?

谢谢大家!

编辑:

可能我发现问题出在哪里...PasswordDeriveBytes 的默认迭代计数为 100,而Rfc2898DeriveBytes 的默认迭代计数为 1000。我将它们更改为与 1000 相同的数字后,执行 Rfc2898DeriveBytes 仅双倍时间。

【问题讨论】:

您打算多久在生产环境中派生一次密钥?而且,关于您的计时数据,当您说“100 次迭代”时 - 是对 onee 键的迭代,还是您生成了 100 个键。任何基于 100 次试验的性能数据都是可疑的,但我认为您实际上测试了 ONE 试验。与所有性能分析案例一样,根据单个试验的响应时间得出有关服务器性能的结论是不合适的。 @Cheeso 该测试只是对这两个类的性能的单元测试,并没有在真实的应用程序中完成。我提到的“100 次迭代”有点令人困惑,这仅意味着我将它们中的每一个都执行了 100 次。这不是真正的性能测试,而只是比较。 我认为您可能错过了Rfc2898DeriveBytes 的基本原理设计 速度较慢,因此密码哈希检查(每次登录时进行,因此很少进行)不会'在蛮力攻击时注意到性能受到影响。如果您需要生成大量哈希,Rfc2898DeriveBytes 不适合您,但如果您需要一些安全性以防止暴力攻击,那么它是。 虽然大家一致认为Rfc2898DeriveByes 的设计速度较慢,但​​我很难相信您的性能测试的可靠性。简单地迭代一段代码一百次肯定不是进行可靠微基准测试的正确方法。 【参考方案1】:

我认为您缺少派生字节的意义。它应该是缓慢的。它故意使用无法通过巧妙的技巧加速的慢速算法。典型的“迭代次数”参数应在 2^16-2^20 范围内,并在用户输入密码和生成密钥之间引入 0.1-0.5 秒的延迟。目的是防御“懒惰无知的用户”选择的弱密码并减慢暴力搜索。

【讨论】:

【参考方案2】:

它们不是一回事。

Rfc2898DeriveBytes 是 PBKDF2 的实现。 PasswordDeriveBytes 是 PBKDF1 的实现。与 PBKDF1 相比,PBKDF2 使用不同的方法和更多的轮数生成不同的输出。

用于密钥派生的密码散列函数(例如这些)应该很慢。这就是重点——这让它们更难破解。

这两个函数不兼容,PasswordDeriveBytes 也没有那么安全。

【讨论】:

感谢 BlackAura。我可以理解 PBKDF2 实现应该很慢,但是没有使用 Rfc2989DeriveBytes 类的最佳实践,例如如何缓存/重用相同的密钥/IV?在生产环境中多次运行一个方法是不可接受的。 :P 通常,您只想使用这些函数从密码生成密钥。通常用于受密码保护的存档或类似的东西。要加密存档,您将生成一个随机 IV,并从密码和 IV 生成一个密钥。您存储 IV(但从不存储密钥)。然后,您可以为存档中的每个文件重新使用密钥,只要每个文件都使用不同的 IV 加密(也存储在存档中)。这些函数的唯一其他用途是密码散列。您只需在用户登录时执行此操作。对于任何其他用途,可能有更好的方法。【参考方案3】:

这篇博文讨论了两者的区别:http://blogs.msdn.com/shawnfa/archive/2004/04/14/generating-a-key-from-a-password.aspx

【讨论】:

十亿,这真的很有帮助! :)

以上是关于PasswordDeriveBytes 与 Rfc2898DeriveBytes,已过时但速度更快的主要内容,如果未能解决你的问题,请参考以下文章

C# 版本的 OpenSSL EVP_BytesToKey 方法?

RFC文档:官网中文RFC文档与DNS相关的RFC文档

SAP的RFC接口的发布与JAVA调用

Docker 标记与 RFC 5424 中的哪些字段相关

当相对 URI 包含空路径时,Java 的 URI.resolve 是不是与 RFC 3986 不兼容?

RFC中文文档