hashlib —安全哈希和消息摘要

源代码: Lib/hashlib.py


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

Note

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

Warning

一些算法具有哈希冲突弱点,请参阅最后的“另请参见”部分。

Hash algorithms

每种* hash *类型都有一个构造函数方法。全部返回具有相同简单接口的哈希对象。例如:使用sha256()创建 SHA-256 哈希对象。现在,您可以使用update()方法以bytes-like objects(通常为bytes)来提供此对象。在任何时候,您都可以使用digest()hexdigest()方法要求它提供馈送给它的数据的“摘要” *。

Note

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

Note

不支持将字符串对象送入update(),因为哈希处理字节而不是字符。

此模块中始终存在的哈希算法构造函数为sha1()sha224()sha256()sha384()sha512()blake2b()blake2s()md5()通常也可用,但是如果您使用的是罕见的“ FIPS 兼容” Python 版本,则可能会丢失它。取决于 Python 在平台上使用的 OpenSSL 库,还可以使用其他算法。在大多数平台上,sha3_224()sha3_256()sha3_384()sha3_512()shake_128()shake_256()也可用。

3.6 版中的新Function:SHA3(Keccak)和 SHAKE 构造函数sha3_224()sha3_256()sha3_384()sha3_512()shake_128()shake_256()

3.6 版中的新Function:添加了blake2b()blake2s()

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

>>> import hashlib
>>> m = hashlib.sha256()
>>> m.update(b"Nobody inspects")
>>> m.update(b" the spammish repetition")
>>> m.digest()
b'\x03\x1e\xdd}Ae\x15\x93\xc5\xfe\\\x00o\xa5u+7\xfd\xdf\xf7\xbcN\x84:\xa6\xaf\x0c\x95\x0fK\x94\x06'
>>> m.digest_size
32
>>> m.block_size
64

More condensed:

>>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest()
'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'
  • hashlib. new(* name * [,* data *])
    • 是一个通用构造函数,它将所需算法的字符串* name *作为其第一个参数。它也可以访问上面列出的散列以及您的 OpenSSL 库可能提供的任何其他算法。命名的构造函数比new()快得多,应该首选。

new()与 OpenSSL 提供的算法结合使用:

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

Hashlib 提供以下常量属性:

  • hashlib. algorithms_guaranteed
    • 包含哈希算法名称的集合,保证该模块在所有平台上均受支持。请注意,尽管有些上游供应商提供了奇怪的“ FIPS 兼容” Python 构建(但不包括它),但“ md5”仍在此列表中。

3.2 版中的新Function。

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

3.2 版中的新Function。

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

  • hash. digest_size

    • 所得哈希的大小(以字节为单位)。
  • hash. block_size

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

哈希对象具有以下属性:

  • hash. name
    • 此哈希的规范名称,始终为小写字母,并且始终适合作为new()的参数来创建此类型的另一个哈希。

在 3.4 版中进行了更改:自 CPython 诞生以来,name 属性就已经存在,但是直到未正式指定 Python 3.4 为止,因此在某些平台上可能不存在。

哈希对象具有以下方法:

  • hash. update(* data *)
    • 使用bytes-like object更新哈希对象。重复调用等效于将所有参数串联在一起的单个调用:m.update(a); m.update(b)等效于m.update(a+b)

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

  • hash. digest ( )

    • 返回到目前为止传递给update()方法的数据的摘要。这是一个大小为digest_size的字节对象,其中可能包含 0 到 255 整个范围内的字节。
  • hash. hexdigest ( )

    • digest()一样,摘要以双倍长度的字符串对象(仅包含十六进制数字)返回。这可用于在电子邮件或其他非二进制环境中安全地交换值。
  • hash. copy ( )

    • 返回哈希对象的副本(“克隆”)。这可用于有效地计算共享公共初始子字符串的数据摘要。

可变长度摘要

shake_128()shake_256()算法提供具有 length_in_bits // 2 的可变长度摘要,安全性最高为 128 或 256 位。因此,它们的摘要方法需要一定长度。最大长度不受 SHAKE 算法的限制。

  • shake. digest(* length *)

    • 返回到目前为止传递给update()方法的数据的摘要。这是一个字节大小为* length *的对象,其中可能包含 0 到 255 之间的整个字节。
  • shake. hexdigest(* length *)

    • digest()一样,摘要以双倍长度的字符串对象(仅包含十六进制数字)返回。这可用于在电子邮件或其他非二进制环境中安全地交换值。

