.NET:PasswordDeriveBytes 和 Rfc2898DeriveBytes 之间的区别

Posted

技术标签:

【中文标题】.NET:PasswordDeriveBytes 和 Rfc2898DeriveBytes 之间的区别【英文标题】:.NET: Difference between PasswordDeriveBytes and Rfc2898DeriveBytes 【发布时间】:2011-10-28 21:49:51 【问题描述】:

我正在尝试理解一些 C# 代码,我已经收到了,它处理密码学,特别是使用来自 System.Security.CryptographyPasswordDeriveBytes

在.NET docs 中,它说PasswordDeriveBytes 使用“PBKDF1 算法的扩展”,该算法稍后在文档中指定为“PKCS#5 v2.0 标准”,即 PBKDF2(就我可以告诉)。但是,我在网上找到的任何地方(包括 Stack Exchange 上的此处)都说“使用 Rfc2898DeriveBytes,因为不推荐使用 Password* 并使用 PBKDF1”。但msdn.microsoft.com 文档中的唯一区别似乎是 Rfc*-version 专门提到了 PBKDF2,其中 Password* 表示“PBKDF1 的扩展”和“PKCS#5 v 2.0”。

那么,谁能告诉我这两个类之间有什么区别(如果有的话)以及为什么我应该使用一个而不是另一个来进行 PBKDF2 密码密钥派生?

现在,处理相同数据的其他代码明确使用 PBKDF2,并且可以工作,因此这表明 PasswordDeriveBytes 确实也使用 PBKDF2,或者 PBKDF2 在某些情况下只是与 PBKDF1 兼容,但我想要要确定这不是一些随机事物的副作用,并且事情只是神奇地起作用(最终可能会神奇而壮观地破坏),而没有人真正理解为什么。

【问题讨论】:

【参考方案1】:

如果您实例化 PasswordDeriveBytes 并对 GetBytes 方法进行一次调用,并传递一个小于底层摘要算法输出大小的值,那么您会从 PBKDF1 算法中返回一个值。

如果您为同一个对象两次调用 GetBytes,您可能会在实现中遇到计数错误。

PBKDF1 仅被描述为输出最大哈希算法的大小(例如 SHA-1 为 20 个字节),但 PasswordDeriveBytes 类已组成一个公式以支持高达 1000 倍的哈希输出大小。所以这个类产生的大值可能在另一个平台上是不容易实现的。


如果您实例化Rfc2898DeriveBytes,您将获得PBKDF2 算法的流式实现。 PBKDF2 与 PBKDF1 最明显的区别是 PBKDF2 允许生成任意数量的数据(限制为(2^32-1)*hashOutputSize;或者对于 SHA-1 85,899,345,900 字节)。 PBKDF2 还使用了更复杂的结构(特别是 HMAC 而非直接摘要),使得从输出值中恢复输入密码更加困难。

实现中的“流”是GetBytes(5)GetBytes(3)的串联与GetBytes(8)相同。与 PasswordDeriveBytes 不同,这在 Rfc2898DeriveBytes 中可以正常工作。


PBKDF1 最初是为生成 DES 密钥而创建的,于 1993 年发布于 PKCS #5 v1.5。 PBKDF2 于 1999 年在 PKCS #5 v2.0(重新发布为 RFC2898)中发布。应该在 ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-5v2/pkcs5v2-0.pdf 找到的幻灯片(但似乎有问题,所以 ftp://ftp.dfn-cert.de/pub/pca/docs/PKCS/ftp.rsa.com/99workshop/pkcs5_v2.0.ppt 可能需要做)进一步总结差异。 (幻灯片由 RSA Security 编写,PBKDF1 和 PBKDF2 的创建者,他们是推荐 PBKDF2 而不是 PBKDF1 的人)。

【讨论】:

【参考方案2】:

我认为在这里可以找到一个很好的答案:

C# PasswordDeriveBytes Confusion

但是总结一下:

Microsoft 对原始 PKCS#5(又名 PBKDF1)的实现包括不安全的扩展,以提供比散列函数所能提供的更多的字节(请参阅此处和此处的错误报告)。

即使它没有错误,您也应该避免对标准进行未记录的专有扩展(或者您将来可能永远无法解密您的数据 - 至少不能在 Windows 之外。)

我强烈建议您使用更新的 Rfc2898DeriveBytes,它实现了自 .NET 2.0 起可用的 PBKDF2 (PKCS#5 v2)。

【讨论】:

【参考方案3】:

这是一篇详细介绍差异的博文:

http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/generating-a-key-from-a-password.aspx

PBKDF2 可用于生成任意长度的密钥,这对于基于密码的加密非常有用(它可以根据对称密码的要求生成任意长度的密钥),但对于安全密码来说意义不大贮存。它还使用 HMAC 来应用盐,而不是像 PBKDF1 那样的串联,这在弱盐的情况下具有更好的安全性。

【讨论】:

是的,我问的不是 1 和 2 之间的区别,而是两个特定 .NET 类之间的区别。 :) 其中一个实现 1,而另一个实现 2 :) 那么什么是“扩展”?【参考方案4】:

PKCS#5 v2.0 定义了 PBKDF1 和 PBKDF2,前者是出于向后兼容性的原因,建议您将 PBKDF2 用于新应用程序。我不知道为什么后者比前者更好,但是这两个 .NET 类似乎确实使用了不同但可互操作的算法。 (可能是因为只交换结果密钥,而不是输入 + KDF。)

【讨论】:

不一定,您仍然可以包含输出数据使用的加密方案/KDF,并且您提到的“其他代码”是确定加密方案使用 PBKDF2 后使用的代码路径。不能仅仅从“明确使用 PBKDF2”中分辨出来。

以上是关于.NET:PasswordDeriveBytes 和 Rfc2898DeriveBytes 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

C# 版本的 OpenSSL EVP_BytesToKey 方法?

.NET和.NET Framework的关系

仅在 Windows 上:net5.0-windows(或 net6.0-windows)是不是允许我在 .Net 5(或 .Net 6)中重新编译 .Net 框架?

.NET平台系列26:在 Windows 上安装 .NET Core/.NET5/.NET6

[.NET大牛之路 005] .NET 的执行模型

ADO.NET和.NET的关系?