hashlib --- 安全哈希與消息摘要?

源碼: Lib/hashlib.py


這個模塊針對許多不同的安全哈希和消息摘要算法實現(xiàn)了一個通用接口。 包括 FIPS 安全哈希算法 SHA1, SHA224, SHA256, SHA384 和 SHA512 (定義于 FIPS 180-2) 以及 RSA 的 MD5 算法 (定義于互聯(lián)網(wǎng) RFC 1321)。 術(shù)語 "安全哈希" 和 "消息摘要" 是同義的。 較舊的算法被稱為消息摘要。 現(xiàn)代的術(shù)語是安全哈希。

備注

如果你想找到 adler32 或 crc32 哈希函數(shù),它們在 zlib 模塊中。

警告

有些算法已知存在哈希碰撞弱點,請參考最后的“另請參閱”段。

哈希算法?

每種類型的 hash 都有一個構(gòu)造器方法。 它們都返回一個具有相同的簡單接口的 hash 對象。 例如,使用 use sha256() 創(chuàng)建一個 SHA-256 hash 對象。 你可以使用 update() 方法向這個對象輸入 字節(jié)類對象 (通常是 bytes)。 在任何時候你都可以使用 digest()hexdigest() 方法獲得到目前為止輸入這個對象的拼接數(shù)據(jù)的 digest。

備注

為了更好的多線程性能,在對象創(chuàng)建或者更新時,若數(shù)據(jù)大于2047字節(jié)則 Python 的 GIL 會被釋放。

備注

update() 輸入字符串對象是不被支持的,因為哈希基于字節(jié)而非字符。

此模塊中總是可用的哈希算法構(gòu)造器有 sha1(), sha224(), sha256(), sha384(), sha512(), blake2b()blake2s()。 md5() 通常也是可用的,但如果你在使用少見的 "FIPS 兼容" 的 Python 編譯版本則可能會找不到它。 此外還可能有一些附加的算法,具體取決于你的平臺上的 Python 所使用的 OpenSSL 庫。 在大部分平臺上可用的還有 sha3_224(), sha3_256(), sha3_384(), sha3_512(), shake_128(), shake_256() 等等?!?/p>

3.6 新版功能: SHA3 (Keccak) 和 SHAKE 構(gòu)造器 sha3_224(), sha3_256(), sha3_384(), sha3_512(), shake_128(), shake_256().

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

在 3.9 版更改: 所有 hashlib 的構(gòu)造器都接受僅限關鍵字參數(shù) usedforsecurity 且其默認值為 True。 設為假值即允許在受限的環(huán)境中使用不安全且阻塞的哈希算法。 False 表示此哈希算法不可用于安全場景,例如用作非加密的單向壓縮函數(shù)。

現(xiàn)在 hashlib 會使用 OpenSSL 1.1.1 或更新版本的 SHA3 和 SHAKE。

For example, to obtain the digest of the byte string 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.hexdigest()
'031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406'

更簡要的寫法:

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

一個接受所希望的算法對應的字符串 name 作為第一個形參的通用構(gòu)造器。 它還允許訪問上面列出的哈希算法以及你的 OpenSSL 庫可能提供的任何其他算法。 同名的構(gòu)造器要比 new() 更快所以應當優(yōu)先使用。

使用 new() 并附帶由 OpenSSL 所提供了算法:

>>>
>>> h = hashlib.new('sha256')
>>> h.update(b"Nobody inspects the spammish repetition")
>>> h.hexdigest()
'031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406'

Hashlib 提供下列常量屬性:

hashlib.algorithms_guaranteed?

一個集合,其中包含此模塊在所有平臺上都保證支持的哈希算法的名稱。 請注意 'md5' 也在此清單中,雖然某些上游廠商提供了一個怪異的排除了此算法的 "FIPS 兼容" Python 編譯版本。

3.2 新版功能.

hashlib.algorithms_available?

一個集合,其中包含在所運行的 Python 解釋器上可用的哈希算法的名稱。 將這些名稱傳給 new() 時將可被識別。 algorithms_guaranteed 將總是它的一個子集。 同樣的算法在此集合中可能以不同的名稱出現(xiàn)多次(這是 OpenSSL 的原因)。

3.2 新版功能.

下列值會以構(gòu)造器所返回的哈希對象的常量屬性的形式被提供:

