BCRYPT 是否应该用于客户端密码散列

信息安全 密码 哈希 bcrypt
2021-08-15 11:03:30

我担心使用 bcrypt 生成客户端密码。我正在开发一个在客户端使用的密码生成功能,类似于 PwdHash 和 PasswordMaker。

关于使用 bcrypt 相对于更快的哈希函数的优势已经说了很多,因为它可以减慢蛮力攻击。我知道 bcrypt 在内部使用 Blowfish,这是一种对称加密算法,而不是哈希算法。所以在某处必须有一个硬编码的密钥才能使用 bcrypt,而且由于使用的是 Blowfish,所以按道理如果发现了密钥,则可以反转密码推导并发现原始密码。

由于客户端代码可以反编译,密钥很容易被发现,使得 bcrypt 在客户端使用不安全。我的推理是正确的还是我错过了什么?

此外,在一个相关问题中,同样的论点在服务器端也不是有效的。散列函数不能反转,但如果密钥已知,加密函数可以反转。使用真正的哈希服务器端不是更安全吗,即使它更快,因此更容易受到暴力攻击,而不是使用可逆的 bcrypt?

编辑:user10008 下面的注释(帖子已被删除)只有部分 Blowfish 用于 bcrypt 并给了我一个链接。当我点击一个链接时,我发现了一个函数原型,其中包含 key 作为最后一个参数。所以我仍然看到用于启动 bcrypt 算法的密钥。如果需要密钥,并且 bcrypt 使用对称加密而不是散列,那么操作不是可逆的吗?

编辑:来自 martinstoeckli 和 user10008 的好答案。由于响应中的最后一句话,我给了marginstoeckli的答案:

BCrypt可以被视为通过丢弃密钥进行加密。

这真的为我清除了它。基本上,我们经历了两个阶段

P -> K ;P,K -> C

然后丢弃密钥 K,留下密文 C。因为我们丢弃了密钥 K,我们无法解密回明文 P。丢弃 K 有效地使 bcrypt 成为单向函数。

编辑:从 user10008 开始,我上面给出的步骤更复杂,但本质是密钥 K 在最后阶段使用并被丢弃。感谢用户 10008。

4个回答

恰恰相反,BCrypt 不使用密钥加密密码,而是使用密码作为密钥来加密已知文本。在生成密钥的设置中,它使用盐和密码(变量EksBlowfishSetup.key)来生成bcrypt.state用于加密的密钥(变量)。

bcrypt(cost, salt, input)
    state \gets EksBlowfishSetup(cost, salt, input)
    ctext \gets "OrpheanBeholderScryDoubt" //three 64-bit blocks
    repeat (64)
        ctext \gets EncryptECB(state, ctext) //encrypt using standard Blowfish in ECB mode
    return Concatenate(cost, salt, ctext)

EksBlowfishSetup(cost, salt, key)
    state \gets InitState()
    state \gets ExpandKey(state, salt, key)
    repeat (2cost)
        state \gets ExpandKey(state, 0, key)
        state \gets ExpandKey(state, 0, salt)
    return state

BCrypt 可以看作是通过丢弃密钥进行加密。

Bcrypt 是不可逆的。您可以在客户端和服务器端使用它。

密钥不是静态的,而是取决于函数调用生成的密码EksBlowfishSetup(cost, salt, input)明文是已知且公开的,其"OrpheanBeholderScryDoubt". 如果你想找回密钥,你需要对 64-times-blowfish 进行已知明文攻击,这非常困难,然后你仍然只能得到密钥,而不是密码。

维基百科给出了算法的伪代码概述bcrypt

 bcrypt(cost, salt, input)
     state ← EksBlowfishSetup(cost, salt, input)
     ctext ← "OrpheanBeholderScryDoubt" //three 64-bit blocks
     repeat (64)
         ctext ← EncryptECB(state, ctext) //encrypt using standard Blowfish in ECB mode
     return Concatenate(cost, salt, ctext)

编辑补充:事实证明我写的是正确的,但这不是对所提问题的回答。我道歉。

从客户端发送到服务器的任何内容都是密码,无论它是经过散列、切片还是切块。在客户端上散列的密码并不比未散列的相同字符串更安全。如果它被拦截,它可以用于任何一种情况下的重放攻击。

重要的是确保密码以加密方式传输,例如使用 SSL/TLS。

看看这个以获得更全面的解释:https : //crackstation.net/hashing-security.htm

通常的做法是在客户端使用任何散列算法,例如 SHA-2。为了稍微提高安全性,可以使用慢速哈希,例如 PBKDF2、bcrypt 或 scrypt。慢速散列是一种设计为需要大量计算能力的散列,使得使用常见密码列表的暴力攻击更加困难。

不过,慢散列的实际安全优势并不大,因为用户从一个相当小的常用密码列表中选择密码。在我自己的分析中,大约一百万个密码(20 位)可以恢复 50% 的帐户(http://www.w3.org/2005/Security/usability-ws/presentations/37-google.pdf)。只需 1000 个密码即可恢复很大一部分帐户 (6.1%)。

对如此少量的熵进行散列是不可能的,以至于它成为攻击者的一个重要障碍。