Key derivation

密钥派生和密钥扩展算法设计用于安全密码哈希。天真的算法(例如sha1(password))不能抵抗暴力攻击。好的密码哈希函数必须是可调的,缓慢的,并且必须包含salt

  • hashlib. pbkdf2_hmac(* hash_name password salt iterations dklen = None *)
    • 该Function提供了基于 PKCS#5 密码的密钥派生Function 2.它使用 HMAC 作为伪随机Function。

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

迭代次数应根据哈希算法和计算能力来选择。截至 2013 年,建议至少进行 100,000 次 SHA-256 迭代。

  • dklen 是派生密钥的长度。如果 dklen None,则使用哈希算法 hash_name *的摘要大小,例如 SHA-512 为 64.
>>> import hashlib
>>> dk = hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 100000)
>>> dk.hex()
'0394a2ede332c9a13eb82e9b24631604c31df978b4e2f0fbd2c549944f9d79a5'

3.4 版的新Function。

Note

OpenSSL 提供了* pbkdf2_hmac *的快速实现。 Python 实现使用内联版本hmac。它慢了大约三倍,并且不会释放 GIL。

  • hashlib. scrypt(* password **,* salt n r p maxmem = 0 dklen = 64 *)
    • 该Function提供了 RFC 7914中定义的基于 scrypt 密码的密钥派生Function。

密码必须为bytes-like objects。应用程序和库应将* password *限制为合理的长度(例如 1024)。 * salt *应该是来自适当来源的大约 16 个或更多字节,例如os.urandom()

  • n 是 CPU /内存成本因素, r 块大小, p 并行化因素和 maxmem *限制内存(OpenSSL 1.1.0 默认为 32 MiB)。 * dklen *是派生密钥的长度。

Availability:OpenSSL 1.1.

3.6 版的新Function。

BLAKE2

BLAKE2 RFC 7693中定义的加密哈希函数,有两种形式:

  • BLAKE2b ,针对 64 位平台进行了优化,可生成 1 到 64 字节之间任意大小的摘要,

  • BLAKE2s ,针对 8 到 32 位平台进行了优化,可生成 1 到 32 字节之间任意大小的摘要。

BLAKE2 支持 密钥模式 (更快,更简单的HMAC替代), 盐化哈希个性化树哈希

来自此模块的哈希对象遵循标准库的hashlib对象的 API。

创建哈希对象

pass调用构造函数创建新的哈希对象:

  • hashlib. blake2b(* data = b''**,* digest_size = 64 key = b'' salt = b'' person = b'' fanout = 1 * ,* depth = 1 leaf_size = 0 node_offset = 0 node_depth = 0 inner_size = 0 last_node = False *)

  • hashlib. blake2s(* data = b''**,* digest_size = 32 key = b'' salt = b'' person = b''*,扇出= 1 * , depth = 1 leaf_size = 0 node_offset = 0 node_depth = 0 inner_size = 0 last_node = False *)

这些函数返回相应的哈希对象以计算 BLAKE2b 或 BLAKE2s。它们可以选择采用以下常规参数:

    • data *:要散列的初始数据块,必须为bytes-like object。它只能作为位置参数传递。
    • digest_size *:输出摘要的大小,以字节为单位。
    • key *:用于密钥哈希的密钥(BLAKE2b 最多 64 个字节,BLAKE2s 最多 32 个字节)。
    • salt *:用于随机哈希的盐(BLAKE2b 最多 16 个字节,BLAKE2s 最多 8 个字节)。
    • person *:个性化字符串(BLAKE2b 最多 16 个字节,BLAKE2s 最多 8 个字节)。

下表显示了常规参数的限制(以字节为单位):

Hashdigest_sizelen(key)len(salt)len(person)
BLAKE2b64641616
BLAKE2s323288

Note

BLAKE2 规范为 salt 和个性化参数定义了恒定长度,但是,为方便起见,此实现接受任何大小的字节字符串,直到指定长度。如果参数的长度小于指定的长度,则会用零填充,因此,例如b'salt'b'salt\x00'是相同的值。 (* key *不是这种情况.)

这些尺寸可在下面描述的模块constants中获得。