hash.digest_size?

以字節(jié)表示的結(jié)果哈希對象的大小。

hash.block_size?

以字節(jié)表示的哈希算法的內(nèi)部塊大小。

hash 對象具有以下屬性:

hash.name?

此哈希對象的規(guī)范名稱,總是為小寫形式并且總是可以作為 new() 的形參用來創(chuàng)建另一個此類型的哈希對象。

在 3.4 版更改: 該屬性名稱自被引入起即存在于 CPython 中,但在 Python 3.4 之前并未正式指明,因此可能不存在于某些平臺上。

哈希對象具有下列方法:

hash.update(data)?

bytes-like object 來更新哈希對象。 重復調(diào)用相當于單次調(diào)用并傳入所有參數(shù)的拼接結(jié)果: m.update(a); m.update(b) 等價于 m.update(a+b)

在 3.1 版更改: 當使用 OpenSSL 提供的哈希算法在大于 2047 字節(jié)的數(shù)據(jù)上執(zhí)行哈希更新時 Python GIL 會被釋放以允許其他線程運行。

hash.digest()?

返回當前已傳給 update() 方法的數(shù)據(jù)摘要。 這是一個大小為 digest_size 的字節(jié)串對象,字節(jié)串中可包含 0 至 255 的完整取值范圍。

hash.hexdigest()?

類似于 digest() 但摘要會以兩倍長度字符串對象的形式返回,其中僅包含十六進制數(shù)碼。 這可以被用于在電子郵件或其他非二進制環(huán)境中安全地交換數(shù)據(jù)值。

hash.copy()?

返回哈希對象的副本(“克隆”)。 這可被用來高效地計算共享相同初始子串的數(shù)據(jù)的摘要。

SHAKE 可變長度摘要?

shake_128()shake_256() 算法提供安全的 length_in_bits//2 至 128 或 256 位可變長度摘要。 為此,它們的摘要需指定一個長度。 SHAKE 算法不限制最大長度。

shake.digest(length)?

返回當前已傳給 update() 方法的數(shù)據(jù)摘要。 這是一個大小為 length 的字節(jié)串對象,字節(jié)串中可包含 0 to 255 的完整取值范圍。

shake.hexdigest(length)?

類似于 digest() 但摘要會以兩倍長度字符串對象的形式返回,其中僅包含十六進制數(shù)碼。 這可以被用于在電子郵件或其他非二進制環(huán)境中安全地交換數(shù)據(jù)值。

File hashing?

The hashlib module provides a helper function for efficient hashing of a file or file-like object.

hashlib.file_digest(fileobj, digest, /)?

Return a digest object that has been updated with contents of file object.

fileobj must be a file-like object opened for reading in binary mode. It accepts file objects from builtin open(), BytesIO instances, SocketIO objects from socket.socket.makefile(), and similar. The function may bypass Python's I/O and use the file descriptor from fileno() directly. fileobj must be assumed to be in an unknown state after this function returns or raises. It is up to the caller to close fileobj.

digest must either be a hash algorithm name as a str, a hash constructor, or a callable that returns a hash object.

Example:

>>>
>>> import io, hashlib, hmac
>>> with open(hashlib.__file__, "rb") as f:
...     digest = hashlib.file_digest(f, "sha256")
...
>>> digest.hexdigest()  
'...'
>>>
>>> buf = io.BytesIO(b"somedata")
>>> mac1 = hmac.HMAC(b"key", digestmod=hashlib.sha512)
>>> digest = hashlib.file_digest(buf, lambda: mac1)
>>>
>>> digest is mac1
True
>>> mac2 = hmac.HMAC(b"key", b"somedata", digestmod=hashlib.sha512)
>>> mac1.digest() == mac2.digest()
True

3.11 新版功能.

密鑰派生?

密鑰派生和密鑰延展算法被設計用于安全密碼哈希。 sha1(password) 這樣的簡單算法無法防御暴力攻擊。 好的密碼哈希函數(shù)必須可以微調(diào)、放慢步調(diào),并且包含 加鹽。

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

此函數(shù)提供 PKCS#5 基于密碼的密鑰派生函數(shù) 2。 它使用 HMAC 作為偽隨機函數(shù)。

