hashlib --- 安全哈希與消息摘要?
源碼: Lib/hashlib.py
這個(gè)模塊針對(duì)不同的安全哈希和消息摘要算法實(shí)現(xiàn)了一個(gè)通用的接口。包括 FIPS 的 SHA1, SHA224, SHA256, SHA384, and SHA512 (定義于 FIPS 180-2) 算法,以及 RSA 的 MD5 算法( 定義于 Internet RFC 1321)。術(shù)語(yǔ)“安全哈希”和“消息摘要”是可互換的,較舊的算法被稱為消息摘要,現(xiàn)代術(shù)語(yǔ)是安全哈希。
注解
如果你想找到 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() 通常也是可用的,但如果你在使用少見(jiàn)的 "FIPS 兼容" 的 Python 編譯版本則可能會(huì)找不到它。 此外還可能有一些附加的算法,具體取決于你的平臺(tái)上的 Python 所使用的 OpenSSL 庫(kù)。 在大部分平臺(tái)上可用的還有 sha3_224(), sha3_256(), sha3_384(), sha3_512(), shake_128(), shake_256() 等等。
3.6 新版功能: SHA3 (Keccak) 和 SHAKE 構(gòu)造器 sha3_224(), sha3_256(), sha3_384(), sha3_512(), shake_128(), shake_256().
例如,如果想獲取字節(jié)串 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
更簡(jiǎn)要的寫(xiě)法:
>>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest()
'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'
-
hashlib.new(name[, data])? 一個(gè)接受所希望的算法對(duì)應(yīng)的字符串 name 作為第一個(gè)形參的通用構(gòu)造器。 它還允許訪問(wèn)上面列出的哈希算法以及你的 OpenSSL 庫(kù)可能提供的任何其他算法。 同名的構(gòu)造器要比
new()更快所以應(yīng)當(dāng)優(yōu)先使用。
使用 new() 并附帶由 OpenSSL 所提供了算法:
>>> h = hashlib.new('ripemd160')
>>> h.update(b"Nobody inspects the spammish repetition")
>>> h.hexdigest()
'cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc'
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ī)范名稱,總是為小寫(xiě)形式并且總是可以作為
new()的形參用來(lái)創(chuàng)建另一個(gè)此類型的哈希對(duì)象。在 3.4 版更改: 該屬性名稱自被引入起即存在于 CPython 中,但在 Python 3.4 之前并未正式指明,因此可能不存在于某些平臺(tái)上。
哈希對(duì)象具有下列方法:
-
hash.update(data)? 用 bytes-like object 來(lái)更新哈希對(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ì)象的副本(“克隆”)。 這可被用來(lái)高效地計(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 的完整取值范圍。
密鑰派生?
密鑰派生和密鑰延展算法被設(shè)計(jì)用于安全密碼哈希。 sha1(password) 這樣的簡(jiǎn)單算法無(wú)法防御暴力攻擊。 好的密碼哈希函數(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'。 password 和 salt 會(huì)以字節(jié)串緩沖區(qū)的形式被解析。 應(yīng)用和庫(kù)應(yīng)當(dāng)將 password 限制在合理長(zhǎng)度 (例如 1024)。 salt 應(yīng)當(dāng)為適當(dāng)來(lái)源例如
os.urandom()的大約 16 個(gè)或更多的字節(jié)串?dāng)?shù)據(jù)。iterations 數(shù)值應(yīng)當(dāng)基于哈希算法和算力來(lái)選擇。 在 2013 年時(shí),建議至少為 100,000 次 SHA-256 迭代。
dklen 為派生密鑰的長(zhǎng)度。 如果 dklen 為
None則會(huì)使用哈希算法 hash_name 的摘要大小,例如 SHA-512 為 64。>>> import hashlib, binascii >>> dk = hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 100000) >>> binascii.hexlify(dk) b'0394a2ede332c9a13eb82e9b24631604c31df978b4e2f0fbd2c549944f9d79a5'
3.4 新版功能.
注解
隨同 OpenSSL 提供了一個(gè)快速的 pbkdf2_hmac 實(shí)現(xiàn)。 Python 實(shí)現(xiàn)是使用
hmac的內(nèi)聯(lián)版本。 它的速度大約要慢上三倍并且不會(huì)釋放 GIL。
-
hashlib.scrypt(password, *, salt, n, r, p, maxmem=0, dklen=64)? 此函數(shù)提供基于密碼加密的密鑰派生函數(shù),其定義參見(jiàn) RFC 7914。
password 和 salt 必須為 字節(jié)類對(duì)象。 應(yīng)用和庫(kù)應(yīng)當(dāng)將 password 限制在合理長(zhǎng)度 (例如 1024)。 salt 應(yīng)當(dāng)為適當(dāng)來(lái)源例如
os.urandom()的大約 16 個(gè)或更多的字節(jié)串?dāng)?shù)據(jù)。n 為 CPU/內(nèi)存開(kāi)銷因子,r 為塊大小,p 為并行化因子,maxmem 為內(nèi)存限制 (OpenSSL 1.1.0 默認(rèn)為 32 MiB)。 dklen 為派生密鑰的長(zhǎng)度。
可用性: OpenSSL 1.1+。
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, personalization 和 tree hashing.
此模塊的哈希對(duì)象遵循標(biāo)準(zhǔn)庫(kù) hashlib 對(duì)象的 API。
創(chuàng)建哈希對(duì)象?
新哈希對(duì)象可通過(guò)調(diào)用構(gòu)造器函數(shù)來(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)?
-
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)?
這些函數(shù)返回用于計(jì)算 BLAKE2b 或 BLAKE2s 的相應(yīng)的哈希對(duì)象。 它們接受下列可選通用形參:
data: 要哈希的初始數(shù)據(jù)塊,它必須為 bytes-like object。 它只能作為位置參數(shù)傳入。
digest_size: 以字節(jié)數(shù)表示的輸出摘要大小。
key: 用于密鑰哈希的密鑰(對(duì)于 BLAKE2b 最多 64 字節(jié),對(duì)于 BLAKE2s 最多 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)度,但是為了方便起見(jiàn),此實(shí)現(xiàn)接受指定在長(zhǎng)度以內(nèi)的任意大小的字節(jié)串。 如果形參長(zhǎng)度小于指定值,它將以零值進(jìn)行填充,因此舉例來(lái)說(shuō),b'salt' 和 b'salt\x00' 為相同的值 (key 的情況則并非如此。)
如下面的模塊 constants 所描述,這些是可用的大小取值。
構(gòu)造器函數(shù)還接受下列樹(shù)形哈希形參:
fanout: 扇出值 (0 至 255,如無(wú)限制即為 0,連續(xù)模式下為 1)。
depth: 樹(shù)的最大深度 (1 至 255,如無(wú)限制則為 255,連續(xù)模式下為 1)。
leaf_size: 葉子的最大字節(jié)長(zhǎng)度 (0 至 2**32-1,如無(wú)限制或在連續(xù)模式下則為 0)。
node_offset: 節(jié)點(diǎn)偏移量 (對(duì)于 BLAKE2b 為 0 至 2**64-1,對(duì)于 BLAKE2s 為 0 至 2**48-1,對(duì)于最左邊第一個(gè)葉子或在連續(xù)模式下則為 0)。
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)樹(shù)形哈希的完整介紹。
常量?
-
blake2b.SALT_SIZE?
-
blake2s.SALT_SIZE?
鹽值長(zhǎng)度(構(gòu)造器所接受的最大長(zhǎng)度)。
-
blake2b.PERSON_SIZE?
-
blake2s.PERSON_SIZE?
鹽值長(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)該首先通過(guò)調(diào)用適當(dāng)?shù)臉?gòu)造器函數(shù) (blake2b() 或 blake2s()) 來(lái)構(gòu)造一個(gè)哈希對(duì)象,然后通過(guò)在該對(duì)象上調(diào)用 update() 來(lái)更新目標(biāo)數(shù)據(jù),最后通過(guò)調(diào)用 digest() (或針對(duì)十六進(jìn)制編碼字符串的 hexdigest()) 來(lái)獲取該對(duì)象的摘要。
>>> from hashlib import blake2b
>>> h = blake2b()
>>> h.update(b'Hello world')
>>> h.hexdigest()
'6ff843ba685842aa82031d3f53c48b66326df7639a63d128974c5c14f31a0f33343a8c65551134ed1ae0f2b0dd2bb495dc81039e3eeb0aa1bb0388bbeac29183'
作為快捷方式,你可以直接以位置參數(shù)的形式向構(gòu)造器傳入第一個(gè)數(shù)據(jù)塊來(lái)直接更新:
>>> 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 來(lái)替代 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'
密鑰哈希?
密鑰哈??杀挥糜谏矸蒡?yàn)證,作為 基于哈希的消息驗(yàn)證代碼 (HMAC) 的一種更快速更簡(jiǎn)單的替代。 BLAKE2 可在前綴 MAC 模式下安全地使用,這是由于它從 BLAKE 所繼承的不可區(qū)分特性。
這個(gè)例子演示了如何使用密鑰 b'pseudorandom key' 來(lái)為 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)證以確保它們沒(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 構(gòu)造過(guò)程中使用:
>>> import hmac, hashlib
>>> m = hmac.new(b'secret key', digestmod=hashlib.blake2s)
>>> m.update(b'message')
>>> m.hexdigest()
'e3c8102868d28b5ff85fc35dda07329970d1a01e273c37481326fe0c861c8142'
隨機(jī)哈希?
用戶可通過(guò)設(shè)置 salt 形參來(lái)為哈希函數(shù)引入隨機(jī)化。 隨機(jī)哈希適用于防止對(duì)數(shù)字簽名中使用的哈希函數(shù)進(jìn)行碰撞攻擊。
隨機(jī)哈希被設(shè)計(jì)用來(lái)處理當(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ù)字簽名生成過(guò)程中使得兩條或更多條消息最終產(chǎn)生相同哈希值的可能性 --- 即使為特定哈希函數(shù)找到碰撞現(xiàn)象是可行的。 但是,當(dāng)消息的所有部分均由簽名者準(zhǔn)備時(shí),使用隨機(jī)哈??赡芙档蛿?shù)字簽名所提供的安全性。
在 BLAKE2 中,鹽值會(huì)在初始化期間作為對(duì)哈希函數(shù)的一次性輸入而不是對(duì)每個(gè)壓縮函數(shù)的輸入來(lái)處理。
警告
使用 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ì)算出來(lái)的哈希值在另一個(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 可通過(guò)向 person 參數(shù)傳入字節(jié)串來(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ù)形模式?
以下是對(duì)包含兩個(gè)葉子節(jié)點(diǎn)的最小樹(shù)進(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'
開(kāi)發(fā)人員?
BLAKE2 是由 Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn 和 Christian Winnerlein 基于 Jean-Philippe Aumasson, Luca Henzen, Willi Meier 和 Raphael C.-W. Phan 所創(chuàng)造的 SHA-3 入圍方案 BLAKE 進(jìn)行設(shè)計(jì)的。
它使用的核心算法來(lái)自由 Daniel J. Bernstein 所設(shè)計(jì)的 ChaCha 加密。
stdlib 實(shí)現(xiàn)是基于 pyblake2 模塊的。 它由 Dmitry Chestnykh 在 Samuel Neves 所編寫(xiě)的 C 實(shí)現(xiàn)的基礎(chǔ)上編寫(xiě)。 此文檔拷貝自 pyblake2 并由 Dmitry Chestnykh 撰寫(xiě)。
C 代碼由 Christian Heimes 針對(duì) Python 進(jìn)行了部分的重寫(xiě)。
以下公共領(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書(shū)的副本。 如果沒(méi)有,請(qǐng)參閱 https://creativecommons.org/publicdomain/zero/1.0/。
根據(jù)創(chuàng)意分享公共領(lǐng)域貢獻(xiàn) 1.0 通用規(guī)范,下列人士為此項(xiàng)目的開(kāi)發(fā)提供了幫助或?qū)差I(lǐng)域的修改作出了貢獻(xiàn):
Alexandr Sokolovskiy
參見(jiàn)
- 模塊
hmac 使用哈希運(yùn)算來(lái)生成消息驗(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)于哪些算法存在已知問(wèn)題以及對(duì)其使用所造成的影響的信息的 Wikipedia 文章。
- https://www.ietf.org/rfc/rfc2898.txt
PKCS #5: 基于密碼的加密規(guī)范描述 2.0 版
