移植 bcrypt.codeplex.com,具有增强的安全性、缺失的修复、功能和更好的 .net 支持。
使用 nuget 或 Paket 下载(https://fsprojects.github.io/Paket/)
包:https://www.nuget.org/packages/BCrypt.Net-Next/
签名包 - https://www.nuget.org/packages/BCrypt.Net-Next.StrongName/
我们的测试工具文件夹和单元测试中有各种示例
最简单的用法如下...
对密码进行哈希处理:
显示文件范围的命名空间;如果需要的话,想象一下大括号。
Top level namespace
namespace DotNetSix ;
using BCrypt . Net ;
string passwordHash = BCrypt . HashPassword ( "my password" ) ;
由于库的命名,如果命名空间位于 using 语句之后,则调用会更改,因为 .net 无法正确解析命名,我建议您不要输入整个命名空间,只需使用导入别名,如下所示。
using BC = BCrypt . Net . BCrypt ;
namespace DotNetSix ;
string passwordHash = BC . HashPassword ( "my password" ) ;
您还可以在 CSProj 级别执行别名操作;并且根本不需要添加 using 语句
此示例允许您在代码中使用别名 BC.HashPassword()
< ItemGroup >
<!-- emits global using BcryptNet = global::BCrypt.Net.BCrypt; -->
< Using Include = " BCrypt.Net.BCrypt " Alias = " BC " />
</ ItemGroup >
此版本允许您仅在代码库中调用Verify
和HashPassword
而无需任何其他参考。
< ItemGroup >
<!-- emits global using static global::BCrypt.Net.BCrypt; -->
< Using Include = " BCrypt.Net.BCrypt " Static = " True " />
</ ItemGroup >
注意:虽然该库允许您提供自己的盐,但强烈建议您允许该库为您生成盐。提供这些方法是为了保持兼容性以及可能需要使用它们的更高级的跨平台要求。
要根据哈希值验证密码(假设您已存储哈希值并从存储中检索以进行验证):
之前所有有关命名空间的注释也适用于此处
BCrypt . Verify ( "my password" , passwordHash ) ;
此哈希实现将自动为您生成盐,并将工作因子(2^轮数)设置为 11(与大多数实现中的默认值匹配,目前被视为良好的安全/风险级别)。
为了节省数学计算,下面提供了一个涵盖迭代的小表。为了兼容性,该库中允许的最小值为 4,最大值为 31(在 31 时,您的处理器将希望死亡)。
| Cost | Iterations |
|-------|--------------------------|
| 8 | 256 iterations |
| 9 | 512 iterations |
| 10 | 1,024 iterations |
| 11 | 2,048 iterations |
| 12 | 4,096 iterations |
| 13 | 8,192 iterations |
| 14 | 16,384 iterations |
| 15 | 32,768 iterations |
| 16 | 65,536 iterations |
| 17 | 131,072 iterations |
| 18 | 262,144 iterations |
| 19 | 524,288 iterations |
| 20 | 1,048,576 iterations |
| 21 | 2,097,152 iterations |
| 22 | 4,194,304 iterations |
| 23 | 8,388,608 iterations |
| 24 | 16,777,216 iterations |
| 25 | 33,554,432 iterations |
| 26 | 67,108,864 iterations |
| 27 | 134,217,728 iterations |
| 28 | 268,435,456 iterations |
| 29 | 536,870,912 iterations |
| 30 | 1,073,741,824 iterations |
| 31 | 2,147,483,648 iterations |
etc
您可以通过创建控制台程序、添加此 BCrypt 库并使用此代码来运行一个简单的基准测试。
var cost = 16 ;
var timeTarget = 100 ; // Milliseconds
long timeTaken ;
do
{
var sw = Stopwatch . StartNew ( ) ;
BCrypt . HashPassword ( "RwiKnN>9xg3*C)1AZl.)y8f_:GCz,vt3T]PI" , workFactor : cost ) ;
sw . Stop ( ) ;
timeTaken = sw . ElapsedMilliseconds ;
cost -= 1 ;
} while ( ( timeTaken ) >= timeTarget ) ;
Console . WriteLine ( "Appropriate Cost Found: " + ( cost + 1 ) ) ;
Console . ReadLine ( ) ;
这将从 16 开始,即65,536 iterations
,并降低成本,直到达到时间目标。这取决于您认为允许的时间,但如果它低于 10,我强烈建议将其保留在 10,并且可能投资更大的服务器包。
bcrypt 建议的 56 字节密码限制(包括空终止字节)与 Blowfish 密钥的 448 位限制相关;超出该限制的任何字节都不会完全混合到哈希中,因此考虑到这些字节对生成的哈希的实际影响,bcrypt 密码的 72 字节绝对限制不太相关。
其他语言通过预先散列密码短语/密码以增加使用的熵来处理这个感知问题,dropbox 是这方面较为公开的文章之一。
您只需使用以下代码即可选择增强哈希(基本上在方法调用前加上“增强”前缀)
var enhancedHashPassword = BCrypt . EnhancedHashPassword ( myPassword ) ;
var validatePassword = BCrypt . EnhancedVerify ( myPassword , enhancedHashPassword ) ;
默认情况下,该库使用密码的 SHA384 哈希,然后将生成的材料传递给 bcrypt,通过通常的 bcrypt 例程形成哈希。如果您想指定不同版本的 SHA,或者只是希望在代码中显式设置所使用的版本,以防它在库的主要版本中发生更改,您可以通过对上述内容进行以下更改来实现。
var enhancedHashPassword = BCrypt . EnhancedHashPassword ( myPassword , hashType : HashType . SHA384 ) ;
var validatePassword = BCrypt . EnhancedVerify ( myPassword , enhancedHashPassword , hashType : HashType . SHA384 ) ;
为什么选择 SHA384?它在性能、安全性、碰撞保护之间取得了良好的平衡,并且是唯一不易受到长度扩展攻击的版本 https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash -长度扩展攻击。
我应该使用增强熵吗?使用它你不会有任何损失
为什么需要更改 SHA 类型?有些库(例如 PassLib 哈希)使用 SHA256,所以主要是兼容性问题。 DropBox 使用 SHA512,因此如果您在 Dropbox 工作,您会需要兼容性。增强主要是一种方便的扩展,因为您已经可以预先哈希并传递到标准方法调用中。
它有什么作用?我们将密码的 utf8 字节作为 inputBytes SHA 对它们进行哈希处理,转换为 base64(为了与其他语言实现兼容),然后使用这些字节执行标准 bcrypt 调用。
您至少需要 VS2022 以及当前的 SDK https://www.microsoft.com/net/download;
nuget 包可以通过运行buildfornuget.cmd
或
dotnet restore . s rc
dotnet pack . s rc B Crypt.Net --configuration Release
您可以通过键入dotnet test .srcBCrypt.Net.UnitTests
运行TestGenerateSaltWithMaxWorkFactor
将花费大量时间。
用 C# 实现的 jBCrypt 的 .Net 端口。它使用 Blowfish 加密算法的密钥计划的变体,并引入工作因子,使您可以确定哈希函数的成本,从而使算法“面向未来”。
出于所有意图和目的,这是由 Damien Miller 编写的 jBCrypt 的直接移植。主要区别是添加了一些便捷方法和一些温和的重构。验证 BCrypt.Net 与 jBCrypt 同等性的最简单方法是比较单元测试。
有关 BCrypt 为何如此重要的概述,请参阅如何安全地存储密码。一般来说,它是一种哈希算法,可以随着时间的推移进行调整,以需要更多的 CPU 能力来生成哈希值。从本质上讲,这提供了一些针对摩尔定律的保护。也就是说,随着计算机变得更快,可以调整该算法以需要更多的 CPU 能力。哈希给定密码所需的 CPU 能力越多,“黑客”必须为每个密码投入的时间就越多。由于“工作因子”嵌入到结果哈希中,因此该算法生成的哈希是前向/后向兼容的。
它使用 Blowfish 加密算法的密钥调度的变体并引入工作因子,使您可以确定哈希函数的成本。正因为如此,BCrypt才能跟上摩尔定律。随着计算机变得越来越快,您可以增加工作因素,并且哈希会变得更慢。
Niels Provos 和 David Mazières 基于 Blowfish 设计了一个名为 bcrypt 的 crypt() 方案,并于 1999 年在 USENIX 上提出。 [14]
这些哈希值的可打印形式以
$2$ – Currently obsolete
$2a$ – The current key used to identify this scheme.
Since a major security flaw was discovered in 2011 in a third-party implementation of the algorithm,
hashes indicated by this string are now ambiguous and might have been generated by the flawed
implementation, or a subsequent fixed, implementation.
The flaw may be triggered by some password strings containing non-ASCII characters, such as specially
crafted password strings.
$2b$ – Used by some recent implementations which include a mitigation to a wraparound problem.
Previous versions of the algorithm have a problem with long passwords. By design, long passwords
are truncated at 72 characters, but there is an 8-bit wraparound problem with certain password
lengths resulting in weak hashes.
$2x$ – Post-2011 bug discovery, old hashes can be renamed to be $2x$ to indicate that they were generated with
the broken algorithm. These hashes are still weak, but at least it's clear which algorithm was used to
generate them.
$2y$ – Post Post-2011 bug discovery, $2y$ may be used to unambiguously use the new, corrected algorithm. On an
implementation suffering from the bug, $2y$ simply won't work. On a newer, fixed implementation, it will
produce the same result as using $2a$.
首先也是最重要的是,这个库起源于mindrot
的 jBCrypt 端口,随后 bcrypt 版本被设置为匹配,在本例中为$2a$
。这已被更改,因为仅处理单个修订版会导致跨平台问题,而实现则更改了其修订版以处理迁移和其他问题。
The original bcrypt code (released in OpenBSD 2.1) identified itself as
$2$. Shortly after release, a bug was fixed and the hash identifier
changed to $2a$. Support for "minor" versions wasn't really
planned, but it was backwards compatible.
Solar Designer wrote a second implementation of bcrypt. This
reimplementation suffered from a flaw dealing with 8 bit characters
and led to the introduction of the 'x' and 'y' flavours. OpenBSD did
not have this problem and supports neither 'x' nor 'y' hash versions.
---
Solar found a bug in their OpenBSD implementation of bcrypt when hashing
long passwords. The length is stored in an unsigned char type, which
will overflow and wrap at 256. Although we consider the existence of
affected hashes very rare, in order to differentiate hashes generated
before and after the fix, we are introducing a new minor 'b'.
OpenBSD 5.5 (coming this spring) will accept and verify 'b' hashes,
although it will still generate 'a' hashes. OpenBSD 5.6 (coming this
fall) will change to generating 'b' hashes by default.
A future release of Solar's bcrypt code should also support 'b'.
2a、2x、2y 和 2b 之间没有区别。它们都输出相同的结果。
发行说明位于 https://github.com/BcryptNet/bcrypt.net/releases
v4.0.3 - 添加了 .net 6 目标;整理目标。
v4.0.2 - 添加了 .net 5 目标;将shaxxx
创建包装在 using 中来发布。
v4.0.0(重大更改) - 发现Enhanced Hashing
中的一个错误,导致创建的哈希在不同语言之间无法操作。 V4 提供了此问题的修复,并添加了来自 PHP 和 Python 的测试向量,以确保该问题在未来得到解决。 V4 还删除了添加 Base64 之前的旧 384 选项。
v3.5.0 - 发现Enhanced Hashing
中的一个错误,导致创建的哈希在不同语言之间无法操作。作为修复的一部分,3.5 版本包含了Verify
功能,并且为HashPassword
提供了额外的v4CompatibleEnhancedEntropy
参数。这允许用户正常验证其增强型哈希;然后使用V4重新散列+存储。此功能纯粹是为了允许迁移,在 V4 中被删除。
v3.3.3 -netcore 的性能(堆减少)和删除正则表达式 https://github.com/BcryptNet/bcrypt.net/releases/tag/3.3.0
v2.1.3 -
v2.1.2 -
PasswordNeedsReshash
中的拼写错误更正为PasswordNeedsRehash
v2.1.1 -
v2.1.0 -
PasswordNeedsReshash(string hash, int newMinimumWorkLoad)
作为开发人员在用户登录时使用的辅助方法,以增加旧工作负载ValidateAndReplacePassword
方法以允许内联密码验证和替换。如果身份验证失败,则抛出BcryptAuthenticationException
。v2.0.1 -
v2.0.0 -
为大多数 .net 打包的新版本并包含安全等于,以降低计时攻击的风险 https://en.wikipedia.org/wiki/Timing_attack / https://cryptocoding.net/index.php/Coding_rules#Compare_secret_strings_in_constant_time从技术上讲,BCrypt 的实现细节理论上可以减轻定时攻击。但Bcrypt.net官方验证函数很容易受到定时攻击,因为一旦在哈希比较中发现不匹配的字节,它就会返回。