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 等)。哈希对象也可能支持一维连续缓冲区作为参数。Python 3.x 中不再支持文本(unicode)。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
。 name
- 一个文本字符串值;哈希算法的规范小写名称。该名称应该是
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’ 参数从第一位置移动到第二位置。可能会感到困惑,将单个参数传递给带密钥的哈希,以为您正在将初始字符串传递给无密钥哈希,但这似乎不值得为了避免此潜在错误而使带密钥哈希的接口变得更加模糊。
2.0 版与 1.0 版的变更
加密哈希函数 API 的 2.0 版阐明了 API 的某些方面并使其保持最新。它还规范化了已经成为事实标准并由大多数实现提供的方面。
2.0 版引入了以下新属性
name
- 问题 18532 规定了 name 属性是必须的。
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年9月17日:将
clear()
重命名为reset()
;向对象添加了digest_size
属性;添加了.hexdigest()
方法。 - 2001年9月20日:完全删除了
reset()
方法。 - 2001年9月28日:对于可变大小的哈希,将
digest_size
设置为None
。 - 2013年8月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