hashlib ---安全hash和消息摘要

源代码: Lib/hashlib.py


该模块实现了许多不同的安全hash和消息摘要算法的公共接口。包括FIPS安全hash算法sha1、sha224、sha256、sha384和sha512(在FIPS 180-2中定义)以及RSA的MD5算法(在Internet中定义) RFC 1321 )术语“安全散列”和“消息摘要”是可互换的。旧的算法称为消息摘要。现代术语是安全散列。

注解

如果要使用adler32或crc32hash函数,可以在 zlib 模块。

警告

有些算法已知hash冲突的弱点,请参阅末尾的“另见”部分。

散列算法

对于每种类型的 hash . 全部返回具有相同简单接口的hash对象。例如:使用 sha256() 创建SHA-256hash对象。您现在可以使用 bytes-like objects (正常情况下 bytes )使用 update() 方法。任何时候你都可以要求 digest 到目前为止,使用 digest()hexdigest() 方法。

注解

为了获得更好的多线程性能,python GIL 在对象创建或更新时释放大于2047字节的数据。

注解

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

此模块中始终存在的哈希算法的构造函数为 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 新版功能: Sha3(Keccak)和震动构造器 sha3_224()sha3_256()sha3_384()sha3_512()shake_128()shake_256() .

3.6 新版功能: blake2b()blake2s() 加入。

在 3.9 版更改: 所有hashlib构造函数都只接受关键字参数 用于安全性 带默认值 True . 假值允许在受限环境中使用不安全和阻塞的哈希算法。 False 指示哈希算法未在安全上下文中使用,例如用作非加密单向压缩函数。

Hashlib现在使用OpenSSL 1.1.1和更新版本中的SHA3和SHAKE。

例如,获取字节字符串的摘要 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

更浓缩:

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

是接受字符串的泛型构造函数 name 作为第一个参数的所需算法。它还允许访问上面列出的hash以及您的OpenSSL库可能提供的任何其他算法。命名的构造函数比 new() 应优先考虑。

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

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

hashlib提供以下常量属性:

hashlib.algorithms_guaranteed

一个包含hash算法名称的集合,保证该模块在所有平台上都支持该hash算法。请注意,“md5”在这个列表中,尽管一些上游供应商提供了一个奇怪的“符合FIPS”的python构建,但不包括它。

3.2 新版功能.

hashlib.algorithms_available

包含运行中的Python解释器中可用的hash算法名称的集合。这些名称将在传递给 new() . algorithms_guaranteed 将始终是一个子集。相同的算法可能会在这个集合中以不同的名称出现多次(多亏了openssl)。

3.2 新版功能.

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

hash.digest_size

结果hash的大小(以字节为单位)。

hash.block_size

hash算法的内部块大小(字节)。

hash对象具有以下属性:

hash.name

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

在 3.4 版更改: name属性自创建以来就一直存在于cpython中,但在未正式指定python 3.4之前,它可能不存在于某些平台上。

hash对象具有以下方法:

hash.update(data)

使用更新hash对象 bytes-like object .重复调用相当于一个具有所有参数串联的调用: m.update(a); m.update(b) 等于 m.update(a+b) .

在 3.1 版更改: 当使用OpenSSL提供的hash算法对大于2047字节的数据进行hash更新时,python gil将允许其他线程运行。

hash.digest()

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

hash.hexdigest()

类似于 digest() 但Digest作为双长度的字符串对象返回,只包含十六进制数字。这可以用于在电子邮件或其他非二进制环境中安全地交换值。

hash.copy()

返回hash对象的副本(“复制”)。这可以用来有效地计算共享一个公共初始子字符串的数据摘要。

摇动可变长度消化道

这个 shake_128()shake_256() 算法提供的可变长度摘要的长度为u位//2高达128或256位的安全性。因此,它们的摘要方法需要一个长度。最大长度不受震动算法的限制。

shake.digest(length)

返回传递给的数据摘要 update() 迄今为止的方法。这是一个字节大小的对象 长度 它可以包含0到255之间的整个范围内的字节。

shake.hexdigest(length)

类似于 digest() 但Digest作为双长度的字符串对象返回,只包含十六进制数字。这可以用于在电子邮件或其他非二进制环境中安全地交换值。

导出密钥