构造函数还接受以下树哈希参数:

    • fanout *:扇出(0 到 255,如果没有限制则为 0,在连续模式下为 1)。
    • depth *:树的最大深度(1 到 255,如果没有限制则为 255,在连续模式下为 1)。
    • leaf_size *:叶子的最大字节长度(0 到 2 ** 32-1,如果为无限制或处于连续模式,则为 0)。
    • node_offset *:节点偏移(对于 BLAKE2b 为 0 到 2 64-1,对于 BLAKE2s 为 0 到 2 48-1,对于第一个,最左边的叶子或 Sequences 模式为 0)。
    • node_depth *:节点深度(0 到 255,叶子为 0,或在连续模式下)。
    • inner_size *:内部摘要大小(BLAKE2b 为 0 到 64,BLAKE2s 为 0 到 32,Sequences 模式为 0)。
    • last_node *:布尔值,指示处理的节点是否为最后一个节点(对于 Sequences 模式为 False)。

树模式参数的说明。

有关树哈希的全面介绍,请参见BLAKE2 specification中的 2.10 节。

Constants

  • blake2b. SALT_SIZE

  • blake2s. SALT_SIZE

盐长度(构造函数接受的最大长度)。

  • blake2b. PERSON_SIZE

  • blake2s. PERSON_SIZE

个性化字符串长度(构造函数接受的最大长度)。

  • blake2b. MAX_KEY_SIZE

  • blake2s. MAX_KEY_SIZE

最大密钥大小。

  • blake2b. MAX_DIGEST_SIZE

  • blake2s. MAX_DIGEST_SIZE

哈希函数可以输出的最大摘要大小。

Examples

Simple hashing

要计算某些数据的哈希,您应该首先pass调用适当的构造函数(blake2b()blake2s())来构造哈希对象,然后pass在对象上调用update()来使用数据更新它,最后,从对象中提取摘要pass调用digest()(对于十六进制编码的字符串,则调用hexdigest())。

>>> from hashlib import blake2b
>>> h = blake2b()
>>> h.update(b'Hello world')
>>> h.hexdigest()
'6ff843ba685842aa82031d3f53c48b66326df7639a63d128974c5c14f31a0f33343a8c65551134ed1ae0f2b0dd2bb495dc81039e3eeb0aa1bb0388bbeac29183'

作为一种快捷方式,您可以将第一部分数据作为位置参数直接传递给构造函数:

>>> from hashlib import blake2b
>>> blake2b(b'Hello world').hexdigest()
'6ff843ba685842aa82031d3f53c48b66326df7639a63d128974c5c14f31a0f33343a8c65551134ed1ae0f2b0dd2bb495dc81039e3eeb0aa1bb0388bbeac29183'

您可以根据需要多次调用hash.update()来迭代更新哈希:

>>> from hashlib import blake2b
>>> items = [b'Hello', b' ', b'world']
>>> h = blake2b()
>>> for item in items:
...     h.update(item)
>>> h.hexdigest()
'6ff843ba685842aa82031d3f53c48b66326df7639a63d128974c5c14f31a0f33343a8c65551134ed1ae0f2b0dd2bb495dc81039e3eeb0aa1bb0388bbeac29183'

使用不同的摘要大小

BLAKE2 具有可配置的摘要大小,BLAKE2b 的摘要最大为 64 字节,BLAKE2s 的摘要最大为 32 字节。例如,要在不更改输出大小的情况下用 BLAKE2b 替换 SHA-1,我们可以告诉 BLAKE2b 产生 20 字节的摘要:

>>> from hashlib import blake2b
>>> h = blake2b(digest_size=20)
>>> h.update(b'Replacing SHA1 with the more secure function')
>>> h.hexdigest()
'd24f26cf8de66472d58d4e1b1774b4c9158b1f4c'
>>> h.digest_size
20
>>> len(h.digest())
20

具有不同摘要大小的哈希对象具有完全不同的输出(较短的哈希不是较长的哈希的* not *前缀);即使输出长度相同,BLAKE2b 和 BLAKE2s 也会产生不同的输出:

>>> from hashlib import blake2b, blake2s
>>> blake2b(digest_size=10).hexdigest()
'6fa1d8fcfd719046d762'
>>> blake2b(digest_size=11).hexdigest()
'eb6ec15daf9546254f0809'
>>> blake2s(digest_size=10).hexdigest()
'1bf21a98c78a1c376ae9'
>>> blake2s(digest_size=11).hexdigest()
'567004bf96e4a25773ebf4'

Keyed hashing

密钥散列可用于身份验证,作为基于哈希的消息认证代码(HMAC)的更快,更简单的替代。由于从 BLAKE 继承了不可区分性属性,因此可以在前缀 MAC 模式下安全地使用 BLAKE2.

