2016-03-17 38 views
5

我們有代碼,它適用於python 2BCrypt。如何用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 

然而,當我嘗試將其轉換爲python3,我們遇到以下問題:

錯誤的卡桑德拉驅動級一個情況:

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

確定。鑄鹽和passwd字符串:

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

現在鹽節省。但在check_password我們得到ValueError: Invalid salt。 如果我們改變支票密碼代碼:

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

我們得到錯誤TypeError: Unicode-objects must be encoded before hashing

哪裏挖?

UPD在密碼鹽價值觀和支票密碼一樣看,例如:

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

回答

7

更新

截至版本3.1.0 bcrypt提供便捷功能

checkpw(password, hashed_password) 

對ha進行密碼檢查丟掉密碼。這應該用來代替:

bcrypt.hashpw(passwd_to_check, hashed_passwd) == hashed_passwd 

這是如下所示。仍然不需要單獨存儲散列。所有的


首先,你並不需要存儲的鹽,因爲它是由bcrypt.hashpw()產生的哈希的一部分。你只需要存儲散列。例如。

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

所以你可以看到鹽包含在散列中。

您還可以使用bcrypt.hashpw()檢查密碼相匹配的哈希密碼:

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

不需要單獨存儲鹽。


所以你可以寫這樣的setter(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') 

和校驗是這樣的:

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

我明白了。麻煩的是,該字符串轉換爲字符串,如「b」$ 2b $ 12 $ 8YtRw4YT27XpnpSBVZ9KeOlwKXdFhEMjN1Mqee6ySc7.71D1GHRKe'「'。我們應該使用'bcrypt.hashpw(passwd,bcrypt.gensalt())來代替str。解碼( 'UTF-8')'。 –

+0

爲什麼不使用'bcrypt.checkpw()'?它看起來像實際的散列值是可變的,並不一定可比(儘管它們在同一次運行中可能是相同的)。 – Shule

+1

@Shule:感謝您指出,'checkpw()'是在[version 3.1.0](https://github.com/pyca/bcrypt/#310)中添加的。在此之前,大概這個答案發布的時間,檢查密碼的方式如上所示。我已經更新了原始答案以推薦使用新功能。哈希改變沒有問題,因爲salt與哈希存儲在一起。如果您生成不同的鹽,那麼您將得到不同的哈希值,但這是一個不同的問題。 – mhawke