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

源碼: Lib/hashlib.py


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

備注

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

警告

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

哈希算法?

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

備注

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

備注

update() 輸入字符串對(duì)象是不被支持的,因?yàn)楣;谧止?jié)而非字符。

此模塊中總是可用的哈希算法構(gòu)造器有 sha1(), sha224(), sha256(), sha384(), sha512(), blake2b()blake2s()md5() 通常也是可用的,但如果你在使用少見的 "FIPS 兼容" 的 Python 編譯版本則可能會(huì)找不到它。 此外還可能有一些附加的算法,具體取決于你的平臺(tái)上的 Python 所使用的 OpenSSL 庫。 在大部分平臺(tái)上可用的還有 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)造器都接受僅限關(guān)鍵字參數(shù) usedforsecurity 且其默認(rèn)值為 True。 設(shè)為假值即允許在受限的環(huán)境中使用不安全且阻塞的哈希算法。 False 表示此哈希算法不可用于安全場(chǎng)景,例如用作非加密的單向壓縮函數(shù)。

現(xiàn)在 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)要的寫法:

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

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

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

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

Hashlib 提供下列常量屬性:

hashlib.algorithms_guaranteed?

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

3.2 新版功能.

hashlib.algorithms_available?

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

3.2 新版功能.

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

hash.digest_size?

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

hash.block_size?

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

hash 對(duì)象具有以下屬性:

hash.name?

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

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

哈希對(duì)象具有下列方法:

hash.update(data)?

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

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

hash.digest()?

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

hash.hexdigest()?

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

hash.copy()?

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

SHAKE 可變長(zhǎng)度摘要?

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

shake.digest(length)?

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

shake.hexdigest(length)?

類似于 digest() 但摘要會(huì)以兩倍長(zhǎng)度字符串對(duì)象的形式返回,其中僅包含十六進(jìn)制數(shù)碼。 這可以被用于在電子郵件或其他非二進(jìn)制環(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 新版功能.

密鑰派生?

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

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

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

字符串 hash_name 是要求用于 HMAC 的哈希摘要算法的名稱,例如 'sha1' 或 'sha256'。 passwordsalt 會(huì)以字節(jié)串緩沖區(qū)的形式被解析。 應(yīng)用和庫應(yīng)當(dāng)將 password 限制在合理長(zhǎng)度 (例如 1024)。 salt 應(yīng)當(dāng)為適當(dāng)來源例如 os.urandom() 的大約 16 個(gè)或更多的字節(jié)串?dāng)?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 為派生密鑰的長(zhǎ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í)現(xiàn)。 Python 實(shí)現(xiàn)是使用 hmac 的內(nèi)聯(lián)版本。 它的速度大約要慢上三倍并且不會(huì)釋放 GIL。

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

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

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

passwordsalt 必須為 字節(jié)類對(duì)象。 應(yīng)用和庫應(yīng)當(dāng)將 password 限制在合理長(zhǎng)度 (例如 1024)。 salt 應(yīng)當(dāng)為適當(dāng)來源例如 os.urandom() 的大約 16 個(gè)或更多的字節(jié)串?dāng)?shù)據(jù)。

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

3.6 新版功能.

BLAKE2?

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

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

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

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

此模塊的哈希對(duì)象遵循標(biāo)準(zhǔn)庫 hashlib 對(duì)象的 API。

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

新哈希對(duì)象可通過調(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ù)返回用于計(jì)算 BLAKE2b 或 BLAKE2s 的相應(yīng)的哈希對(duì)象。 它們接受下列可選通用形參:

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

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

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

  • salt: 用于隨機(jī)哈希的鹽值(對(duì)于 BLAKE2b 最長(zhǎng) 16 字節(jié),對(duì)于 BLAKE2s 最長(zhǎng) 8 字節(jié))。

  • person: 個(gè)性化字符串(對(duì)于 BLAKE2b 最長(zhǎng) 16 字節(jié),對(duì)于 BLAKE2s 最長(zhǎng) 8 字節(jié))。

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

Hash

目標(biāo)長(zhǎng)度

長(zhǎng)度(鍵)

長(zhǎng)度(鹽)

長(zhǎng)度(個(gè)人)

BLAKE2b

64

64

16

16

BLAKE2s

32

32

8

8

備注

BLAKE2 規(guī)格描述為鹽值和個(gè)性化形參定義了固定的長(zhǎng)度,但是為了方便起見,此實(shí)現(xiàn)接受指定在長(zhǎng)度以內(nèi)的任意大小的字節(jié)串。 如果形參長(zhǎng)度小于指定值,它將以零值進(jìn)行填充,因此舉例來說,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é)點(diǎn)深度 (0 至 255,對(duì)于葉子或在連續(xù)模式下則為 0)。

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

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

樹模式形參的說明。

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

常量?

blake2b.SALT_SIZE?
blake2s.SALT_SIZE?

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

blake2b.PERSON_SIZE?
blake2s.PERSON_SIZE?

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

blake2b.MAX_KEY_SIZE?
blake2s.MAX_KEY_SIZE?

最大密鑰長(zhǎng)度。

blake2b.MAX_DIGEST_SIZE?
blake2s.MAX_DIGEST_SIZE?

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

例子?

簡(jiǎn)單哈希?

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

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

作為快捷方式,你可以直接以位置參數(shù)的形式向構(gòu)造器傳入第一個(gè)數(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 具有可配置的摘要大小,對(duì)于 BLAKE2b 最多 64 字節(jié),對(duì)于 BLAKE2s 最多 32 字節(jié)。 例如,要使用 BLAKE2b 來替代 SHA-1 而不改變輸出大小,我們可以讓 BLAKE2b 產(chǎn)生 20 個(gè)字節(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

不同摘要大小的哈希對(duì)象具有完全不同的輸出(較短哈希值 并非 較長(zhǎng)哈希值的前綴);即使輸出長(zhǎ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' 來為 b'message data' 獲取一個(gè)(十六進(jìn)制編碼的)128 位驗(yàn)證代碼:

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

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

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

隨機(jī)哈希?

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

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

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

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

警告

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

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

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

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

BLAKE2 可通過向 person 參數(shù)傳入字節(jié)串來進(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è)性化配合密鑰模式也可被用來從單個(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=

樹形模式?

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

  10
 /  \
00  01

這個(gè)例子使用 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 進(jìn)行設(shè)計(jì)的。

它使用的核心算法來自由 Daniel J. Bernstein 所設(shè)計(jì)的 ChaCha 加密。

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

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

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

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

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

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

  • Alexandr Sokolovskiy

參見

模塊 hmac

使用哈希運(yùn)算來生成消息驗(yàn)證代碼的模塊。

模塊 base64

針對(duì)非二進(jìn)制環(huán)境對(duì)二進(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)于哪些算法存在已知問題以及對(duì)其使用所造成的影響的信息的 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.