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

源碼: Lib/hashlib.py


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

備注

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

警告

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

哈希算法?

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

備注

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

備注

update() 輸入字符串對象是不被支持的,因為哈?;谧止澏亲址?。

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

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

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

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

現在 hashlib 會(huì )使用 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'

更簡(jiǎn)要的寫(xiě)法:

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

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

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

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

Hashlib 提供下列常量屬性:

hashlib.algorithms_guaranteed?

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

3.2 新版功能.

hashlib.algorithms_available?

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

3.2 新版功能.

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

hash.digest_size?

以字節表示的結果哈希對象的大小。

hash.block_size?

以字節表示的哈希算法的內部塊大小。

hash 對象具有以下屬性:

hash.name?

此哈希對象的規范名稱(chēng),總是為小寫(xiě)形式并且總是可以作為 new() 的形參用來(lái)創(chuàng )建另一個(gè)此類(lèi)型的哈希對象。

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

哈希對象具有下列方法:

hash.update(data)?

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

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

hash.digest()?

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

hash.hexdigest()?

類(lèi)似于 digest() 但摘要會(huì )以?xún)杀堕L(cháng)度字符串對象的形式返回,其中僅包含十六進(jìn)制數碼。 這可以被用于在電子郵件或其他非二進(jìn)制環(huán)境中安全地交換數據值。

hash.copy()?

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

SHAKE 可變長(cháng)度摘要?

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

shake.digest(length)?

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

shake.hexdigest(length)?

類(lèi)似于 digest() 但摘要會(huì )以?xún)杀堕L(cháng)度字符串對象的形式返回,其中僅包含十六進(jìn)制數碼。 這可以被用于在電子郵件或其他非二進(jìn)制環(huán)境中安全地交換數據值。

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) 這樣的簡(jiǎn)單算法無(wú)法防御暴力攻擊。 好的密碼哈希函數必須可以微調、放慢步調,并且包含 加鹽。

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

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

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

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 為派生密鑰的長(cháng)度。 如果 dklenNone 則會(huì )使用哈希算法 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 提供了一個(gè)快速的 pbkdf2_hmac 實(shí)現。 Python 實(shí)現是使用 hmac 的內聯(lián)版本。 它的速度大約要慢上三倍并且不會(huì )釋放 GIL。

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

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

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

passwordsalt 必須為 字節類(lèi)對象。 應用和庫應當將 password 限制在合理長(cháng)度 (例如 1024)。 salt 應當為適當來(lái)源例如 os.urandom() 的大約 16 個(gè)或更多的字節串數據。

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

3.6 新版功能.

BLAKE2?

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

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

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

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

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

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

新哈希對象可通過(guò)調用構造器函數來(lái)創(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)?

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

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

  • digest_size: 以字節數表示的輸出摘要大小。

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

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

  • person: 個(gè)性化字符串(對于 BLAKE2b 最長(cháng) 16 字節,對于 BLAKE2s 最長(cháng) 8 字節)。

下表顯示了常規參數的限制(以字節為單位):

Hash

目標長(cháng)度

長(cháng)度(鍵)

長(cháng)度(鹽)

長(cháng)度(個(gè)人)

BLAKE2b

64

64

16

16

BLAKE2s

32

32

8

8

備注

BLAKE2 規格描述為鹽值和個(gè)性化形參定義了固定的長(cháng)度,但是為了方便起見(jiàn),此實(shí)現接受指定在長(cháng)度以?xún)鹊娜我獯笮〉淖止澊?如果形參長(cháng)度小于指定值,它將以零值進(jìn)行填充,因此舉例來(lái)說(shuō),b'salt'b'salt\x00' 為相同的值 (key 的情況則并非如此。)

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

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

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

  • depth: 樹(shù)的最大深度 (1 至 255,如無(wú)限制則為 255,連續模式下為 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: 節點(diǎn)深度 (0 至 255,對于葉子或在連續模式下則為 0)。

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

  • last_node: 一個(gè)布爾值,指明所處理的節點(diǎn)是否為最后一個(gè) (連續模式下則為 False)。

樹(shù)模式形參的說(shuō)明。

請參閱 BLAKE2 規格描述 第 2.10 節獲取有關(guān)樹(shù)形哈希的完整說(shuō)明。

常量?

blake2b.SALT_SIZE?
blake2s.SALT_SIZE?

鹽值長(cháng)度(構造器所接受的最大長(cháng)度)。

blake2b.PERSON_SIZE?
blake2s.PERSON_SIZE?

個(gè)性化字符串長(cháng)度(構造器所接受的最大長(cháng)度)。

blake2b.MAX_KEY_SIZE?
blake2s.MAX_KEY_SIZE?

最大密鑰長(cháng)度。

blake2b.MAX_DIGEST_SIZE?
blake2s.MAX_DIGEST_SIZE?

哈希函數可輸出的最大摘要長(cháng)度。

例子?

簡(jiǎn)單哈希?

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

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

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

>>>
>>> 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 來(lái)替代 SHA-1 而不改變輸出大小,我們可以讓 BLAKE2b 產(chǎn)生 20 個(gè)字節的摘要:

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

不同摘要大小的哈希對象具有完全不同的輸出(較短哈希值 并非 較長(cháng)哈希值的前綴);即使輸出長(cháng)度相同,BLAKE2b 和 BLAKE2s 也會(huì )產(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.

這個(gè)例子演示了如何使用密鑰 b'pseudorandom key' 來(lái)為 b'message data' 獲取一個(gè)(十六進(jìn)制編碼的)128 位驗證代碼:

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

作為實(shí)際的例子,一個(gè) Web 應用可為發(fā)送給用戶(hù)的 cookies 進(jìn)行對稱(chēng)簽名,并在之后對其進(jìn)行驗證以確保它們沒(méi)有被篡改:

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

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

隨機哈希?

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

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

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

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

警告

使用 BLAKE2 或任何其他通用加密哈希函數例如 SHA-256 進(jìn)行 加鹽哈希 (或純哈希) 并不適用于哈希密碼。 請參閱 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

個(gè)性化?

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

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

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

BLAKE2 可通過(guò)向 person 參數傳入字節串來(lái)進(jìn)行個(gè)性化:

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

個(gè)性化配合密鑰模式也可被用來(lái)從單個(gè)密鑰派生出多個(gè)不同密鑰。

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

樹(shù)形模式?

以下是對包含兩個(gè)葉子節點(diǎn)的最小樹(shù)進(jìn)行哈希的例子:

  10
 /  \
00  01

這個(gè)例子使用 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'

開(kāi)發(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 進(jìn)行設計的。

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

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

C 代碼由 Christian Heimes 針對 Python 進(jìn)行了部分的重寫(xiě)。

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

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

你應該已收到此軟件附帶的 CC0 公共領(lǐng)域專(zhuān)屬證書(shū)的副本。 如果沒(méi)有,請參閱 https://creativecommons.org/publicdomain/zero/1.0/。

根據創(chuàng )意分享公共領(lǐng)域貢獻 1.0 通用規范,下列人士為此項目的開(kāi)發(fā)提供了幫助或對公共領(lǐng)域的修改作出了貢獻:

  • Alexandr Sokolovskiy

參見(jiàn)

模塊 hmac

使用哈希運算來(lái)生成消息驗證代碼的模塊。

模塊 base64

針對非二進(jìn)制環(huán)境對二進(jìn)制哈希值進(jì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

有關(guān)安全哈希算法的 FIPS 180-2 出版物。

https://en.wikipedia.org/wiki/Cryptographic_hash_function#Cryptographic_hash_algorithms

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

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

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

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

NIST Recommendation for Password-Based Key Derivation.