2016-03-17 22 views
5

Mamy kod, który działa dla python 2.BCrypt. Jak przechowywać sól w python3?

@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 

Jednak gdy próbuję przekonwertować go do python3 spotykamy następujące problemy:

błędach jeden dzieje się na poziomie sterownika Cassandra:

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

Ok. Casting salt i passwd na ciąg:

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

Teraz sól ratuje. Ale w check_password otrzymujemy ValueError: Invalid salt. Jeśli zmienimy sprawdzić kod hasłem:

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

Otrzymujemy błąd TypeError: Unicode-objects must be encoded before hashing.

Gdzie kopać?

UPD wartości Sól w hasło i sprawdzić hasło wyglądać tak samo, na przykład:

b'$2b$12$cb03angGsu91KLj7xoh3Zu'                   
b'$2b$12$cb03angGsu91KLj7xoh3Zu' 

Odpowiedz

7

aktualizacji

Począwszy od wersji 3.1.0 bcrypt udostępnia funkcję ogólnospożywczy

checkpw(password, hashed_password) 

do sprawdzania haseł przed ha przelać hasło. Należy go użyć zamiast:

bcrypt.hashpw(passwd_to_check, hashed_passwd) == hashed_passwd 

, który pokazano poniżej. Wciąż nie ma potrzeby przechowywania skrótu osobno.


Przede wszystkim, nie trzeba do przechowywania soli, ponieważ jest częścią hash produkowanego przez bcrypt.hashpw(). Musisz tylko zapisać hasz. Na przykład.

>>> salt = bcrypt.gensalt() 
>>> salt 
b'$2b$12$ge7ZjwywBd5r5KG.tcznne' 
>>> passwd = b'[email protected]' 
>>> hashed_passwd = bcrypt.hashpw(passwd, salt) 
b'$2b$12$ge7ZjwywBd5r5KG.tcznnez8pEYcE1QvKshpqh3rrmwNTQIaDWWvO' 
>>> hashed_passwd.startswith(salt) 
True 

Widać więc, że sól jest zawarta w hashu.

Można również użyć bcrypt.hashpw() aby sprawdzić, czy hasło pasuje zaszyfrowaną hasło:

>>> passwd_to_check = b'[email protected]' 
>>> matched = bcrypt.hashpw(passwd_to_check, hashed_passwd) == hashed_passwd 
>>> matched 
True 
>>> bcrypt.hashpw(b'thewrongpassword', hashed_passwd) == hashed_passwd 
False 

Nie trzeba przechowywać sól oddzielnie.


Można więc napisać setter takiego (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') 

a sprawdzania takiego:

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 
+1

widzę. Kłopot polegał na tym, że str jest konwertowany na ciąg jak '' b '$ 2b $ 12 $ 8YtRw4YT27XpnpSBVZ9KeOlwKXdFhEMjN1Mqee6ySc7.71D1GHRKe' "'. Zamiast łańcucha str powinniśmy użyć 'bcrypt.hashpw (passwd, bcrypt.gensalt()).dekodowanie ("utf-8") '. –

+0

Dlaczego nie używasz 'bcrypt.checkpw()'? Wygląda na to, że rzeczywiste wartości skrótu są zmienne i niekoniecznie porównywalne (chociaż mogą być takie same w tym samym przebiegu). – Shule

+1

@ Shule: dzięki za wskazanie tego, 'checkpw()' zostało dodane w [wersja 3.1.0] (https://github.com/pyca/bcrypt/#310). Wcześniej, około czasu, w którym ta odpowiedź została wysłana, sposób sprawdzenia hasła był taki, jak pokazano powyżej. Zaktualizowałem oryginalną odpowiedź, aby polecić korzystanie z nowej funkcji. Nie ma problemu ze zmianą hasza, ponieważ sól jest przechowywana z hashem. Jeśli wygenerujesz inną sól, otrzymasz inny skrót, ale to jest inny problem. – mhawke