Using bcrypt
with Python 2.7, I can see that the example uses the bcrypt.hashpw
to both hash a password for storage and verify that the given password matches a hashed one, like so:
import bcrypt
password = b"somepassword"
hashed = bcrypt.hashpw(password, bcrypt.gensalt())
Ok, so far so good. The given password is now hashed using bcrypt, so it is a string of hashed bytes.
Now, here's the part that confuses me: to check that a plaintext password matches a hashed password, the same function is used, using the hashed password as a salt:
if bcrypt.hashpw(password, hashed) == hashed:
print("It Matches!")
else:
print("It Does not Match :(")
Shouldn't the results of both bcrypt.hashpw
calls be different, since the input salts are different?
The only reasonable answer I can think of is that the salt is truncated to a fixed length before being prepended to the hashed password. That way, when using the result of the hash, only the generated salt is left (after stripping off the trailing hashed password), and the result of hashing the password with the truncated salt is the same as the original. I don't have any evidence to support this, though.
Why does this work?
In the expression bcrypt.hashpw(password, hashed)
only the first couple of characters of hashed
are used for the salt, not the entire string.
For instance, in this example how the output of hashpw()
begins with the salt:
salt1 = b"$2a$12$w40nlebw3XyoZ5Cqke14M."
print "salt1:", salt1
print "hash1:", bcrypt.hashpw(password, salt1)
prints:
salt1: $2a$12$w40nlebw3XyoZ5Cqke14M.
hash1: $2a$12$w40nlebw3XyoZ5Cqke14M.d.7cdO2wJhr/K6ZSDjODIxLrPmYzY/a
so there is a convention where the salt only goes up the first period or the first 29 characters.