2016-03-17 36 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