C#密码散列和验证的参考实现
鉴于您的新“政府批准”要求,我猜一个好的解决方案是RFC 2898中的 PBKDF2 。它是在Rfc2898DeriveBytes Class (System.Security.Cryptography)中为 .NET 实现的。您大概想在那里用 SHA-256 代替 SHA-1。
我也刚刚遇到了相当安全的哈希密码:fshp,它类似于 PBKDF1,但默认使用 SHA-256。它支持可变数量的迭代,默认为 4096。它使用 64 位盐。他们在那里实现了 .NET、Python、Ruby、Perl、PHP5、Java 和 JavaScript。
正如.net impl of bcrypt - Stack Overflow所描述和讨论的那样,对于 .NET/CLR 来说,另一个不错的选择(尽管未经 NIST 批准)似乎是 BCrypt.net:
对于 Java,一个不错的选择是
我想两者似乎都没有“胡椒”概念,也没有 scrypt 的空间复杂性。
基础
基本方法是Hash(secret | salt),它与盐一起存储。显然,使用像 SHA2 变体之一这样的现代哈希算法很重要(尽管目前 SHA1 并没有像 MD5 那样完全被破坏)。请注意,如果您以这种方式存储挑战问题,您可能希望在对其Trim()进行ToLower()散列之前存储秘密。这可能会在一定程度上降低复杂性,但安全问题并不打算像密码那样具有高熵。
像彩虹表这样的蛮力攻击呢?
可以通过两种方式减轻对暴力攻击的担忧:
- 要求密钥中的最小熵(长度、复杂性等)。
- 增加执行散列所需的计算量。
中使用的方法bcrypt是对标准散列的一个很好的改进,因为它将计算散列的时间增加了许多数量级。基本上,它只是多次迭代地散列秘密: Hash(Hash(...Hash(secret | salt)...))
由于时间量仍然相对较小(数百毫秒),因此不会给合法用户增加无法忍受的延迟。但它可以破坏自动蛮力攻击。
这还不够好
如果 的附加难度bcrypt不足,请尝试scrypt。它的工作原理类似bcrypt,但需要将每个迭代哈希保存在内存中,以便在最后进行最终合并。这增加了与时间复杂度相同的时间复杂度,bcrypt但也增加了空间复杂度,使其更难以在硬件中实现,尤其是并行实现。
执行
老实说,我不知道有一个 C# 库来实现这一点,更不用说某个官方机构的“认证”了,但这不会太难。假设您编写线程安全代码,并且密码验证发生在受信任的系统(如服务器)上,则可以最大限度地减少侧信道攻击等实现问题。
进一步阅读:这个答案是BCrypt 是一个在 C# 中使用的好的加密算法吗?我在哪里可以找到它?
.Net 答案:
根据这篇文章,来自.Net Cryptography命名空间的所有-Cng和-CryptoServiceProvider后缀实现都应该经过 FIPS 认证,而不是 -Managed 版本。
缺点:
- 较旧的 .Net Framework 版本不支持它们(请检查每个版本的“适用于”部分以确保)。
- 较旧的操作系统版本可能不支持它们。
好处:
- 它们已通过 FIPS 认证
- 哈希算法使用 bcrypt