为什么bcrypt.hashpw可用于散列和验证密码?

时间:2014-12-11 00:15:00

标签: python hash salt bcrypt

在Python 2.7中使用bcrypt,我可以看到该示例使用bcrypt.hashpw对存储密码进行哈希处理,并验证给定的密码是否与哈希值相匹配,如下所示:

散列

import bcrypt
password = b"somepassword"
hashed = bcrypt.hashpw(password, bcrypt.gensalt())

好的,到目前为止一切顺利。现在使用bcrypt对给定的密码进行哈希处理,因此它是一个哈希字节字符串。


验证

现在,这里让我感到困惑的部分是:要检查明文密码是否与哈希密码匹配,使用相同的函数,使用哈希密码作为salt:

if bcrypt.hashpw(password, hashed) == hashed:
    print("It Matches!")
else:
    print("It Does not Match :(")


发生了什么?

两个bcrypt.hashpw调用的结果是否不同,因为输入盐是不同的?

我能想到的唯一合理的答案是,在将前缀添加到哈希密码之前,盐被截断为固定长度。这样,当使用散列的结果时,仅留下生成的盐(在剥离尾随的散列密码之后),并且使用截断的盐散列密码的结果与原始密码相同。但是,我没有任何证据支持这一点。

为什么这样做?

2 个答案:

答案 0 :(得分:8)

在表达式bcrypt.hashpw(password, hashed)中,只有hashed的前几个字符用于salt,而不是整个字符串。

例如,在此示例中,hashpw()的输出如何以salt开头:

salt1 = b"$2a$12$w40nlebw3XyoZ5Cqke14M."

print "salt1:", salt1
print "hash1:", bcrypt.hashpw(password, salt1)

打印:

salt1: $2a$12$w40nlebw3XyoZ5Cqke14M.
hash1: $2a$12$w40nlebw3XyoZ5Cqke14M.d.7cdO2wJhr/K6ZSDjODIxLrPmYzY/a

所以有一个惯例,盐只会上升第一个时期或前29个字符。

答案 1 :(得分:5)

hashpw函数返回盐渍哈希(在bcyrpt规范之后多次迭代),前面是使用的盐(并且以点作为分隔符)。

In : salt = bcrypt.gensalt()
In : all(salt == bcrypt.hashpw(pw,salt)[:len(salt)] for pw in ('','12345','asdfgh'))
Out: True

如果bcrypt.hashpw的第二个参数被识别为VALID_SALT.VALID_HASH形式,那么salt会自动设置为VALID_SALT,从而产生与原始相同的salt-hash-pair相同pw输入的密码。