密钥派生和密钥拉伸算法是为安全密码散列而设计的。简单的算法,如 sha1(password) 不能抵抗暴力攻击。一个好的密码散列函数必须是可调的、缓慢的,并且包含 salt .

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

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

hash_name 是HMAChash摘要算法的所需名称,例如“sha1”或“sha256”。 密码salt 被解释为字节缓冲区。应用程序和库应限制 密码 合理长度(如1024)。 salt 应该是来自正确源的大约16个或更多字节,例如 os.urandom() .

迭代 应该根据hash算法和计算能力来选择。截至2013年,建议至少100000次SHA-256迭代。

德克伦 是派生密钥的长度。如果 德克伦None 然后是hash算法的摘要大小 hash_name 使用,例如,用于SHA-512的64。

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

3.4 新版功能.

注解

快速实现 pbkdf2_hmac 可用于OpenSSL。python实现使用的是内联版本 hmac . 它大约慢了三倍,而且不释放镀金。

hashlib.scrypt(password, *, salt, n, r, p, maxmem=0, dklen=64)

该函数提供基于密码的密钥派生函数,如中定义的 RFC 7914 .

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

n 是CPU/内存成本因素, r 块大小, p 并联因数和 麦克默姆 限制内存(openssl 1.1.0默认为32mib)。 德克伦 是派生密钥的长度。

Availability OpenSSL 1.1 +。

3.6 新版功能.

BLAKE2

BLAKE2 是在中定义的加密hash函数 RFC 7693 有两种口味:

  • 布莱克2B ,针对64位平台进行了优化,并生成1到64字节之间的任何大小的摘要,

  • 布莱克2 ,针对8到32位平台进行了优化,并生成1到32字节之间的任何大小的摘要。

BLAKE2载体 键控模式 (更快、更简单地替代 HMAC) , **salted hashing**个人化树状散列 .

此模块中的hash对象遵循标准库的API hashlib 物体。

创建hash对象

通过调用构造函数函数创建新的hash对象:

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, usedforsecurity=True)
hashlib.blake2s(data=b'', *, digest_size=32, 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, usedforsecurity=True)

这些函数返回用于计算blake2b或blake2s的相应hash对象。它们可以选择使用以下常规参数:

  • data :要hash的初始数据块,必须是 bytes-like object . 它只能作为位置参数传递。

  • digest_size :输出摘要的大小(字节)。

  • key :键控散列键(blake2b最多64个字节,blake2s最多32个字节)。

  • salt :随机散列的salt(blake2b最多16个字节,blake2s最多8个字节)。

  • :个性化字符串(Blake2b最多16个字节,Blake2s最多8个字节)。

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

搞砸

digest_size

len(键)

莱恩(盐)

莱恩(人)

布莱克2B

64

64

16

16

布莱克2

32

32

8

8

注解

