Python 进阶学习笔记之十:一般加密支持

Python 进阶系列笔记文章链接:
Python 进阶学习笔记之一:内置常用类型及方法
Python 进阶学习笔记之二:常用数据类型(上)
Python 进阶学习笔记之三:常用数据类型(下)
Python 进阶学习笔记之四:高效迭代器工具
Python 进阶学习笔记之五:异步 IO
Python 进阶学习笔记之六:多线程编程
Python 进阶学习笔记之七:互联网支持
Python 进阶学习笔记之八:面向对象高级编程
Python 进阶学习笔记之九:IO 编程
Python 进阶学习笔记之十:一般加密支持
Python 进阶学习笔记之十一:日志支持
Python 进阶学习笔记之十二:数据压缩与归档

——————
一般加密算法就是我们最常见的如 MD5、SHA1等 Hash 算法。Hash 算法又称摘要算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串。
Hash 函数是一个单向函数,即通过 Hash 函数计算一段文本的结果很容易,反向推原文确很难,这也是为什么我们用这种函数来加密我们的密码等隐私信息的原因之一。

hashlib模块

Python 的 hashlib 提供了常见的摘要算法,如 MD5,SHA1 等等。

MD5
MD5 是最常见的摘要算法,速度很快,生成结果是固定的128 bit 字节,通常用一个 32 位的 16 进制字符串表示。这里用它来加密一个字符串:

import hashlib

md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())       
# 输出 d26a53750bc40b38b65a520292f69306

如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:

import hashlib

md5 = hashlib.md5()
md5.update('how to use md5 in '.encode('utf-8'))
md5.update('python hashlib?'.encode('utf-8'))
print(md5.hexdigest())

SHA1
另一种常见的摘要算法是 SHA1,SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。
调用SHA1和调用MD5完全类似:

import hashlib

sha1 = hashlib.sha1()
sha1.update('how to use sha1 in '.encode('utf-8'))
sha1.update('python hashlib?'.encode('utf-8'))
print(sha1.hexdigest())

除了上面常见的两个算法,模块中还支持很多中算法,在 hashlib 模块中有两个集合常量,常量中包含了 hashlib 支持的算法的名称:

  • hashlib.algorithms_guaranteed:按官方文档解释是保证在主流平台都支持的算法名称的集合,是 algorithms_available 的子集。
  • hashlib.algorithms_available:包含所有 hashlib 支持的算法的名称集合。

我们可以输出一下 hashlib.algorithms_available 的值:

>>> hashlib.algorithms_available
{'md4', 'MDC2', 'DSA', 'dsaEncryption', 'sha3_384', 'MD4', 'shake_128', 'blake2b', 'SHA256', 'SHA224', 'sha1', 'MD5', 'sha384', 'sha256', 'sha3_224', 'blake2s', 'dsaWithSHA', 'SHA384', 'ripemd160', 'sha', 'SHA512', 'sha3_256', 'SHA', 'shake_256', 'RIPEMD160', 'DSA-SHA', 'sha3_512', 'sha512', 'mdc2', 'whirlpool', 'SHA1', 'ecdsa-with-SHA1', 'md5', 'sha224'}

Python 提供了一个根据可用算法名称来得到算法对象的方法hashlib.new(),只要上面列表中有的名称都可以传入到 new 中来得到一个算法对象,用这个对象对内容进行加密:

>>> import hashlib
>>> hashlib.md5(b'abc').hexdigest()
'900150983cd24fb0d6963f7d28e17f72'
>>> h = hashlib.new('md5')
>>> h
<md5 HASH object @ 0x10e1e6f58>
>>> h.update(b'abc')
>>> h.hexdigest()
'900150983cd24fb0d6963f7d28e17f72'

可以看到加密结果是一样的。

注意:加密对象接收的是二进制的内容,除了使用 b'abc' 字符串来传入,还可以使用字符串的编码方法指定编码 'python hashlib?'.encode('utf-8')

模块中还有很多特定场景的加密支持,有兴趣可以看官方文档:hashlib — 安全哈希与消息摘要

hmac模块

使用上面 hashlib 模块中的哈希算法,我们可以验证一段数据是否有效,方法就是对比该数据的哈希值。只是使用纯 hash 算法来加密存储一些信息,当前已经不是特别安全了,尤其是用户密码,很多用户的密码都是简单密码或者重复密码,黑客获取了数据库后,可以使用彩虹表来反推出密码明文。因此我们可以对这类数据在加密时添加一下额外信息(salt),只要这个 salt 值不泄漏,简单数据的加密结果就很难暴力破解。

HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code)的缩写,现在已经成为事实上的 Internet 安全标准。它可以与任何迭代散列函数捆绑使用。Python 专门提供类一个模块来支持 hmc,这个模块的实现和使用是依赖hashlib模块的。

HMAC 类使用起来很简单,基本只有三个方法最常用:

  • 类构造器__init__(self, key, msg = None, digestmod = None)key - 加密密钥,必须为字节或者字节数组;msg - 待加密字节串;digestmod - 加密算法,可以是个 hashlib.algorithms_available 内有效字符串,也可以是 hashlib 中的一个具体算法实现方法,如 hashlib.md5
  • HMAC.update(msg):追加待加密字符串
  • HMAC.hexdigest():获取加密后字符串的摘要结果

代码示例:

>>> import hmac
>>> h = hmac.HMAC(b'xibaword', digestmod='sha1')
>>> h.update(b'hello word')
>>> h.hexdigest()
'24a18c0fc8cd44e2639faddcce060c81de0c2bb6'
>>> h.update(b'world')
>>> h.hexdigest()
'f3943b0a81dd1fb878bf84f076ab6f60abedd855'

生成安全随机串支持模块 - secrets

secrets 模块从 3.6 版本开始提供的。
secrets 模块主要适用于 密码、token、安全地址等安全管理操作。

模块中常用方法:

  • secrets.choice(sequence) :从给定的一个字符串中随机返回其中一个
  • secrets.randbelow(n):给定一个上限 n ,返回一个小于 n 的整数
  • secrets.token_hex([nbytes=None]):返回一个 hex 字符串,字符串会包含nbytes位随机字节,每个字节被转成两个 hex 摘要
  • secrets.token_urlsafe([nbytes=None]):返回一个随机的 URL-safe 的文本字符串,包含 nbytes个随机字节. 最终结果是 Base64 编码的。
>>> import secrtes
>>> secrets.choice('abcdefg')
'a'
>>> secrets.choice('abcdefgasdfadf')
'd'
>>> secrets.randbelow(10)
2
>>> secrets.token_hex(16)
'f46ed277b9da347643fd0ff739f3394c'
>>> secrets.token_hex(16)
'f46ed277b9da347643fd0ff739f3394c'

这里引用一下官方文档提及的最佳实践代码:

# 生成一个 8 位的随机”字母+数字“串
import string
alphabet = string.ascii_letters + string.digits
password = ''.join(choice(alphabet) for i in range(8))
# Generate a ten-character alphanumeric password with at least one lowercase character, at least one uppercase character, and at least three digits:
# 生成一个10位的密码,包含至少2位小写字母,至少1位大写字母,至少3个数字
import string
alphabet = string.ascii_letters + string.digits
while True:
    password = ''.join(choice(alphabet) for i in range(10))
    if (any(c.islower() for c in password)
            and any(c.isupper() for c in password)
            and sum(c.isdigit() for c in password) >= 3):
        break
# 生成一个安全 token 用于 url 传输
url = 'https://mydomain.com/reset=' + token_urlsafe()

————————
继续阅读请点击:Python 进阶学习笔记之十一:日志支持

你可能感兴趣的:(Python)