密码加密与check

对用户的密码的进行加密、check

import base64
import hashlib
import hmac
import random
try:
    import crypt
except ImportError:
    crypt = None


class BasePasswordHash(object):
    def __init__(self):
        self._algorithm = None
        self._chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

    def get_random_string(self, length=12):
        """
        返回一个随机字符串
        """
        return ''.join(random.choice(self._chars) for _ in range(length))

    def salt(self):
        """
        生成在ASCII码范围内的随机字符串salt
        """
        return self.get_random_string()

    def encode(self, password):
        raise NotImplemented('子类必须实现encode方法')

    def verify(self, password, encoded):
        raise NotImplemented('子类必须实现verify方法')


class PBKDF2SHA256Hash(BasePasswordHash):
    """
    使用PBKDF2算法加密密码,hash使用SHA256(推荐)
    结果是64字节的二进制字符串。
    """
    algorithm = "pbkdf2_sha256"
    iterations = 36000
    digest = hashlib.sha256

    def encode(self, password, salt=None, iterations=None):
        if salt is None:
            salt = self.salt()
        assert password is not None
        assert salt and '$' not in salt
        if not iterations:
            iterations = self.iterations
        dklen = None
        hash_value = hashlib.pbkdf2_hmac(
            self.digest().name, password.encode('utf-8'), salt.encode('utf-8'), iterations, dklen)
        hash_value = base64.b64encode(hash_value).decode('ascii').strip()
        return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash_value)

    def verify(self, password, encoded):
        algorithm, iterations, salt, hash_value = encoded.split('$', 3)
        assert algorithm == self.algorithm
        encoded_2 = self.encode(password, salt, int(iterations))
        return hmac.compare_digest(encoded, encoded_2)


class PBKDF2SHA1Hash(PBKDF2SHA256Hash):
    """
    使用PBKDF2算法加密密码,hash使用SHA1。
    """
    algorithm = "pbkdf2_sha1"
    digest = hashlib.sha1


class SHA1Hash(BasePasswordHash):
    """
    使用SHA1算法加密密码(不推荐)
    """
    algorithm = "sha1"

    def encode(self, password, salt=None):
        if salt is None:
            salt = self.salt()
        assert password is not None
        assert salt and '$' not in salt
        hash_value = hashlib.sha1((salt + password).encode('utf-8')).hexdigest()
        return "%s$%s$%s" % (self.algorithm, salt, hash_value)

    def verify(self, password, encoded):
        algorithm, salt, hash_value = encoded.split('$', 2)
        assert algorithm == self.algorithm
        encoded_2 = self.encode(password, salt)
        return hmac.compare_digest(encoded, encoded_2)


class MD5Hash(BasePasswordHash):
    """
    使用加salt的MD5加密算法(不推荐)
    """
    algorithm = "md5"

    def encode(self, password, salt=None):
        if salt is None:
            salt = self.salt()
        assert password is not None
        assert salt and '$' not in salt
        hash_value = hashlib.md5((salt + password).encode('utf-8')).hexdigest()
        return "%s$%s$%s" % (self.algorithm, salt, hash_value)

    def verify(self, password, encoded):
        algorithm, salt, hash_value = encoded.split('$', 2)
        assert algorithm == self.algorithm
        encoded_2 = self.encode(password, salt)
        return hmac.compare_digest(encoded, encoded_2)


class CryptHash(BasePasswordHash):
    """
    使用UNIX下的crypt加密密码(不推荐)
    crypt模块不是所有平台都支持,只有unix平台能使用。
    """
    algorithm = "crypt"

    def salt(self):
        return self.get_random_string(2)

    def encode(self, password, salt=None):
        if salt is None:
            salt = self.salt()
        assert len(salt) == 2
        data = crypt.crypt(password, salt)
        assert data is not None
        return "%s$%s$%s" % (self.algorithm, '', data)

    def verify(self, password, encoded):
        algorithm, salt, data = encoded.split('$', 2)
        assert algorithm == self.algorithm
        return hmac.compare_digest(data, crypt.crypt(password, data))


def make_password(password, hasher='PBKDF2SHA256Hash'):
    """
    密码加密
    :param password: 原密码字符串
    :param hasher: 加密方式
    :return: 加密后的字符串
    """
    hashers = ['PBKDF2SHA256Hash', 'PBKDF2SHA1Hash', 'SHA1Hash', 'MD5Hash', 'CryptHash']
    assert hasher in hashers
    assert password is not None
    assert type(password) == str
    if hasher == 'PBKDF2SHA1Hash':
        hash_ = PBKDF2SHA1Hash()
    elif hasher == 'SHA1Hash':
        hash_ = SHA1Hash()
    elif hasher == 'MD5Hash':
        hash_ = MD5Hash()
    elif hasher == 'CryptHash':
        if crypt is not None:
            hash_ = CryptHash()
        else:
            raise ImportError('你的平台不支持crypt')
    else:
        hash_ = PBKDF2SHA256Hash()
    return hash_.encode(password)


def check_password(password, encoded, hasher='PBKDF2SHA256Hash'):
    """
    校验密码
    :param password: 原密码字符串
    :param encoded: 加密后的字符串
    :param hasher: 验证的加密方式
    :return: 验证是否正确
    """
    hashers = ['PBKDF2SHA256Hash', 'PBKDF2SHA1Hash', 'SHA1Hash', 'MD5Hash', 'CryptHash']
    assert hasher in hashers
    assert password is not None
    assert type(password) == str
    if hasher == 'PBKDF2SHA1Hash':
        hash_ = PBKDF2SHA1Hash()
    elif hasher == 'SHA1Hash':
        hash_ = SHA1Hash()
    elif hasher == 'MD5Hash':
        hash_ = MD5Hash()
    elif hasher == 'CryptHash':
        if crypt is not None:
            hash_ = CryptHash()
        else:
            raise ImportError('你的平台不支持crypt')
    else:
        hash_ = PBKDF2SHA256Hash()
    return hash_.verify(password, encoded)

加密、check 方法与Django中的make_password、check_password相同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值