我今天在忙于bcrypt,发现了一些问题:

hashpw('testtdsdddddddddddddddddddddddddddddddddddddddddddddddsddddddddddddddddd', salt)
Output: 'a$jQYbLa5m0PIo7eZ6MGCzr.BC17WEAHyTHiwv8oLvyYcg3guP5Zc1y'

hashpw('testtdsdddddddddddddddddddddddddddddddddddddddddddddddsdddddddddddddddddd', salt)
Output: 'a$jQYbLa5m0PIo7eZ6MGCzr.BC17WEAHyTHiwv8oLvyYcg3guP5Zc1y'


bcrypt是否具有最大密码长度?

#1 楼

是的,bcrypt具有最大密码长度。原始文章包含以下内容:


key参数是一个秘密加密密钥,它可以是用户选择的密码,最大为56个字节(当密钥为0时,包括一个终止的零字节)。一个ASCII字符串)。


所以可以推断出输入密码的最大长度为55个字符(不计算结尾的零)。请注意,ASCII字符:通用Unicode字符以UTF-8编码时,最多可以使用四个字节;字形的视觉概念可能包含无限数量的Unicode字符。如果将密码限制为纯ASCII,您将省去很多麻烦。

但是,实际限制上有相当多的困惑。有人认为,“ 56字节”的限制包括4字节的盐,导致下限为51个字符。其他人指出,该算法在内部将18个32位字管理起来,总共72个字节,因此您可以输入71个字符(如果不使用零结尾的字符串,则可以输入72个字符)。

实际的实现方式会有一个限制,具体取决于实现者在上述所有方面的信奉和执行。所有体面的实现都将至少允许您使用50个字符。除此之外,不能保证支持。如果您需要支持长度超过50个字符的密码,则可以添加一个初步的哈希步骤,如本问题所述(但是,当然,这意味着您不再计算“ the” bcrypt,而是本地变量,因此互操作性就可以了)下水道)。

编辑:已经向我指出,尽管从密码学家的角度来看,这篇文章是最终的参考,但这并不一定是设计者的想法。 “原始”实现最多可以处理72个字节。根据您对形式主义的立场,您可能会声称实施正确,文章错误。无论如何,这是我的建议仍然有效的当前状态:如果您的字符数少于50个,那么到处都可以。 (当然,如果算法首先没有长度限制,那就更好了。)

评论


我懂了。我读了一篇文章(实际上是在这里),它建议使用服务器端密钥以及实际的密码和盐来生成哈希。您会建议什么作为密钥长度,或者对于这种用途,我是否应该首先通过crypt这样的哈希,然后通过bcrypt对其进行哈希加密?

– d0ctor
13年7月31日在13:38



附加的密钥通常称为“抢劫”。正确的方法是使用秘密密钥作为MAC密钥来计算密码上的MAC(使用HMAC / SHA-256);然后将MAC输出用作bcrypt中的“密码”。 HMAC / SHA-256产生32个字节,可以在bcrypt的限制内使用Base64将其转换为44个ASCII字符。而且,HMAC将处理任意长密码,从而也解决了密码长度问题。请注意,使用密钥意味着密钥管理问题,这可能很棘手(例如,它会干扰备份和多前端系统)。

–汤姆韭菜
13年7月31日在13:50

根据目前的一些测试,Java bcrypt库jBCrypt的字符数限制为72个。

–肯尼·埃维特(Kenny Evitt)
13年10月10日在19:44

这是一个思想和问题,同时存在:为什么不将密码的长度分为任何可管理的长度(72字节(不是72个字符)),然后使用bcrypt对每个块进行哈希处理,然后将结果结合起来,可以得到更多的结果。更长的时间,可能没问题,或者我们也可以使用sha512对其进行哈希处理。它更慢,但适用!你怎么看 ?

–穆罕默德·阿拉(Mohamed Allal)
18年5月7日在10:52

#2 楼

tl; lr:BCrypt限制为72个字节,而不是56个字节。
背景
BCrypt限制为72个字节。原始文件还提到了空终止符的使用。这意味着您通常将限于:

71个字符+ 1个字节的空终止符

,但是BCrypt 2a修订版指定使用UTF-8编码(而原始白皮书指的是到ASCII)。使用UTF-8时,一个字符并不表示一个字节,例如:

