python-hkdf 调用方法汇总
网络通讯加密hkdf
HKDF 是基于 HMAC(Hashed Message Authentication Code)的密钥派生函数(key derivation function)。它可以从一些 initial keying material派生出密码学意义上强度高的密钥。
即HKDF = HMAC + KDF
HKDF 通常有以下几个重要输入:
- 作为输入的 keying material
- 可选的 salt, 但是使用 salt 可以明显增强 HKDF 的强度
- 可选的 info,用于指示一些信息
- Hash 函数的 mode,支持md5/sha1/sha224/sha256/sha384/sha512
- 输出密钥的字节长度最大值与内部使用的 Hash 函数有关,为 255 * Hash 函数输出字节长度。例如对于 sha256,输出密钥的字节长度最长为 255 * 32
算法拆解
一般来说,HKDF算法所做的工作分为2步,其一称之为提取;其二称之为扩展。接下来我们说明这两步
(1)、提取
所谓提取就是将用户输入的密钥尽量的伪随机化。一般是使用一个哈希函数来实现,具体那种更具需要在HMAC中确定。这一过程可以表示如下:
HKDF-Extract(salt, IKM)得到PRK,而PRK的计算公式如下:
- PRK = HMAC-Hash(salt, IKM) ,这其中有2个输入和1个输出
- Salt,输入,加盐操作的盐,如果不提供则全部初始化为0的字符串,长度则为所采用哈希函数的散列值长度
- IKM,输入,数额udemiyao材料
- PRK,输出,伪随机化后的密钥,长度则为所采用哈希函数的散列值长度
需要注意的是,在这一步中“IKM”被用作HMAC输入,而不是HMAC密钥。
(2)、扩展
所谓扩展,其实就是通过一系列的哈希运算将密钥扩展到我们需要的长度。这个长度我们记为L。这一过程标识如下:
HKDF-Expand(PRK, info, L) -> OKM,其中有3个输入量和1个输出量,其中:
- PRK,输入,一般是在提取阶段得到的输出,是一个伪随机的密钥,长度不小于所采用的哈希算法的输出摘要长度
- Info,输入,可选上下文和应用程序特定信息(可以是零长度字符串)
- L,输入,以字节计算的密钥原料的长度,一般不长于哈希函数输出摘要长度的255倍
OKM,输出,长度为L的密钥材料输出,其计算方式如下:
计算一系列的哈希值,我们记为T(n),其中n为0-255的整数,具体取值由所计算的长度L来确定。n的最大值为:L除以所用哈希函数输出摘要的长度,再向上取整,我们将其记为N。
- T(0) = 长度为0的空字符串
- T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
- T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
- T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
直到T(N)为止,需要注意的是,每个哈希操作都会串接一个字节的常量,从1到N,所以最大的N值只能到255。然后将计算得到的这些T(n)串接起来,我们记为T,即:
T = T(1) | T(2) | T(3) | … | T(N)
而我们想要获得的OKM正是取T的前L个字节组成。这要我们就得到了我们想要的密钥材料。
官方资料
安装python-hkdf
pip install hkdf
使用样例
import hkdf
import hashlib
import sys
from binascii import hexlify, unhexlify
# A.3. Test Case 3
# Test with SHA-256 and zero-length salt/info
# decode_hex() <=change=> unhexlify()
test_vectors = {}
test_vectors[1] = TestCase({
"name" : "A.3 Test Case 3",
"hash" : hashlib.sha256,
"IKM" : decode_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
"salt" : b"",
"info" : b"",
"L" : 42,
"PRK" : decode_hex("19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04"),
"OKM" : decode_hex("8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"),
})
tv = test_vectors[1]
prk = hkdf_extract(tv["salt"], tv["IKM"], tv["hash"])
okm = hkdf_expand(prk, tv["info"], tv["L"], tv["hash"])
print("Test Case 3")
for i in prk:
print("%02x" % i, end="")
print("")
for i in okm:
print("%02x" % i, end="")
print("")