BCrypt 哈希字符串如下所示:
$2a$10$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm
\__/\/ \____________________/\_____________________________/
| | Salt Hash
| Cost
Version
在哪里
2a
:算法标识符(BCrypt,UTF8 编码密码,空终止)
10
:成本因素(2 10
= 1,024 发)
Ro0CUfOqk6cXEKf3dyaM7O
:OpenBSD-Base64 编码盐(22 个字符,16 个字节)
hSCvnwM9s4wIX9JeLapehKK5YdLxKcm
: OpenBSD-Base64 编码散列(31 个字符,24 个字节)
编辑:我只是注意到这些词完全吻合。我不得不分享:
$2a$10$TwentytwocharactersaltThirtyonecharacterspasswordhash
$==$==$======================-------------------------------
BCrypt确实使用 16 字节的盐创建了一个 24 字节的二进制哈希。您可以随意存储二进制哈希和盐;没有人说您必须将其 base-64 编码为字符串。
但是BCrypt是由从事 OpenBSD 工作的人创建的。OpenBSD已经为他们的密码文件定义了一种格式:
$ [HashAlgorithmIdentifier]
$[AlgorithmSpecificData]
这意味着“bcrypt 规范”与 OpenBSD 密码文件格式密不可分。每当有人创建“bcrypt hash”时,他们总是将其转换为格式为 ISO-8859-1 的字符串:
$ 2a
$ [Cost]
$[Base64Salt][Base64Hash]
几个重要的点:
2a
是算法标识符
- 1:MD5
- 2:早期的 bcrypt,它对哪些编码密码存在混淆(已过时)
- 2a:当前 bcrypt,将密码指定为 UTF-8 编码
成本是计算哈希时使用的成本因素。“当前”值为 10,表示内部密钥设置经过 1,024 轮
- 10: 2 10 = 1,024 次迭代
- 11: 2 11 = 2,048 次迭代
- 12:2 12 = 4,096 次迭代
OpenBSD 密码文件使用的 base64 算法与其他人使用的 Base64 编码不同;他们有自己的:
Regular Base64 Alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
BSD Base64 Alphabet: ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
所以 bcrypt 的任何实现都不能使用任何内置的或标准的 base64 库
有了这些知识,您现在可以correctbatteryhorsestapler
根据保存的哈希验证密码:
$2a$12$mACnM5lzNigHMaf7O1py1O3vlf6.BA8k8x3IoJ.Tq3IB/2e7g61Km
BCrypt 变种
bcrypt 版本有很多混淆。
$2$
BCrypt 是由 OpenBSD 人设计的。它旨在散列密码以存储在 OpenBSD 密码文件中。散列密码与前缀一起存储,以识别所使用的算法。BCrypt 得到了前缀$2$
。
这与其他算法前缀形成对比:
$1$
: MD5
$5$
: SHA-256
$6$
: SHA-512
$2a$
最初的 BCrypt 规范没有定义如何处理非 ASCII 字符,或者如何处理空终止符。对规范进行了修订,以指定在散列字符串时:
- 字符串必须是 UTF-8 编码的
- 必须包含空终止符
$2x$, $2y$ (2011 年 6 月)
在crypt_blowfish中发现了一个错误, BCrypt 的 PHP 实现。这是第 8 位设置的错误处理字符。
他们建议系统管理员更新他们现有的密码数据库,用 替换$2a$
,$2x$
以表明这些哈希是错误的(并且需要使用旧的损坏算法)。他们还提出了让 crypt_blowfish$2y$
为固定算法生成的哈希值发出的想法。没有其他人,包括规范的 OpenBSD,采用2x
/的想法2y
。此版本标记仅限于 crypt_blowfish.
版本$2x$和$2y$并不比$2a$ “更好”或“更强” 。它们是 BCrypt 的一种特殊错误实现的残余。
$2b$ (2014 年 2 月)
在 BCrypt 的 OpenBSD 实现中发现了一个错误。他们用一种不支持字符串的语言编写了他们的实现——所以他们用一个长度前缀、一个指向字符的指针来伪造它,然后用[]
. 不幸的是,他们将字符串的长度存储在unsigned char
. 如果密码超过 255 个字符,它将溢出并在 255 处换行。 BCrypt 是为 OpenBSD 创建的。当他们的库中出现错误时,他们决定修改版本是可以的。这意味着如果您想保持最新的“他们的”规范,其他所有人都需要效仿。
2a、2x、2y和2b之间没有区别。如果你正确地编写了你的实现,它们都会输出相同的结果。
- 如果您从一开始就做正确的事情(将字符串存储在 utf8 中并散列空终止符),那么: 2、2a、2x、2y和2b之间没有区别。如果你正确地编写了你的实现,它们都会输出相同的结果。
- 版本$2b$并不比$2a$ “更好”或“更强” 。它是 BCrypt 的一个特殊错误实现的残余。但是由于 BCrypt 规范地属于 OpenBSD,他们可以将版本标记更改为他们想要的任何内容。
- $2x$和$2y$版本并不比任何东西更好,甚至更可取。它们是错误实现的残余 - 应该立即被遗忘。
唯一需要关心 2x 和 2y 的人是那些您在 2011 年可能一直在使用crypt_blowfish的人。唯一需要关心2b的人是那些可能一直在运行 OpenBSD 的人。
所有其他正确的实现都是相同且正确的。