字符串 hash_name 是要求用于 HMAC 的哈希摘要算法的名稱,例如 'sha1' 或 'sha256'。 passwordsalt 會以字節(jié)串緩沖區(qū)的形式被解析。 應用和庫應當將 password 限制在合理長度 (例如 1024)。 salt 應當為適當來源例如 os.urandom() 的大約 16 個或更多的字節(jié)串數(shù)據(jù)。

The number of iterations should be chosen based on the hash algorithm and computing power. As of 2022, hundreds of thousands of iterations of SHA-256 are suggested. For rationale as to why and how to choose what is best for your application, read Appendix A.2.2 of NIST-SP-800-132. The answers on the stackexchange pbkdf2 iterations question explain in detail.

dklen 為派生密鑰的長度。 如果 dklenNone 則會使用哈希算法 hash_name 的摘要大小,例如 SHA-512 為 64。

>>>
>>> from hashlib import pbkdf2_hmac
>>> our_app_iters = 500_000  # Application specific, read above.
>>> dk = pbkdf2_hmac('sha256', b'password', b'bad salt'*2, our_app_iters)
>>> dk.hex()
'15530bba69924174860db778f2c6f8104d3aaf9d26241840c8c4a641c8d000a9'

3.4 新版功能.

備注

隨同 OpenSSL 提供了一個快速的 pbkdf2_hmac 實現(xiàn)。 Python 實現(xiàn)是使用 hmac 的內(nèi)聯(lián)版本。 它的速度大約要慢上三倍并且不會釋放 GIL。

3.10 版后已移除: 較慢的 pbkdf2_hmac Python 實現(xiàn)已被棄用。 未來該函數(shù)將僅在 Python 附帶 OpenSSL 編譯時可用。

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

此函數(shù)提供基于密碼加密的密鑰派生函數(shù),其定義參見 RFC 7914。

passwordsalt 必須為 字節(jié)類對象。 應用和庫應當將 password 限制在合理長度 (例如 1024)。 salt 應當為適當來源例如 os.urandom() 的大約 16 個或更多的字節(jié)串數(shù)據(jù)。

n 為 CPU/內(nèi)存開銷因子,r 為塊大小,p 為并行化因子,maxmem 為內(nèi)存限制 (OpenSSL 1.1.0 默認為 32 MiB)。 dklen 為派生密鑰的長度。

3.6 新版功能.

BLAKE2?

BLAKE2 是在 RFC 7693 中定義的加密哈希函數(shù),它有兩種形式:

  • BLAKE2b,針對 64 位平臺進行優(yōu)化,并會生成長度介于 1 和 64 字節(jié)之間任意大小的摘要。

  • BLAKE2s,針對 8 至 32 位平臺進行優(yōu)化,并會生成長度介于 1 和 32 字節(jié)之間任意大小的摘要。

BLAKE2 支持 keyed mode (HMAC 的更快速更簡單的替代), salted hashing, personalizationtree hashing.

此模塊的哈希對象遵循標準庫 hashlib 對象的 API。

創(chuàng)建哈希對象?

新哈希對象可通過調(diào)用構(gòu)造器函數(shù)來創(chuàng)建:

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

這些函數(shù)返回用于計算 BLAKE2b 或 BLAKE2s 的相應的哈希對象。 它們接受下列可選通用形參:

  • data: 要哈希的初始數(shù)據(jù)塊,它必須為 bytes-like object。 它只能作為位置參數(shù)傳入。

  • digest_size: 以字節(jié)數(shù)表示的輸出摘要大小。

  • key: 用于密鑰哈希的密鑰(對于 BLAKE2b 最長 64 字節(jié),對于 BLAKE2s 最長 32 字節(jié))。

  • salt: 用于隨機哈希的鹽值(對于 BLAKE2b 最長 16 字節(jié),對于 BLAKE2s 最長 8 字節(jié))。

  • person: 個性化字符串(對于 BLAKE2b 最長 16 字節(jié),對于 BLAKE2s 最長 8 字節(jié))。

下表顯示了常規(guī)參數(shù)的限制(以字節(jié)為單位):

Hash

目標長度

長度(鍵)

長度(鹽)

長度(個人)

BLAKE2b

64

64

16

16

BLAKE2s

32

32

8

8

備注