Blake2规范为salt和个性化参数定义了常量长度,但是为了方便起见,此实现接受任何大小的字节字符串,最大为指定长度。如果参数的长度小于指定的长度,则用零填充,例如, b'salt'b'salt\x00' 是相同的值。(事实并非如此 key

这些尺寸可作为模块提供 constants 如下所述。

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

  • 扇出 :扇出(0到255,如果不受限制,则为0,顺序模式下为1)。

  • 深度 :树的最大深度(1到255,如果不受限制,则为255,顺序模式下为1)。

  • leaf_size :叶的最大字节长度(0到2**32-1,如果不受限制或处于顺序模式,则为0)。

  • node_offset :节点偏移(0到2 64-1 for BLAKE2b, 0 to 2 48-1表示blake2s,0表示第一个、最左边、叶,或以顺序模式)。

  • node_depth :节点深度(0到255,0表示叶,或以顺序模式)。

  • inner_size :内部摘要大小(Blake2b为0到64,Blake2s为0到32,顺序模式为0)。

  • last_node :布尔值,指示处理的节点是否是最后一个节点(对于顺序模式,“false”)。

树模式参数说明。

见第2.10节 BLAKE2 specification 对于树散列的全面审查。

常量

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

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

实例

简单散列

要计算某些数据的hash值,应首先通过调用适当的构造函数函数构造hash对象。 (blake2b()blake2s() ,然后通过调用 update() 在对象上,最后通过调用 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() 重复更新hash所需的次数:

>>> 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

具有不同摘要大小的hash对象具有完全不同的输出(较短的hash为 not 较长hash的前缀);即使输出长度相同,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'

键控散列

作为对 Hash-based message authentication code (HMAC)。Blake2可以在前缀mac模式下安全使用,这得益于从Blake继承的无差异性属性。

此示例演示如何为消息获取(十六进制编码)128位身份验证代码。 b'message data' 带钥匙 b'pseudorandom key' ::

>>> 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当然可以用于hmac结构 hmac 模块:

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

随机散列

通过设置 salt 参数用户可以将随机化引入散列函数。随机散列对于防止数字签名中使用的散列函数受到冲突攻击非常有用。

随机散列是为一方(消息准备者)生成消息的全部或部分,由第二方(消息签名者)签名的情况而设计的。如果消息准备器能够发现加密hash函数冲突(即,两条消息产生相同的hash值),那么他们可以准备消息的有意义的版本,该版本将产生相同的hash值和数字签名,但结果不同(例如,将1000000美元转移到一个帐户,而不是10美元)。密码散列函数的设计以抗碰撞性为主要目标,但当前集中攻击密码散列函数的情况可能导致给定的密码散列函数提供的抗碰撞性比预期的要小。随机散列通过降低准备者在数字签名生成过程中生成最终生成相同散列值的两条或多条消息的可能性(即使为散列函数找到冲突是可行的),为签名者提供了额外的保护。但是,当消息的所有部分都由签名者准备时,使用随机散列可能会减少数字签名提供的安全性。

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

在blake2中,salt在初始化期间被处理为hash函数的一次性输入,而不是作为每个压缩函数的输入。

警告

*salted hashing* (或只是散列)使用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

个人化

有时为了不同的目的,强制hash函数为相同的输入生成不同的摘要是有用的。引用skeinhash函数的作者:

我们建议所有应用程序设计者认真考虑这样做;我们已经看到许多协议,其中一部分协议中计算的hash可以在完全不同的部分中使用,因为两个hash计算是在类似或相关数据上进行的,攻击者可以强制应用程序使hash输入相同。对协议中使用的每个散列函数进行个性化,可以立即停止这种类型的攻击。

(` skeinhash函数族 <http://www.skein-hash.info/sites/default/files/skein1.3.pdf>`_, 第21页)

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=

树模式

下面是一个使用两个叶节点散列最小树的示例:

  10
 /  \
00  01

此示例使用64字节的内部摘要,并返回32字节的最终摘要:

>>> 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'

信用

BLAKE2 是由 Jean-Philippe Aumasson塞缪尔内维尔Zooko Wilcox-O'Hearn克里斯蒂安·温纳 基于 SHA-3 决赛选手 BLAKE 创建的 Jean-Philippe Aumasson卢卡亨森威利米耶Raphael C.-W. Phan .

它使用的核心算法来自 ChaCha 密码设计人 丹尼尔·伯恩斯坦 .

stdlib实现基于 pyblake2 模块。它是由 德米特里·切斯特尼赫 基于C实现编写者 塞缪尔内维尔 . 文件是从 pyblake2 写的 德米特里·切斯特尼赫 .

C代码被部分重写为python 克里斯蒂安·海姆斯 .

以下公共域奉献适用于Chash函数实现、扩展代码和本文档:

在法律允许的范围内,作者已将本软件的所有版权和相关及邻近权利专用于全球公共领域。本软件无需任何担保即可分发。

您应该已经收到了一份CC0公共领域奉献与此软件的副本。如果没有,请参阅https://creativecommons.org/publicdomain/zero/1.0/。

根据创意共享公共领域贡献1.0 Universal,以下人员帮助开发或对项目和公共领域做出了贡献:

  • 亚历山大·索科洛夫斯基

参见

模块 hmac

使用hash生成消息身份验证代码的模块。

模块 base64

另一种为非二进制环境编码二进制散列的方法。

https://blake2.net

官方blake2网站。

https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf

关于安全hash算法的FIPS 180-2出版物。

https://en.wikipedia.org/wiki/cryptographic_hash_function cryptographic_hash_算法

维基百科的一篇文章,介绍了哪些算法存在已知问题,以及这些算法的使用意味着什么。

https://www.ietf.org/rfc/rfc8018.txt

PKCS#5:基于密码的加密规范版本2.1