首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >密码散列在中间包含“\x00”,导致来自bcrypt.hashpw的bcrypt.hashpw

密码散列在中间包含“\x00”,导致来自bcrypt.hashpw的bcrypt.hashpw
EN

Cryptography用户
提问于 2021-05-24 16:49:09
回答 3查看 2.8K关注 0票数 7

我有一些代码可以接受字符串格式的密码,并在将密码传递给bcrypt进行散列之前使用SHA3-512进行散列。然而,出于某种巧合,我发现了一个测试用例,它在哈希结果中间生成一个包含'\x00‘的散列,如下所示:

代码语言:javascript
运行
复制
password_str = 'tes15!tes15!tes15!tes15!tes15!tes15!tes15!tes15!tes15!tes15!tes15!tes15!.'
password_bytes = password_str.encode('utf-8')
hashed = hashlib.sha3_512(password_bytes).digest()

在散列中间包含'\x00‘的散列结果:

代码语言:javascript
运行
复制
b'u~"\x98\xac\xc8E2eV\xbb\x8e#}\x92R\xdc\xa2\xab\xab\xcb\x8d.~\x9f\x82a\xbf\xec]k\xdb\xc55\x1d\xa4\x00\xe8\x03\x94\xb0\x91\x14\xf0\x9ec\x9a\x9ay\xfeP\xe3\x07J\x00\xb5\xbd\xba\xcb(\xf5\xdb\xab\x1a'

正如我们所看到的,在散列的中间有一个'\x00‘,而不是在末尾。bcrypt检测到这是ValueError异常:

代码语言:javascript
运行
复制
if b"\x00" in password:
    raise ValueError("password may not contain NUL bytes")

据我所知,'\x00‘是一个保留字符和可能的攻击矢量,因为哈希长度扩展攻击。然而,我认为我并没有做任何不寻常的事情。在将散列传递给我丢失的bcrypt之前,是否有最佳做法将散列清除,或者是否有另一种类型的字节编码应该与密码一起使用?

拒绝普通密码是很奇怪的,因为它的派生散列与所使用的auth库有冲突。任何帮助或建议都是非常感谢的。谢谢!

编辑:发帖后,我在bcrypt上发现了一些描述我的问题https://github.com/pyca/bcrypt/issues/55 https://github.com/pyca/bcrypt/pull/57的问题。

EN

回答 3

Cryptography用户

回答已采纳

发布于 2021-05-24 17:09:27

您不应该在传递到bcrypt之前对其进行散列,bcrypt是为完成散列和键拉伸工作而设计的。

它对散列结果感到窒息,因为它期望一个冗余的、糊状的、ASCII (或UTF-8)、不严格的、用户输入的字符串。

一般来说,散列可能是不值得信任的,这样就可以避免各种数字漏洞(例如,Curve25519中的内部SHA-512操作来净化事物) --但是,在这种情况下,您可以信任bcrypt;它的设计是为了安全和良好地工作,当输入一个蹩脚的用户创建的密码(以及一个适当的、随机生成的盐类)。

然而,在进一步的思考中,我认为pyca/bcrypt的行为实际上是不正确的。您应该使用密码哈希函数将超过72个字节(576位)的密码转换为bcrypt可以接受的大小。这只是出于归档的目的;它仍然被设计成安全地扩展密码学上的普通密码。

通过查看他们的跟踪器上的票据,以及他们所确认的已经“修复”了它的变更集,看来这些作者并没有真正修复他们的实现的古怪行为,而只是更新了他们的文档,以推荐以下解决方法:

一种常见的方法是使用密码散列(如sha256)对密码进行散列,然后base64对其进行编码,以防止出现空字节问题(…)。

在我看来,这看起来既草率又奇怪;例如,它将限制这些摘要的输出最多为408位(使用base85 85编码),从而将>72个字节的密码截断为51个字节。我很想了解更有经验的密码学家对此的看法。

这并不否定这个答案的前半部分,但要记住这一点。显然,即使有了解决办法,该方案仍然相当安全(最好的密码方案是为了避免实现中的一些错误而设计的);将这种任意截断应用于用户的密码似乎并不完全正确,而不仅仅是bcrypt本身所应用的密码。

你可能会考虑将72字节的限制返回给你的用户,除非你不得不将较长的限制缩短至少30%,才能遵守pyca's的实现怪癖。(我相信,那些想要最大化密码熵并达到72字节限制的人,如果他们研究香肠是如何制作的,最终会更喜欢前者。)

票数 18
EN

Cryptography用户

发布于 2021-05-24 19:44:23

在将散列传递给我丢失的bcrypt之前,是否有最佳做法将散列清除,或者是否有另一种类型的字节编码应该与密码一起使用?

一个合理的方法是将哈希转换为Base64 (例如,使用标准的base64字母表),并截断到64个字符(远低于bcrypt的最常见输入大小限制,而不超过Base64中LF插入的公共阈值)。384位熵是足够的。这解决了问题的问题,还有更多的问题,包括一些bcrypt实现可以检查的畸形UTF-8。它应该确保跨实现的可移植性,这些实现至少以标准方式处理前64个字符,即使它们是否则非ASCII处理不当

0.3之前版本的jBCrypt出现了一个与字符编码相关的错误,大大降低了包含非US字符的散列密码的熵。不正确的编码步骤透明地用'?‘替换了这些字符。在哈希之前。在密码完全由非US字符组成的最坏情况下,这将导致其散列与所有其他相同长度的此类密码等效。

票数 2
EN

Cryptography用户

发布于 2021-05-25 13:25:51

bcrypt仍然被认为是一种可靠的密码散列(当与现代硬件的适当成本参数一起使用时),但是它已经相当老了,并且有很多奇怪的地方;72字节的输入限制就是其中之一。正如在其他答案中所讨论的,PyCA的绑定为绕过这一限制所做的工作在密码学上是可疑的。我建议您用argon2替换bcrypt,这是一个当前生成的密码哈希,没有任何这些奇怪之处。

票数 2
EN
页面原文内容由Cryptography提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://crypto.stackexchange.com/questions/90173

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档