BLAKE2 規(guī)格描述為鹽值和個性化形參定義了固定的長度,但是為了方便起見,此實現(xiàn)接受指定在長度以內(nèi)的任意大小的字節(jié)串。 如果形參長度小于指定值,它將以零值進行填充,因此舉例來說,b'salt'b'salt\x00' 為相同的值 (key 的情況則并非如此。)

如下面的模塊 constants 所描述,這些是可用的大小取值。

構(gòu)造器函數(shù)還接受下列樹形哈希形參:

  • fanout: 扇出值 (0 至 255,如無限制即為 0,連續(xù)模式下為 1)。

  • depth: 樹的最大深度 (1 至 255,如無限制則為 255,連續(xù)模式下為 1)。

  • leaf_size: maximal byte length of leaf (0 to 2**32-1, 0 if unlimited or in sequential mode).

  • node_offset: node offset (0 to 2**64-1 for BLAKE2b, 0 to 2**48-1 for BLAKE2s, 0 for the first, leftmost, leaf, or in sequential mode).

  • node_depth: 節(jié)點深度 (0 至 255,對于葉子或在連續(xù)模式下則為 0)。

  • inner_size: 內(nèi)部摘要大小 (對于 BLAKE2b 為 0 至 64,對于 BLAKE2s 為 0 至 32,連續(xù)模式下則為 0)。

  • last_node: 一個布爾值,指明所處理的節(jié)點是否為最后一個 (連續(xù)模式下則為 False)。

樹模式形參的說明。

請參閱 BLAKE2 規(guī)格描述 第 2.10 節(jié)獲取有關樹形哈希的完整說明。

常量?

blake2b.SALT_SIZE?
blake2s.SALT_SIZE?

鹽值長度(構(gòu)造器所接受的最大長度)。

blake2b.PERSON_SIZE?
blake2s.PERSON_SIZE?

個性化字符串長度(構(gòu)造器所接受的最大長度)。

blake2b.MAX_KEY_SIZE?
blake2s.MAX_KEY_SIZE?

最大密鑰長度。

blake2b.MAX_DIGEST_SIZE?
blake2s.MAX_DIGEST_SIZE?

哈希函數(shù)可輸出的最大摘要長度。

例子?

簡單哈希?

要計算某個數(shù)據(jù)的哈希值,你應該首先通過調(diào)用適當?shù)臉?gòu)造器函數(shù) (blake2b()blake2s()) 來構(gòu)造一個哈希對象,然后通過在該對象上調(diào)用 update() 來更新目標數(shù)據(jù),最后通過調(diào)用 digest() (或針對十六進制編碼字符串的 hexdigest()) 來獲取該對象的摘要。

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

作為快捷方式,你可以直接以位置參數(shù)的形式向構(gòu)造器傳入第一個數(shù)據(jù)塊來直接更新:

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

你可以多次調(diào)用 hash.update() 至你所想要的任意次數(shù)以迭代地更新哈希值:

>>>
>>> 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 字節(jié),對于 BLAKE2s 最多 32 字節(jié)。 例如,要使用 BLAKE2b 來替代 SHA-1 而不改變輸出大小,我們可以讓 BLAKE2b 產(chǎn)生 20 個字節(jié)的摘要:

>>>
>>> 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 和 BLAKE2s 也會產(chǎn)生不同的輸出:

>>>
>>> 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 can be used for authentication as a faster and simpler replacement for Hash-based message authentication code (HMAC). BLAKE2 can be securely used in prefix-MAC mode thanks to the indifferentiability property inherited from BLAKE.

這個例子演示了如何使用密鑰 b'pseudorandom key' 來為 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 應用可為發(fā)送給用戶的 cookies 進行對稱簽名,并在之后對其進行驗證以確保它們沒有被篡改:

>>>
>>> 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 構(gòu)造過程中使用:

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

隨機哈希?

用戶可通過設置 salt 形參來為哈希函數(shù)引入隨機化。 隨機哈希適用于防止對數(shù)字簽名中使用的哈希函數(shù)進行碰撞攻擊。

