BCrypt How to store salt with python3?

We have code that works for python 2 .

 @password.setter def password(self, value): self.salt = bcrypt.gensalt() self.passwd = bcrypt.hashpw(value.encode('utf-8'), self.salt) def check_password(self, value): return bcrypt.hashpw(value.encode('utf-8'), self.salt.encode('utf-8')) == self.passwd 

However, when I try to convert it to python3, we encounter the following problems:

Error at the cassandra driver level:

 cassandra.cqlengine.ValidationError: passwd <class 'bytes'> is not a string 

Ok Casting salt and passwd to a string:

 @password.setter def password(self, value): salt = bcrypt.gensalt() self.salt = str(salt) self.passwd = str(bcrypt.hashpw(value.encode('utf-8'), salt)) 

Now the salt is saved. But in check_password we get ValueError: Invalid salt . If we change the verification code code to:

 def check_password(self, value): return bcrypt.hashpw(value, self.salt) == self.passwd 

We get a TypeError error TypeError: Unicode-objects must be encoded before hashing .

Where to dig?

UPD The salt values ​​in the password and the control password look the same, for example:

 b'$2b$12$cb03angGsu91KLj7xoh3Zu' b'$2b$12$cb03angGsu91KLj7xoh3Zu' 
+5
source share
1 answer

Update

Starting with version 3.1.0 bcrypt provides a convenient function

 checkpw(password, hashed_password) 

Perform password verification with a hashed password. This should be used instead:

 bcrypt.hashpw(passwd_to_check, hashed_passwd) == hashed_passwd 

which is shown below. There is still no need to store the hash separately.


First of all, you do not need to store salt, because it is part of the hash generated by bcrypt.hashpw() . You just need to save the hash. For instance.

 >>> salt = bcrypt.gensalt() >>> salt b'$2b$12$ge7ZjwywBd5r5KG.tcznne' >>> passwd = b' p@ssw0rd ' >>> hashed_passwd = bcrypt.hashpw(passwd, salt) b'$2b$12$ge7ZjwywBd5r5KG.tcznnez8pEYcE1QvKshpqh3rrmwNTQIaDWWvO' >>> hashed_passwd.startswith(salt) True 

So you can see that salt is included in the hash.

You can also use bcrypt.hashpw() to verify that the password matches the hashed password:

 >>> passwd_to_check = b' p@ssw0rd ' >>> matched = bcrypt.hashpw(passwd_to_check, hashed_passwd) == hashed_passwd >>> matched True >>> bcrypt.hashpw(b'thewrongpassword', hashed_passwd) == hashed_passwd False 

No need to store salt separately.


So you can write setter like this (Python 3):

 @password.setter def password(self, passwd): if isinstance(passwd, str): passwd = bytes(passwd, 'utf-8') self.passwd = str(bcrypt.hashpw(passwd, bcrypt.gensalt()), 'utf8') 

And a checker like this:

 def check_password(self, passwd_to_check): if isinstance(passwd_to_check, str): passwd_to_check = bytes(passwd_to_check, 'utf-8') passwd = bytes(self.passwd, 'utf8') return bcrypt.hashpw(passwd_to_check, passwd) == passwd 
+8
source

Source: https://habr.com/ru/post/1245221/


All Articles