本示例说明如何为密钥b'message data'的消息b'message data'获取(十六进制编码的)128 位验证码:

>>> from hashlib import blake2b
>>> h = blake2b(key=b'pseudorandom key', digest_size=16)
>>> h.update(b'message data')
>>> h.hexdigest()
'3d363ff7401e02026f4a4687d4863ced'

作为一个实际示例,Web 应用程序可以对发送给用户的 cookie 进行对称签名,然后对其进行验证以确保它们未被篡改:

>>> from hashlib import blake2b
>>> from hmac import compare_digest
>>>
>>> SECRET_KEY = b'pseudorandomly generated server secret key'
>>> AUTH_SIZE = 16
>>>
>>> def sign(cookie):
...     h = blake2b(digest_size=AUTH_SIZE, key=SECRET_KEY)
...     h.update(cookie)
...     return h.hexdigest().encode('utf-8')
>>>
>>> def verify(cookie, sig):
...     good_sig = sign(cookie)
...     return compare_digest(good_sig, sig)
>>>
>>> cookie = b'user-alice'
>>> sig = sign(cookie)
>>> print("{0},{1}".format(cookie.decode('utf-8'), sig))
user-alice,b'43b3c982cf697e0c5ab22172d1ca7421'
>>> verify(cookie, sig)
True
>>> verify(b'user-bob', sig)
False
>>> verify(cookie, b'0102030405060708090a0b0c0d0e0f00')
False

即使存在本机键哈希模式,BLAKE2 当然也可以passhmac模块用于 HMAC 构造:

>>> import hmac, hashlib
>>> m = hmac.new(b'secret key', digestmod=hashlib.blake2s)
>>> m.update(b'message')
>>> m.hexdigest()
'e3c8102868d28b5ff85fc35dda07329970d1a01e273c37481326fe0c861c8142'

Randomized hashing

pass设置* salt *参数,用户可以将随机化引入哈希函数。随机散列可用于防止对数字签名中使用的散列函数的冲突攻击。

Note

随机散列设计用于以下情况:一方(消息准备者)生成要由另一方(消息签名者)签名的全部或部分消息。如果消息准备者能够发现加密哈希函数冲突(即,两条消息产生相同的哈希值),则他们可能会准备有意义的消息版本,这些消息将产生相同的哈希值和数字签名,但结果不同(例如,将$ 1,000,000 转移到一个帐户,而不是$ 10)。已经设计了以抗冲突为主要目标的密码散列函数,但是当前集中在攻击密码散列函数上可能会导致给定的密码散列函数提供的抗碰撞性低于预期。随机哈希处理pass降低准备者可以生成两个或多个消息的可能性,从而为签名者提供了额外的保护,这些消息finally会在数字签名生成过程中产生相同的哈希值-即使为哈希函数找到冲突是可行的。但是,当签名者准备了消息的所有部分时,使用随机散列可能会降低数字签名提供的安全性。

(NIST SP-800-106“数字签名的随机散列”)

在 BLAKE2 中,盐在初始化期间被作为对哈希函数的一次性 Importing,而不是作为每个压缩函数的 Importing。

Warning

使用 BLAKE2 或其他通用加密哈希函数(例如 SHA-256)进行的带盐度哈希(或仅哈希)不适用于哈希密码。有关更多信息,请参见BLAKE2 FAQ

>>> import os
>>> from hashlib import blake2b
>>> msg = b'some message'
>>> # Calculate the first hash with a random salt.
>>> salt1 = os.urandom(blake2b.SALT_SIZE)
>>> h1 = blake2b(salt=salt1)
>>> h1.update(msg)
>>> # Calculate the second hash with a different random salt.
>>> salt2 = os.urandom(blake2b.SALT_SIZE)
>>> h2 = blake2b(salt=salt2)
>>> h2.update(msg)
>>> # The digests are different.
>>> h1.digest() != h2.digest()
True

Personalization

有时,强制哈希函数针对相同的 Importing 出于不同的目的而产生不同的摘要很有用。引用 Skein 哈希函数的作者:

Note

我们建议所有应用程序设计人员认真考虑这样做。我们已经看到许多协议,其中协议的一部分中计算出的哈希可以在完全不同的部分中使用,因为对相似或相关数据进行了两次哈希计算,攻击者可以迫使应用程序将哈希 Importing 相同。对协议中使用的每个哈希函数进行个性化设置,将立即停止这种攻击。

