文章参考:实现来源
HMAC实现原理
以摘要算法为MD5实现的HMAC为例(MD5将原文以64字节分组来进行分别计算,最终输出一个16字节的散列值),如上图所示,HMAC的计算公式为:
HMAC(K,M)=H(K⊕opad∣H(K⊕ipad∣M)),其中,
B为计算hash过程中对信息分组时,每个信息块的长度(MD5算法中B=64);
L为哈希算法计算出的信息摘要长度(MD5算法中L=16);
K为任意长度的密钥,一般为了安全强度考虑,K的长度不小于L;
Ipad为00110110(16进制为0x36)重复B次;
Opad为01011100(16进制为0x5c)重复B次;
M 代表一个消息输入,即待加密原文;
H为哈希函数(例如MD5)。
根据上面的算法表示公式,我们可以描述HMAC算法的运算步骤:
(1)检查密钥K的长度。如果K的长度大于B则先使用摘要算法计算出一个长度为L的新密钥。如果后K的长度小于B,则在其后面追加0来使其长度达到B。
(2)将上一步生成的B字长的密钥字符串与ipad做异或运算,得到比特序列ipadkey。
(3)将ipadkey附加在消息M的开头;
(4)使用哈希函数H计算第3步中生成的数据流的信息摘要值。
(5) 将第1步生成的B字长密钥字符串与opad做异或运算,得到opadkey。
(6)再将第4步得到的结果填充到opadkey之后。
(7)使用哈希函数H计算第6步中生成的数据流的信息摘要值,输出结果就是最终的HMAC值。
实现代码
SM3算法使用来源第三方库gmssl
pip install gmssl
import base64
from gmssl.sm3 import sm3_hash
BLOCK_LENGTH = 64
def xor_bytes(a, b):
return bytes(x ^ y for x, y in zip(a, b))
def hmac_sm3(secret_key:str, raw_str:str):
# HMAC algorithm
structured_key = bytearray(BLOCK_LENGTH)
sm3_key = sm3_hash(base64.b64decode(secret_key)) if len(base64.b64decode(secret_key)) > BLOCK_LENGTH else base64.b64decode(secret_key)
structured_key[:len(sm3_key)] = sm3_key
# 2. XOR the processed key with ipad (0x36) to obtain ipadkey
ipadkey = xor_bytes(structured_key, bytes([0x36] * BLOCK_LENGTH))
# 3. Concatenate ipadkey with text
t3 = bytearray(ipadkey + raw_str.encode())
# 4. Hash the concatenated result using SM3
t4 = bytes.fromhex(sm3_hash(t3))
# 5. XOR the processed key with opad (0x5c) to obtain opadkey
opadkey = xor_bytes(structured_key, bytes([0x5c] * BLOCK_LENGTH))
# 6. Concatenate t4 with opadkey
t6 = bytearray(opadkey + t4)
return sm3_hash(t6)