15.1. hashlib - 安全散列和消息摘要

源代码: Lib/hashlib.py

这个模块实现了一个通用的接口来实现多个不同的安全哈希和消息摘要算法。包括FIPS安全散列算法SHA1,SHA224,SHA256,SHA384和SHA512(在FIPS 180-2中定义)以及RSA的MD5算法(在因特网 RFC 1321术语“安全散列”和“消息摘要”是可互换的。较旧的算法被称为消息摘要。现代术语是安全哈希。

如果你想要adler32或crc32哈希函数,它们在zlib模块中可用。

警告

一些算法具有已知的哈希冲突弱点,请参阅末尾的"另请参见"一节。

15.1.1.哈希算法

每种类型的哈希都具有一个命名构造函数。它们都返回一个具有相同的简单接口的哈希对象。例如:使用sha1()创建SHA1哈希对象。现在,你可以使用update()方法以类字节对象填充这个对象(通常为字节)。在连接数据的任何时候,你都可以使用digest()hexdigest()方法来向它请求摘要

为了更好的多线程性能,在对象创建或更新时,针对大于2047字节的数据发布Python GIL

不支持将字符串对象添加到update()中,因为哈希在字节上工作,而不是字符。

此模块中始终存在的散列算法的构造函数为md5()sha1()sha224()sha256()sha384()sha512()可能还有其它算法,这取决于在你的平台上Python 使用的 OpenSSL 库。

例如,获取字节字符串b'Nobody inspects the spammish repetition'的摘要:

>>> import hashlib
>>> m = hashlib.md5()
>>> m.update(b"Nobody inspects")
>>> m.update(b" the spammish repetition")
>>> m.digest()
b'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9'
>>> m.digest_size
16
>>> m.block_size
64

更精炼的版本:

>>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest()
'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'
hashlib.new(name[, data])

是一个通用构造函数,它接受所需算法的字符串名称作为其第一个参数。它也存在允许访问上面列出的哈希以及您的OpenSSL库可能提供的任何其他算法。命名的构造函数比new()快得多,应该是首选。

使用OpenSSL提供的算法使用new()

>>> h = hashlib.new('ripemd160')
>>> h.update(b"Nobody inspects the spammish repetition")
>>> h.hexdigest()
'cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc'

Hashlib提供以下常量属性:

hashlib.algorithms_guaranteed

包含保证在所有平台上此模块支持的哈希算法的名称的集合。

版本3.2中的新功能。

hashlib.algorithms_available

一组包含在运行的Python解释器中可用的哈希算法的名称。当传递到new()时,这些名称将被识别。algorithms_guaranteed将始终是子集。相同的算法可能出现多次在此集中不同的名称(感谢OpenSSL)。

版本3.2中的新功能。

构造函数返回的哈希对象提供以下值作为常量属性:

hash.digest_size

以字节为单位的哈希结果的大小。

hash.block_size

以字节为单位的哈希算法的内部块的大小。

哈希对象具有以下属性:

hash.name

此哈希的规范名称,始终小写,始终适合作为new()的参数,以创建此类型的另一个哈希。

在版本3.4中更改: CPython自启动以来就存在name属性,但直到Python 3.4未正式指定,因此在某些平台上可能不存在。

哈希对象都具有以下方法:

hash.update(arg)

使用对象arg更新哈希对象,该对象必须可解释为字节缓冲区。重复调用等效于具有所有参数串联的单个调用:m.update(a); m.update(b)相当于m.update(ab)

在版本3.1中已更改:发布Python GIL以允许其他线程在使用OpenSSL提供的哈希算法时对大于2047字节的数据进行哈希更新时运行。

hash.digest()

返回传递给update()方法的数据的摘要。它是一个大小为digest_size的字节对象,包含的字节可以在0到255整个范围。

hash.hexdigest()

类似digest(),但是摘要以2倍长度的字符串对象返回,只包含十六进制数字。这可用于在电子邮件或其它非二进制环境中安全交换数据。

hash.copy()

返回哈希对象的一个副本("克隆")。这可以用于有效地计算共享公共初始子串的数据的摘要。

15.1.2.密钥导出

密钥派生和密钥stretching 设计用于安全的密码哈希。诸如sha1(password)的朴素算法不能抵抗暴力攻击。一个好的密码哈希函数必须是可调谐、 速度慢,并且包括一个salt

hashlib.pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None)

该函数提供 PKCS #5 基于密码的密钥派生函数 2。它使用 HMAC 作为伪随机函数。

字符串hash_name是HMAC的所需的哈希摘要算法的名称,例如。'sha1'或'sha256'。passwordsalt被解释为缓冲区的字节数。应用程式和程式库应将密码限制为明智的长度(例如1024)。salt应该是来自适当源的大约16个或更多个字节,例如os.urandom()

迭代次数应基于散列算法和计算能力来选择。截至2013年,建议至少100,000次迭代的SHA-256。

dklen是派生密钥的长度。如果dklenNone,则使用散列算法的摘要大小hash_name64用于SHA-512。

>>> import hashlib, binascii
>>> dk = hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 100000)
>>> binascii.hexlify(dk)
b'0394a2ede332c9a13eb82e9b24631604c31df978b4e2f0fbd2c549944f9d79a5'

新版本3.4。

OpenSSL 中实现的pbkdf2_hmac 更加快速。Python实现使用hmac的内联版本。它慢了约三倍且不释放 GIL。

请参见

模块hmac
使用哈希生成消息认证码的一个模块
模块base64
用于非二进制环境的编码二进制哈希的另外一种方式
http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
关于安全哈希算法的 FIPS 180-2 的公开发行
https://en.wikipedia.org/wiki/Cryptographic_hash_function#Cryptographic_hash_algorithms
维基百科的文章,关于哪些算法有已知问题和使用中的含义
https://www.ietf.org/rfc/rfc2898.txt
PKCS#5:基于密码的加密规范2.0版