文章目录
- Abstract
- 1 Introduction
- 2 Specification of AES-CMAC
- 2.1 Basic Definitions
- 2.2 Overview
- 2.3 Subkey Generation Algorithm
- 2.4 MAC Generation Algorithm
- 2.5 MAC Verification Algorithm
- 3 Security Considerations
- 4 Test Vectors
- 5 测试代码
- 5.1 C语言版本
- 5.2 Python语言版本
- 6 SM4-CMAC
- 6.1 SM4算法库
- 6.2 SM4算法测试向量
- 6.3 SM4-CMAC算法测试向量
- 参考资料
Abstract
This memo specifies an authentication algorithm based on CMAC with the 128-bit Advanced Encryption Standard (AES). This new authentication algorithm is named AES-CMAC.
1 Introduction
AES-CMAC可以检测有意图的,未鉴权的数据修改,也包括意外修改。
AES比hash函数更容易使用。
2 Specification of AES-CMAC
2.1 Basic Definitions
见原文。
2.2 Overview
如果Message的size是128bit的整数倍,最后一个block在AES_K运算之前要和K1进行XOR运算;否则,最后一个block会使用10^i填充到128bit,并且在AES_K运算之前和K2进行XOR运算。
AES_K:使用秘钥K的AES-128。
M:message,被切分成了M_1,M_2,……, M_n, M_i就表示第i个block。M_1到M_n-1的长度都是128bits。M_n 的长度是≤128bits。
K1和K2是子密钥生成算法生成的两个子密钥。
2.3 Subkey Generation Algorithm
子密钥生成算法的输入输出表示:(K1,K2) := Generate_Subkey(K),K就是AES-128的秘钥,K1和K2就是算法输出结果,两个子密钥。
2.4 MAC Generation Algorithm
MAC生成算法被表示为:T := AES-CMAC(K,M,len),K表示秘钥,M就是要保护的message,len是消息长度(单位为octets)。校验MAC可以确定消息的完整性(integrity)和鉴权(authenticity)。
n就是block个数, flag就表示是否被整除了,true表示正好是128的整数倍,false表示反之。
2.5 MAC Verification Algorithm
3 Security Considerations
由AES算法提供安全性保证。 AES或者其他加密算法的优势部分在于秘钥K和实现的正确性。密钥的生成方式应满足 RFC 4086的伪随机性要求,并应安全保存。 当且仅当正确使用 AES-CMAC 时,它才能提供满足当前消息身份验证最佳实践的身份验证和完整性。
4 Test Vectors
见原文:https://datatracker.ietf.org/doc/html/rfc4493
5 测试代码
5.1 C语言版本
见原文。
5.2 Python语言版本
from .abscipheralgo import AbsCipherAlgoclass CmacAlgo:byte_limit = 16bit_limit = 128const_rb = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87')const_zero = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')def xor_bit_limit(self, a:bytearray, b:bytearray) -> bytearray:assert len(a) == self.byte_limitassert len(b) == self.byte_limitout = bytearray(self.byte_limit)for i in range(self.byte_limit):out[i] = a[i] ^ b[i]return outdef left_shift_one_bit(self, input:bytearray) -> bytearray:assert len(input) == self.byte_limitoverflow = bytearray(1)output = bytearray(self.byte_limit)for i in reversed(range(self.byte_limit)):# make sure is a byteoutput[i] = (input[i] << 1) & 0xFFoutput[i] |= overflow[0]overflow[0] = 1 if (input[i] & 0x80) else 0return outputdef generate_subkey(self, key: bytearray, cipher_algo:AbsCipherAlgo):L = bytearray(self.byte_limit)Z = bytearray(self.byte_limit)tmp = bytearray(self.byte_limit)for i in range(self.byte_limit):Z[i] = 0L = cipher_algo.encrypt(key, Z)# If MSB(L) = 0, then K1 = L << 1if (L[0] & 0x80) == 0:K1 = self.left_shift_one_bit(L)else:tmp = self.left_shift_one_bit(L)K1 = self.xor_bit_limit(tmp, self.const_rb)if K1[0] & 0x80 == 0:K2 = self.left_shift_one_bit(K1)else:tmp = self.left_shift_one_bit(K1)K2 = self.xor_bit_limit(tmp, self.const_rb)return K1,K2"""将最后一个block以10^i的方式补齐"""def padding(self, last_block: bytearray):assert last_block is not Nonepad = bytearray(self.byte_limit)for j in range(self.byte_limit):if j < len(last_block):pad[j] = last_block[j]elif j == len(last_block):pad[j] = 0x80else:pad[j] = 0x00return paddef cmac(self, key: bytearray, input:bytearray, cipher_algo:AbsCipherAlgo) -> bytes:K1, K2 = self.generate_subkey(key, cipher_algo)# n is number of rounds# c语言直接除,因为int截断n = (len(input) + self.byte_limit - 1) // self.byte_limitif n == 0:n = 1# last block is not a complete blockflag = 0else:# last block is a complete blockif len(input) % self.byte_limit == 0:flag = 1else:flag = 0# 计算M_last# last block is completeif flag:M_last = self.xor_bit_limit(input[(n - 1) * self.byte_limit : ], K1)else:padded = self.padding(input[(n - 1) * self.byte_limit : ])M_last = self.xor_bit_limit(padded, K2)X = bytearray(self.byte_limit)for i in range(self.byte_limit):X[i] = 0for i in range(n-1):Y = self.xor_bit_limit(X, input[self.byte_limit * i : self.byte_limit * (i + 1)])X = cipher_algo.encrypt(key, Y)Y = self.xor_bit_limit(X, M_last)X = cipher_algo.encrypt(key, Y)mac = bytearray(self.byte_limit)for i in range(self.byte_limit):mac[i] = X[i]return mac
from .cmacalgo import CmacAlgoclass Cmac128Algo(CmacAlgo):const_rb = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87')const_zero = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')def __init__(self):self.byte_limit = 16self.bit_limit = 128self.const_rb = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87')self.const_zero = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
from .cmacalgo import CmacAlgoclass Cmac256Algo(CmacAlgo):const_rb = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87')const_zero = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')def __init__(self):self.byte_limit = 32self.bit_limit = 256const_rb = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87')const_zero = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
6 SM4-CMAC
6.1 SM4算法库
Cryptography:https://blog.51cto.com/u_16175518/6765321
CryptSM4:https://cloud.tencent.com/developer/article/1751336?areaId=106001
https://github.com/yang3yen/pysm4
算法padding模式:PKCS7,None
6.2 SM4算法测试向量
明文:
0x40, 0x10, 0xFF, 0xEF, 0x00, 0x45, 0x93, 0x00, 0xAB, 0xCD, 0xEE, 0x00, 0xF0, 0xF4, 0x00, 0x88,
0xA2, 0x19, 0x09, 0x67, 0x87, 0x0C, 0xFF, 0x54, 0xF3, 0x12, 0x50, 0x33, 0xC7, 0xF9, 0x1F, 0xDF,
0x13, 0x73, 0x4F, 0x67, 0xD7, 0xEB, 0xCC, 0x44, 0xF1, 0x12, 0x90, 0x18, 0xA7, 0xA9, 0x1F, 0x03,
0x13, 0x88, 0x4F, 0x67, 0xD7, 0xEB, 0xCC, 0x44, 0xF1, 0x12, 0x46, 0x18, 0x64, 0xA9, 0x1F, 0xEE,
密钥:
0x23, 0x33, 0x41, 0x67, 0x87, 0xEB, 0xFF, 0x54, 0xF1, 0x12, 0x90, 0x11, 0xC7, 0xF9, 0x1F, 0x23
ECB密文:
0x92, 0x31, 0xc8, 0x55, 0xcb, 0x47, 0x0b, 0x07, 0x93, 0x1d, 0xff, 0xb8, 0x14, 0x23, 0x4c, 0x63,
0x06, 0xc9, 0x57, 0x3f, 0x37, 0x12, 0x3b, 0x54, 0xef, 0x61, 0xb6, 0x82, 0x18, 0x83, 0x1f, 0xa2,
0x8a, 0xb6, 0xa9, 0xcc, 0x02, 0xa7, 0xd3, 0x26, 0xeb, 0xeb, 0xe4, 0x5a, 0x48, 0xab, 0xb2, 0xe1,
0x5b, 0x38, 0x67, 0xe9, 0xb4, 0x16, 0x47, 0x6a, 0x0a, 0xf3, 0x9b, 0xef, 0x12, 0xb0, 0x28, 0xb5,
CBC密文:
0x0f, 0xa7, 0x44, 0xda, 0xba, 0x7c, 0x9d, 0xe3, 0xc3, 0xde, 0xab, 0xe7, 0x42, 0x4f, 0x29, 0x68,
0xa2, 0xdd, 0x8e, 0x21, 0x60, 0xd5, 0xbd, 0x5f, 0xf1, 0x63, 0x7e, 0xa7, 0xb2, 0xdf, 0x3f, 0x89,
0x73, 0xc9, 0x72, 0xe6, 0x69, 0x2d, 0xee, 0x23, 0xe5, 0x10, 0xd7, 0x57, 0x7d, 0xc2, 0x1f, 0x0b,
0x6f, 0x12, 0x51, 0x6d, 0xc3, 0x28, 0x2b, 0x07, 0xee, 0xd2, 0x56, 0x05, 0x22, 0x1e, 0x3d, 0xad,
6.3 SM4-CMAC算法测试向量
明文:
0x40, 0x10, 0xFF, 0xEF, 0x00, 0x45, 0x93, 0x00, 0xAB, 0xCD, 0xEE, 0x00, 0xF0, 0xF4, 0x00, 0x88,
0xA2, 0x19, 0x09, 0x67, 0x87, 0x0C, 0xFF, 0x54, 0xF3, 0x12, 0x50, 0x33, 0xC7, 0xF9, 0x1F, 0xDF,
0x13, 0x73, 0x4F, 0x67, 0xD7, 0xEB, 0xCC, 0x44, 0xF1, 0x12, 0x90, 0x18, 0xA7, 0xA9, 0x1F, 0x03,
0x13, 0x88, 0x4F, 0x67, 0xD7, 0xEB, 0xCC, 0x44, 0xF1, 0x12, 0x46, 0x18, 0x64, 0xA9, 0x1F, 0xEE,
密钥:
0x23, 0x33, 0x41, 0x67, 0x87, 0xEB, 0xFF, 0x54, 0xF1, 0x12, 0x90, 0x11, 0xC7, 0xF9, 0x1F, 0x23
CMAC密文:
0xb0, 0xeb, 0x38, 0x61, 0xe6, 0xc5, 0xc1, 0x09, 0x89, 0x61, 0x30, 0x7d, 0x49, 0xb1, 0x7a, 0x7d
参考资料
[1] https://datatracker.ietf.org/doc/html/rfc4493
[2]