You are here:  Home » Python » hashlib哈希算法和消息摘要(1)Python加密处理(必读进阶Python教程)(参考资料)

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

注意

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

警告

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

哈希算法

为每种类型的哈希命名了一个构造函数方法。全部返回具有相同简单接口的哈希对象。例如:用于sha256()创建SHA-256哈希对象。您现在可以使用该方法使用类似字节的对象(通常bytes)来提供此对象update()。在任何时候,您都可以使用或 方法询问它到目前为止为其提供的数据串联的摘要digest()hexdigest()

注意

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

注意

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版: SHA3​​(Keccak)和SHAKE构造sha3_224()sha3_256(), sha3_384()sha3_512()shake_128()shake_256()

新的3.6版: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

 

更浓缩:

>>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest()
'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'

 

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

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

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

 

Hashlib提供以下常量属性:

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

版本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数据
使用类似字节的对象更新哈希对象。重复调用相当于单个调用,并且所有参数都连接在一起:相当于。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变长生成

shake_128()shake_256()算法提供可变长度的消化物与length_in_bits // 2到安全的128或256位。因此,他们的摘要方法需要一定的长度。最大长度不受SHAKE算法的限制。

shake.digest长度
返回update()到目前为止传递给方法的数据的摘要。这是一个大小为length的字节对象,可能包含0到255范围内的整个字节。
shake.hexdigest长度
就像digest()除了摘要作为双倍长度的字符串对象返回,只包含十六进制数字。这可用于在电子邮件或其他非二进制环境中安全地交换值。

密钥派生

密钥推导和密钥扩展算法是为安全密码散列而设计的。天真的算法,如sha1(password)不抵抗暴力攻击。一个好的密码散列函数必须是可调的,慢的,并包含一个盐。

hashlib.pbkdf2_hmachash_namepasswordsaltiterationsdklen = None 
该功能提供PKCS#5基于密码的密钥导出功能2.它使用HMAC作为伪随机函数。

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

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

dklen是派生密钥的长度。如果dklenNone哈希算法hash_name的摘要大小,则使用例如64的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。

hashlib.scrypt密码*nrpmaxmem = 0dklen = 64 
该函数提供了基于密码的scrypt密钥派生函数,如中所定义 RFC 7914

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

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

可用性:OpenSSL 1.1+。

版本3.6中的新功能。

BLAKE2

BLAKE2是一个定义的加密哈希函数RFC 7693有两种版本:

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

BLAKE2支持键控模式(更快更简单的HMAC替换), 盐渍散列个性化树形散列

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

创建哈希对象

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

hashlib.blake2bdata = b”*digest_size = 64key = b”salt = b”person = b”fanout = 1depth = 1leaf_size = 0node_offset = 0node_depth = 0inner_size = 0last_node = False 
hashlib.blake2sdata = b”*digest_size = 32key = b”salt = b”person = b”fanout = 1depth = 1leaf_size = 0node_offset = 0node_depth = 0inner_size = 0last_node = False 

这些函数返回相应的哈希对象以计算BLAKE2b或BLAKE2。他们可选择采用以下一般参数:

  • data:要初始化的数据块,它必须是 类似字节的对象。它只能作为位置参数传递。
  • digest_size:输出摘要的大小(以字节为单位)。
  • key:键控散列的键(BLAKE2b最多64个字节,BLAKE2最多32个字节)。
  • salt:用于随机散列的salt(BLAKE2b最多16个字节,BLAKE2最多8个字节)。
  • person:个性化字符串(BLAKE2b最多16个字节,BLAKE2最多8个字节)。

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

哈希 digest_size LEN(钥匙) LEN(盐) LEN(人)
BLAKE2b 64 64 16 16
BLAKE2s 32 32 8 8

注意

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

这些尺寸可用作下面描述的模块常数。

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

  • 扇出:扇出(0到255,如果无限制则为0,顺序模式为1)。
  • 深度:树的最大深度(1到255,如果无限制则为255,在顺序模式下为1)。
  • leaf_size:叶子的最大字节长度(0到2 ** 32-1,0如果无限制或在顺序模式下)。
  • node_offset:节点偏移量(BLAKE2b为 0到2 ** 64-1,BLAKE2为0到2 ** 48-1,第一个,最左边,叶子或顺序模式为0)。
  • node_depth:节点深度(0到255,叶子为0或顺序模式)。
  • inner_size:内部摘要大小(BLAKE2b为0到64,BLAKE2为0到32,顺序模式为0)。
  • last_node:boolean指示处理的节点是否是最后一个节点(顺序模式为False)。
树模式参数的说明。

有关树哈希的综合评论,请参阅BLAKE2规范中的 2.10节。

常数

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

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

示例

简单散列

要计算某些数据的哈希值,首先应该通过调用相应的构造函数(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()根据需要多次调用迭代更新哈希:

>>> 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个字节,BLAKE2最多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

 

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

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

 

键控散列

密钥哈希可用于身份验证,作为基于哈希的消息身份验证代码(HMAC)的更快,更简单的替代。由于从BLAKE继承的无差异属性,BLAKE2可以安全地用于前缀MAC模式。

此示例显示如何使用密钥获取消息的(十六进制编码的)128位身份验证代码:b'message data'b'pseudorandomkey'

>>>
>>> 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参数,用户可以将随机化引入哈希函数。随机散列对于防止对数字签名中使用的散列函数的冲突攻击很有用。

随机散列是针对一方(消息编写者)生成要由第二方(消息签名者)签名的全部或部分消息的情况而设计的。如果消息准备者能够找到加密散列函数冲突(即,两个消息产生相同的散列值),那么他们可能会准备有意义的消息版本,这些消息将产生相同的散列值和数字签名,但结果不同(例如,将1,000,000美元转入一个帐户,而不是10美元。密码散列函数已经设计为具有抗冲突性作为主要目标,但是当前对攻击加密散列函数的集中可能导致给定的加密散列函数提供比预期更少的碰撞阻力。随机散列通过降低编制者可以生成两个或多个消息的可能性来为签名者提供额外的保护,这些消息最终在数字签名生成过程中产生相同的散列值 – 即使找到散列函数的冲突是可行的。然而,当签名者准备好消息的所有部分时,使用随机散列可以减少数字签名所提供的安全性。

(NIST SP-800-106“用于数字签名的随机哈希”)

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

警告

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

 

个性化

有时,为了不同的目的,强制散列函数为相同的输入生成不同的摘要是有用的。引用Skein哈希函数的作者:

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

(Skein Hash函数族,第21页)

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

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

 

积分

BLAKE2Jean-Philippe AumassonSamuel NevesZooko Wilcox-O’HearnChristian Winnerlein设计,基于由Jean-Philippe AumassonLuca HenzenWilli Meier和 Raphael C. -W创建的SHA-3决赛BLAKE。

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

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

C代码部分由Christian Heimes重写为Python 。

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

在法律允许的范围内,作者已将此软件的所有版权及相关和邻接权利用于全球公共领域。本软件的发布不附带任何保证。

您应该已经收到了CC0 Public Domain Dedication的副本以及该软件。如果没有,请参阅https://creativecommons.org/publicdomain/zero/1.0/。

根据Creative Commons Public Domain Dedication 1.0 Universal,以下人员帮助开发或贡献他们对项目和公共领域的更改:

  • Alexandr Sokolovskiy

也可以看看

模 hmac
使用哈希生成消息身份验证代码的模块。
模 base64
另一种为非二进制环境编码二进制哈希的方法。
https://blake2.net
官方BLAKE2网站。
https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/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版