Noël是四个字符,但是五个字节(N o e ¨ l
💩是一个字符,但是四个字节(F0 9F 92 A9
M̡̢̛̖̗̘̙̜̝̞̟̠̀́̂̃̄̅̆̇̉́̋̌̍̎̏̐̑̒̓̔̕̚是一个字符,但是74个字节(包括空终止符)

所以这把扳手扔进了您允许多少个“字符” 。
55或56从何而来?
原始白皮书提到最大密钥长度为56个字节:

最后,key参数是秘密加密密钥,可以是用户选择的最多56个字节的密码(当密钥是ASCII字符串时,包括一个终止的零字节)。

基于Blowfish推荐的最大密钥长度448位,这是一个误解。 (448/8 = 56字节)。 bcrypt源自的Blowfish加密算法的最大密钥大小为448位。摘自Bruce Schneier在1993年的原始论文中对新的可变长度密钥64位块密码(Blowfish)的描述:

块大小为64位,并且密钥可以是任何长度,最大为448位。

另一方面,bcrypt算法可以(并且确实)支持最多72个字节的密钥,例如:

71×8位字符+ 1 ×8位空终止符


72个字节的限制来自Blowfish P-Box的大小,即18个DWORD(18×4字节= 72字节)。来自原始的bcrypt白皮书:

Blowfish是一种64位块密码,结构为16轮Feistel网络[14]。它使用从加密密钥派生的18个32位子密钥P1,...,P18。子项被统称为P-Array

规范的OpenBSD实现将截断超过72个字节的任何键。
这意味着,如果您的UTF8字符串超过72个字节,它将被截断。被截断为72个字节。
警告:

此截断将删除空终止符
该截断甚至会在中间字符(对于多代码点字符)发生

例如,如果您的密码结尾为:

“…装订器”“

BCrypt的UTF-8编码为:
    ══╤══╤═══╤═══╤═══╤═══╤═══╤═════╤═════╤═════╗        
... 63│64│ 65│ 66│ 67│ 68│ 69│ 70  │ 71  │ 72  ║ 73   74
    s │ t│ a │ p │ l │ e │ r │ 0xF0│ 0x9F│ 0x92║ 0xA9 
    ══╤══╤═══╤═══╤═══╤═══╤═══╤═════╤═════╤═════╗
... 63│64│ 65│ 66│ 67│ 68│ 69│ 70  │ 71  │ 72  ║
    s │ t│ a │ p │ l │ e │ r │ 0xF0│ 0x9F│ 0x92║
    ══╧══╧═══╧═══╧═══╧═══╧═══╧═════╧═════╧═════╝
══╧══╧═══╧═══╧═══╧═══╧═══╧═════╧═════╧═════╝ | cutoff

这意味着在规范的OpenBSD实现中,字节在字符中间被切断(即使它留下无效的utf-8字节序列):
BCrypt.EnhancedHashPassword("correct battery horse staple Noël 💩 M̡̢̛̖̗̘̙̜̝̞̟̠̀́̂̃̄̅̆̇̉̊̋̌̍̎̏̐̑̒̓̔̕̚");

摆脱掉最大长度
近年来,密码哈希算法不应有任何最大限​​制已被认为是一个好主意。但是允许客户端使用无限制的密码存在一个问题:

由于有人提交了数千兆字节的密码,因此引入了拒绝服务攻击。这就是为什么现在,使用SHA2-256之类的东西来预哈希用户密码已变得很普遍。生成的base-64编码字符串,例如:

n4bQgYhMfWWaL + qgxVrQFaO / TxsrC4Is0V1sFbDwCgg =

只能是44个ASCII字符(45个带空终止符)。 >这是DropBox采取的方法,并包含在bcrypt.net中:
q4312078q
这意味着您昂贵的哈希算法不会导致您拒绝服务。

#3 楼

是的,BCrypt的上限为72个字符。这是河豚密码本身的局限性。解决该问题的一种方法是先使用SHA-256,然后使用BCrypt结果。就您而言,它就像是

hashpw(sha256('pass'), salt)


评论


根据stackoverflow.com/a/16597402/313113的说法:“首先通过散列操作,您并不会真正帮助很多使用长密码的人。某些组您绝对可以提供帮助。某些组您肯定可以受到伤害。”

–user6059
2014年7月7日12:43

最好警告它太长,然后截断它。

–橙色狗
16年7月26日在16:50

为什么?对于使用长单词列表的人,sha256仍然很棒。您甚至可以使用sha384和base91作为输入来获得更多字节,并且您仍然不会超过甚至很长的wordlist型密码所具有的熵。或者您可以使用sha512,base91来截断7个字符,但仍然剩下约472位熵。尤其是在单词列表密码越来越流行的情况下,因为这是创建安全但仍令人难忘的PWS网站的好方法,应该准备好长密码。

– My1
16 Dec 19'0:32