All Articles

Bcrypt[checkpw()] Login, how to check if an entered password matches the hashed password saved in the database

Bcrypt has a method called checkpw(), which allows you to check whether the entered password matches the hashed password, which is saved in the database. bcrypt.checkpw(password, hashed):

I used checkpw() method as well like below;

if bcrypt.checkpw(login_password.encode("utf-8"), registered_password):
    return JsonResponse({"message" : "login success"}, safe=False)

In my last post, I mentioned that you have to save a decoded password to the database because it would cause errors in login otherwise. I encoded the login_password, which is the password that a user entered to login, but did not encode registered_password, which is the hashed password because I had encoded it before hasing when I saved it to the database.

But it gave me this error Unicode-objects must be encoded before checking

Facing the error message, I changed my code to this

if bcrypt.checkpw(login_password.encode("utf-8"), registered_password.encode("utf-8")):
    return JsonResponse({"message" : "login success"}, safe=False)

But the code above doesn’t really make sense because I am “double-encoding” my hashed password, so I go another error message like this below

File "/Users/byeongjinkang/miniconda3/envs/lunch_buddy/lib/python3.7/site-packages/bcrypt/__init__.py", line 86, in hashpw
    raise ValueError("Invalid salt")
ValueError: Invalid salt

I thought this implied that my salt, which was randomly generated by bcrypt.gensalt(), was invalid, which doesn’t make sense. Why is bcrypt telling me that a salt, which was randomly generated by bcrypt, was invalid? In order to get deeper into the problem, I decided to look into that __init__.py, and this is where the error occurred.

hashed = _bcrypt.ffi.new("char[]", 128)
retval = _bcrypt.lib.bcrypt_hashpass(password, salt, hashed, len(hashed))

if retval != 0:
    raise ValueError("Invalid salt")

The bcrypt library describes this section that the hashed password must have the $2b$ prefix, which is achived by decoding the password. If you save the password without decoding it, its prefix becomes b'$2b$, which raises an error.

Then you could argue “why don’t you save it as an encoded password?” I tried it, but unfortunately(?) bytes object, whish is a type of the hashed password, doesn’t have an attribute encode. So this is pretty much the only way.

In my next post, I am going to talk about how to use jwt token.

Jul 3, 2019

AI Enthusiast and a Software Engineer