PEP 452 – 密码哈希函数 API v2.0
- 作者:
- A.M. Kuchling <amk at amk.ca>, Christian Heimes <christian at python.org>
- 状态:
- 最终版
- 类型:
- 信息性
- 创建日期:
- 2013年8月15日
- 发布历史:
- 取代:
- 247
目录
摘要
有几个不同的模块可用于实现MD5或SHA等加密哈希算法。本文档为这些算法指定了一个标准API,以方便在不同实现之间切换。
规范
所有哈希模块都应该提供相同的接口。可以添加额外的方法或变量,但本文档中描述的那些应该始终存在。
哈希函数模块定义一个函数
new([string]) (无密钥哈希)
new(key, [string], [digestmod]) (有密钥哈希)
- 创建一个新的哈希对象并返回它。第一种形式用于无密钥哈希,例如MD5或SHA。对于HMAC等有密钥哈希,'key'是一个必需参数,包含一个表示要使用的密钥的字符串。在两种情况下,如果提供了可选的'string'参数,它将立即被哈希到对象的起始状态,就像调用了
obj.update(string)
一样。创建哈希对象后,可以使用其
update()
方法将任意字节数据输入到对象中,并且可以随时通过调用对象的digest()
方法获取哈希值。尽管参数名为“string”,但哈希对象仅对8位数据进行操作。“key”和“string”都必须是字节类对象(bytes、bytearray…)。哈希对象也可以支持一维、连续的缓冲区作为参数。文本(unicode)在Python 3.x中不再支持。Python 2.x实现可以接受仅包含ASCII的unicode作为参数,但可移植代码不应依赖此功能。
可以向此函数添加任意额外的关键字参数,但如果未提供,则应使用合理的默认值。例如,可以为支持可变轮数和多种不同输出大小的哈希函数添加“rounds”和“digest_size”关键字,它们应默认为被认为是安全的值。
哈希函数模块定义一个变量
digest_size
- 一个整数值;由该模块创建的哈希对象生成的摘要大小,以字节为单位。您也可以通过创建一个示例对象并访问其“digest_size”属性来获取此值,但将此值从模块中直接获取可能更方便。具有可变输出大小的哈希将此变量设置为None。
哈希对象需要以下属性
digest_size
- 此属性与模块级别的digest_size变量相同,表示由哈希对象生成的摘要大小,以字节为单位。如果哈希具有可变输出大小,则必须在创建哈希对象时选择此输出大小,并且此属性必须包含所选的大小。因此,
None
不是此属性的合法值。 block_size
- 一个整数值或
NotImplemented
;哈希算法的内部块大小,以字节为单位。块大小由HMAC模块用于将密钥填充到digest_size
,或者如果密钥长度超过digest_size
,则对密钥进行哈希。如果哈希算法没有标准化的HMAC算法,则返回NotImplemented
。 名称
- 一个文本字符串值;哈希算法的规范的、小写名称。该名称应是
hashlib.new
的合适参数。
哈希对象需要以下方法
copy()
- 返回此哈希对象的独立副本。对此副本的更新不会影响原始对象。
digest()
- 将此哈希对象的哈希值作为包含8位数据的字节返回。此函数不会以任何方式更改对象;调用此函数后,您可以继续更新对象。
hexdigest()
- 将此哈希对象的哈希值作为包含十六进制数字的字符串返回。数字“a”到“f”应使用小写字母。与
.digest()
方法一样,此方法不得更改对象。 update(string)
- 将字节类“string”哈希到哈希对象的当前状态。
update()
可以在哈希对象的生命周期内被调用任意次。
哈希模块可以定义额外的模块级函数或对象方法,并且仍然符合本规范。
这是一个示例,使用名为“MD5”的模块
>>> import hashlib
>>> from Crypto.Hash import MD5
>>> m = MD5.new()
>>> isinstance(m, hashlib.CryptoHash)
True
>>> m.name
'md5'
>>> m.digest_size
16
>>> m.block_size
64
>>> m.update(b'abc')
>>> m.digest()
b'\x90\x01P\x98<\xd2O\xb0\xd6\x96?}(\xe1\x7fr'
>>> m.hexdigest()
'900150983cd24fb0d6963f7d28e17f72'
>>> MD5.new(b'abc').digest()
b'\x90\x01P\x98<\xd2O\xb0\xd6\x96?}(\xe1\x7fr'
基本原理
摘要大小以字节而不是位为单位,即使哈希算法大小通常以位为单位;例如,MD5是一个128位算法,而不是16字节算法。这是因为在我查看的示例代码中,经常需要以字节为单位的长度(用于在文件中向前或向后查找;计算输出字符串的长度),而以位为单位的长度很少使用。因此,实际需要以位为单位的大小的少数人将不得不将digest_size乘以8。
有人建议将update()
方法更好地命名为append()
。然而,该方法确实导致哈希对象的当前状态被更新,并且Python中包含的md5和sha模块已经使用了update()
,因此最简单的做法似乎是保留名称update()
。
有密钥哈希的构造函数参数顺序是一个棘手的问题。不清楚密钥应该放在第一位还是第二位。它是一个必需参数,通常的惯例是将必需参数放在前面,但这也意味着“string”参数从第一个位置移动到第二个位置。可能会混淆并将单个参数传递给有密钥哈希,认为您正在将初始字符串传递给无密钥哈希,但为了避免这种潜在错误,使有密钥哈希的接口更不清楚似乎不值得。
从1.0版到2.0版的更改
密码哈希函数API的2.0版澄清了API的某些方面并使其保持最新。它还正式化了已经成为事实标准并由大多数实现提供的方面。
2.0版引入了以下新属性
名称
- name属性由问题18532强制要求。
block_size
- 新版本还规定,返回值
NotImplemented
会阻止HMAC支持。
2.0版考虑了Python 3.0中二进制数据和文本数据的分离。new()
和update()
的“string”参数以及“key”参数都必须是字节类对象。在Python 2.x上,哈希对象也可以支持仅包含ASCII的unicode。参数的实际名称没有改变,因为它是公共API的一部分。代码可能依赖于参数名为“string”这一事实。
常用哈希算法的推荐名称
算法 | 变体 | 推荐名称 |
---|---|---|
MD5 | md5 | |
RIPEMD-160 | ripemd160 | |
SHA-1 | sha1 | |
SHA-2 | SHA-224 | sha224 |
SHA-256 | sha256 | |
SHA-384 | sha384 | |
SHA-512 | sha512 | |
SHA-3 | SHA-3-224 | sha3_224 |
SHA-3-256 | sha3_256 | |
SHA-3-384 | sha3_384 | |
SHA-3-512 | sha3_512 | |
WHIRLPOOL | whirlpool |
更改
- 2001-09-17: 将
clear()
重命名为reset()
;向对象添加digest_size
属性;添加.hexdigest()
方法。 - 2001-09-20: 完全删除
reset()
方法。 - 2001-09-28: 对于可变大小哈希,将
digest_size
设置为None
。 - 2013-08-15: 添加
block_size
和name
属性;澄清“string”实际上指的是字节类对象。
致谢
感谢Aahz、Andrew Archibald、Rich Salz、Itamar Shtull-Trauring以及python-crypto列表的读者对本PEP的评论。
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0452.rst