隨機哈希被設計用來處理當一方(消息準備者)要生成由另一方(消息簽名者)進行簽名的全部或部分消息的情況。 如果消息準備者能夠找到加密哈希函數(shù)的碰撞現(xiàn)象(即兩條消息產(chǎn)生相同的哈希值),則他們就可以準備將產(chǎn)生相同哈希值和數(shù)字簽名但卻具有不同結(jié)果的有意義的消息版本(例如向某個賬戶轉(zhuǎn)入 $1,000,000 而不是 $10)。 加密哈希函數(shù)的設計都是以防碰撞性能為其主要目標之一的,但是當前針對加密哈希函數(shù)的集中攻擊可能導致特定加密哈希函數(shù)所提供的防碰撞性能低于預期。 隨機哈希為簽名者提供了額外的保護,可以降低準備者在數(shù)字簽名生成過程中使得兩條或更多條消息最終產(chǎn)生相同哈希值的可能性 --- 即使為特定哈希函數(shù)找到碰撞現(xiàn)象是可行的。 但是,當消息的所有部分均由簽名者準備時,使用隨機哈??赡芙档蛿?shù)字簽名所提供的安全性。

(NIST SP-800-106 "數(shù)字簽名的隨機哈希")

在 BLAKE2 中,鹽值會在初始化期間作為對哈希函數(shù)的一次性輸入而不是對每個壓縮函數(shù)的輸入來處理。

警告

使用 BLAKE2 或任何其他通用加密哈希函數(shù)例如 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

個性化?

出于不同的目的強制讓哈希函數(shù)為相同的輸入生成不同的摘要有時也是有用的。 正如 Skein 哈希函數(shù)的作者所言:

我們建議所有應用設計者慎重考慮這種做法;我們已看到有許多協(xié)議在協(xié)議的某一部分中計算出來的哈希值在另一個完全不同的部分中也可以被使用,因為兩次哈希計算是針對類似或相關的數(shù)據(jù)進行的,這樣攻擊者可以強制應用為相同的輸入生成哈希值。 個性化協(xié)議中所使用的每個哈希函數(shù)將有效地阻止這種類型的攻擊。

(Skein 哈希函數(shù)族, p. 21)

BLAKE2 可通過向 person 參數(shù)傳入字節(jié)串來進行個性化:

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

樹形模式?

以下是對包含兩個葉子節(jié)點的最小樹進行哈希的例子:

  10
 /  \
00  01

這個例子使用 64 字節(jié)內(nèi)部摘要,返回 32 字節(jié)最終摘要:

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

開發(fā)人員?

BLAKE2 是由 Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'HearnChristian Winnerlein 基于 Jean-Philippe Aumasson, Luca Henzen, Willi MeierRaphael C.-W. Phan 所創(chuàng)造的 SHA-3 入圍方案 BLAKE 進行設計的。

它使用的核心算法來自由 Daniel J. Bernstein 所設計的 ChaCha 加密。

stdlib 實現(xiàn)是基于 pyblake2 模塊的。 它由 Dmitry ChestnykhSamuel Neves 所編寫的 C 實現(xiàn)的基礎上編寫。 此文檔拷貝自 pyblake2 并由 Dmitry Chestnykh 撰寫。

C 代碼由 Christian Heimes 針對 Python 進行了部分的重寫。

以下公共領域貢獻同時適用于 C 哈希函數(shù)實現(xiàn)、擴展代碼和本文檔:

在法律許可的范圍內(nèi),作者已將此軟件的全部版權(quán)以及關聯(lián)和鄰接權(quán)利貢獻到全球公共領域。 此軟件的發(fā)布不附帶任何擔保。

你應該已收到此軟件附帶的 CC0 公共領域?qū)僮C書的副本。 如果沒有,請參閱 https://creativecommons.org/publicdomain/zero/1.0/。

根據(jù)創(chuàng)意分享公共領域貢獻 1.0 通用規(guī)范,下列人士為此項目的開發(fā)提供了幫助或?qū)差I域的修改作出了貢獻:

  • Alexandr Sokolovskiy

參見

模塊 hmac

使用哈希運算來生成消息驗證代碼的模塊。

模塊 base64

針對非二進制環(huán)境對二進制哈希值進行編輯的另一種方式。

https://blake2.net

BLAKE2 官方網(wǎng)站

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

包含關于哪些算法存在已知問題以及對其使用所造成的影響的信息的 Wikipedia 文章。

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

PKCS #5: 基于密碼的加密規(guī)范描述 2.1 版

https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf

NIST Recommendation for Password-Based Key Derivation.