RFC4493——AES-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

Illustration of the two cases of AES-CMAC
如果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就是算法输出结果,两个子密钥。
Algorithm Generate_Subkey

2.4 MAC Generation Algorithm

MAC生成算法被表示为:T := AES-CMAC(K,M,len),K表示秘钥,M就是要保护的message,len是消息长度(单位为octets)。校验MAC可以确定消息的完整性(integrity)和鉴权(authenticity)。
Algorithm AES-CMAC
n就是block个数, flag就表示是否被整除了,true表示正好是128的整数倍,false表示反之。

2.5 MAC Verification Algorithm

Algorithm Verify_MAC

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 AbsCipherAlgo

class CmacAlgo:
    byte_limit = 16
    bit_limit = 128

    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 xor_bit_limit(self, a:bytearray, b:bytearray) -> bytearray:
        assert len(a) == self.byte_limit
        assert len(b) == self.byte_limit

        out = bytearray(self.byte_limit)
        for i in range(self.byte_limit):
            out[i] = a[i] ^ b[i]
        return out

    def left_shift_one_bit(self, input:bytearray) -> bytearray:
        assert len(input) == self.byte_limit

        overflow = bytearray(1)
        output = bytearray(self.byte_limit)

        for i in reversed(range(self.byte_limit)):
            # make sure is a byte
            output[i] = (input[i] << 1) & 0xFF
            output[i] |= overflow[0]
            overflow[0] = 1 if (input[i] & 0x80) else 0

        return output

    def 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] = 0

        L = cipher_algo.encrypt(key, Z)

        # If MSB(L) = 0, then K1 = L << 1
        if (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 None

        pad = 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] = 0x80
            else:
                pad[j] = 0x00
        return pad

    def 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_limit

        if n == 0:
            n = 1
            # last block is not a complete block
            flag = 0
        else:
            # last block is a complete block
            if len(input) % self.byte_limit == 0:
                flag = 1
            else:
                flag = 0

        # 计算M_last
        # last block is complete
        if 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] = 0
        for 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 CmacAlgo

class 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 = 16
        self.bit_limit = 128

        self.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 CmacAlgo

class 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 = 32
        self.bit_limit = 256

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

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] 国密算法库:https://github.com/duanhongyi/gmssl

  • 23
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值