(绞线哈希函数族,第 21 页)

可以pass将字节传递给* person *参数来个性化 BLAKE2:

>>> from hashlib import blake2b
>>> FILES_HASH_PERSON = b'MyApp Files Hash'
>>> BLOCK_HASH_PERSON = b'MyApp Block Hash'
>>> h = blake2b(digest_size=32, person=FILES_HASH_PERSON)
>>> h.update(b'the same content')
>>> h.hexdigest()
'20d9cd024d4fb086aae819a1432dd2466de12947831b75c5a30cf2676095d3b4'
>>> h = blake2b(digest_size=32, person=BLOCK_HASH_PERSON)
>>> h.update(b'the same content')
>>> h.hexdigest()
'cf68fb5761b9c44e7878bfb2c4c9aea52264a80b75005e65619778de59f383a3'

个性化以及键控模式也可以用于从单个键推导不同的键。

>>> from hashlib import blake2s
>>> from base64 import b64decode, b64encode
>>> orig_key = b64decode(b'Rm5EPJai72qcK3RGBpW3vPNfZy5OZothY+kHY6h21KM=')
>>> enc_key = blake2s(key=orig_key, person=b'kEncrypt').digest()
>>> mac_key = blake2s(key=orig_key, person=b'kMAC').digest()
>>> print(b64encode(enc_key).decode('utf-8'))
rbPb15S/Z9t+agffno5wuhB77VbRi6F9Iv2qIxU7WHw=
>>> print(b64encode(mac_key).decode('utf-8'))
G9GtHFE1YluXY1zWPlYk1e/nWfu0WSEb0KRcjhDeP/o=

Tree mode

这是对具有两个叶节点的最小树进行哈希处理的示例:

10
 /  \
00  01

本示例使用 64 字节内部摘要,并返回 32 字节finally摘要:

>>> from hashlib import blake2b
>>>
>>> FANOUT = 2
>>> DEPTH = 2
>>> LEAF_SIZE = 4096
>>> INNER_SIZE = 64
>>>
>>> buf = bytearray(6000)
>>>
>>> # Left leaf
... h00 = blake2b(buf[0:LEAF_SIZE], fanout=FANOUT, depth=DEPTH,
...               leaf_size=LEAF_SIZE, inner_size=INNER_SIZE,
...               node_offset=0, node_depth=0, last_node=False)
>>> # Right leaf
... h01 = blake2b(buf[LEAF_SIZE:], fanout=FANOUT, depth=DEPTH,
...               leaf_size=LEAF_SIZE, inner_size=INNER_SIZE,
...               node_offset=1, node_depth=0, last_node=True)
>>> # Root node
... h10 = blake2b(digest_size=32, fanout=FANOUT, depth=DEPTH,
...               leaf_size=LEAF_SIZE, inner_size=INNER_SIZE,
...               node_offset=0, node_depth=1, last_node=True)
>>> h10.update(h00.digest())
>>> h10.update(h01.digest())
>>> h10.hexdigest()
'3ad2a9b37c6070e374c7a8c508fe20ca86b6ed54e286e93a0318e95e881db5aa'

Credits

BLAKE2由* Jean-Philippe Aumasson Samuel Neves Zooko Wilcox-O'Hearn Christian Winnerlein 根据 Jean-Philippe Aumasson Luca Henzen *,创建的SHA-3决赛入围者BLAKE设计。 Willi Meier Raphael C.-W.潘

它使用由* Daniel J. Bernstein *设计的ChaCha密码的核心算法。

stdlib 实现基于pyblake2模块。它由* Dmitry Chestnykh 基于 Samuel Neves 编写的 C 实现编写。该文档是从pyblake2复制并由 Dmitry Chestnykh *编写的。

  • Christian Heimes *为 Python 重写了部分 C 代码。

以下公共领域专用代码适用于 C 哈希函数实现,扩展代码和本文档:

Note

在法律允许的范围内,作者已将此软件的所有版权以及与之相关的邻接权专用于 Global 的公共领域。该软件的分发没有任何保证。

您应该已经与该软件一起收到了 CC0 公共域专用证书的副本。如果不是,请参见https://creativecommons.org/publicdomain/zero/1.0/

根据“知识共享公共领域奉献 1.0 通用”,以下人员为项目和公共领域的开发提供了帮助或做出了贡献:

  • Alexandr Sokolovskiy

See also