2016-03-17 16 views
5

Abbiamo codice, che funziona per python 2.BCrypt. Come conservare il sale con 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 

Tuttavia, quando si tenta di convertirlo in python3, incontriamo seguenti problemi:

errore ci capita sul livello di driver cassandra:

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

Ok. Casting salt and passwd to string:

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

Ora il sale risparmia. Ma in check_password otteniamo ValueError: Invalid salt. Se cambiamo controllare il codice password:

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

otteniamo errore TypeError: Unicode-objects must be encoded before hashing.

Dove scavare?

UPD valori di sale di password e spunta la password aspetto stesso, ad esempio:

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

risposta

7

Aggiornamento

A partire dalla versione 3.1.0 bcrypt fornisce la funzione di convenienza

checkpw(password, hashed_password) 

per eseguire il controllo della password su un ha perdere la password. Questo dovrebbe essere utilizzato al posto di:

bcrypt.hashpw(passwd_to_check, hashed_passwd) == hashed_passwd 

che è mostrato di seguito. Non è ancora necessario memorizzare l'hash separatamente.


Prima di tutto, non è necessario per memorizzare il sale perché è parte della hash prodotto da bcrypt.hashpw(). Hai solo bisogno di memorizzare l'hash. Per esempio.

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

Quindi è possibile vedere che il sale è incluso nell'hash.

È inoltre possibile utilizzare bcrypt.hashpw() per controllare che una password corrisponde una password hash:

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

Non c'è bisogno di conservare il sale separatamente.


Così si potrebbe scrivere il setter come questo (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') 

E il controllo in questo modo:

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

vedo. Il problema è che, str si converte in stringa come "b" $ 2b $ 12 $ 8YtRw4YT27XpnpSBVZ9KeOlwKXdFhEMjN1Mqee6ySc7.71D1GHRKe '"'. Invece di str dovremmo usare 'bcrypt.hashpw (passwd, bcrypt.gensalt()).decodificare ('utf-8') '. –

+0

Perché non usi 'bcrypt.checkpw()'? Sembra che i valori hash effettivi siano variabili e non necessariamente confrontabili (sebbene possano essere uguali nella stessa esecuzione). – Shule

+1

@Shule: grazie per questo, "checkpw()" è stato aggiunto in [versione 3.1.0] (https://github.com/pyca/bcrypt/#310). In precedenza, all'incirca nel tempo in cui questa risposta è stata pubblicata, il modo di controllare la password era come mostrato sopra. Ho aggiornato la risposta originale per raccomandare l'uso della nuova funzione. Non c'è alcun problema con la modifica dell'hash, perché il sale è memorizzato con l'hash. Se generi un sale diverso, otterrai un hash diverso, ma questo è un problema diverso. – mhawke