【密码算法】HMAC-SM3消息鉴别码

admin 2026-03-09 02:23:54 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文解读国标GB/T15852.2—2024下的HMAC-SM3算法,阐述其密钥扩展、杂凑计算与截断流程。文章分析了算法的安全强度与实现效率,列举网络通信与金融等应用场景,并提供Python脚本演示计算细节,为技术人员掌握该国产密码算法提供了从理论到实现的完整参考。 综合评分: 90 文章分类: 技术标准,数据安全,应用安全,安全开发


cover_image

【密码算法】HMAC-SM3 消息鉴别码

原创

利刃信安 利刃信安

利刃信安

2026年3月7日 00:04 北京

HMAC-SM3 消息鉴别码

1. 概述

1.1 标准信息

  • • 标准名称:GB/T 15852.2—2024《网络安全技术 消息鉴别码 第2部分:采用专门设计的杂凑函数的机制》
  • • 发布日期:2024-09-29
  • • 实施日期:2025-04-01
  • • 代替标准:GB/T 15852.2—2012

1.2 算法基本概念

消息鉴别码能够保护数据的完整性,也能够验证数据的来源。采用专门设计的杂凑函数的消息鉴别码是指:在设计过程中,以专门设计的杂凑函数(如SM3等)或其轮函数为主要部件,通过一定的迭代机制形成的消息鉴别码。

HMAC-SM3是一种基于专门设计的杂凑函数SM3的消息鉴别码(MAC)算法,属于MAC算法2(HMAC)的范畴。它通过将SM3杂凑函数与密钥结合,生成用于验证消息完整性和真实性的固定长度鉴别码。

1.3 基本参数

  • • 输入

  • • 密钥K(长度不小于L2位,L2为杂凑值长度,SM3中L2=256)

  • • 消息D(长度不大于2^64-512位)

  • • 输出:固定长度的MAC值(长度m不小于32位,不大于杂凑值长度LH)

  • • 杂凑函数:SM3(符合GB/T 32905—2016标准)

  • • 安全性强度:取决于密钥长度,最高可达256位

2. 术语和定义

| 术语 | 定义 | | — | — | | 消息鉴别码(MAC) | MAC算法输出的位串,用于验证消息完整性和真实性 | | 杂凑函数 | 将任意长的位串映射为定长位串的函数,具有抗原像和抗碰撞特性 | | SM3密码杂凑算法 | 中国自主设计的专门密码学杂凑函数,输出长度为256比特 | | 轮函数 | 构成杂凑函数的主要部件,将两个特定长度的位串映射为一个定长位串 | | HMAC | 基于杂凑函数的消息鉴别码算法,通过两次杂凑函数调用实现 |

3. HMAC-SM3算法描述

3.1 通则

HMAC-SM3算法通过以下四个步骤计算MAC值:密钥扩展、杂凑操作、输出变换和截断操作。该算法需要调用两次完整的SM3杂凑函数。

3.2 算法步骤

3.2.1 步骤1:密钥扩展

  1. 1. 密钥预处理
  • • 若密钥K的长度大于L1位(L1为轮函数输入的第一个位串长度,SM3中L1=512),则对K进行杂凑运算,得到长度为L2位的杂凑值作为新的密钥
  • • 若密钥K的长度小于L1位,则在K的右侧填充L1-k个0,得到长度为L1的位串K_padded
  • • 若密钥K的长度等于L1位,则直接使用K作为K_padded
  1. 2. 生成子密钥
  • • IPAD:将十六进制值”36″重复L1/8次连接而成的位串(SM3中L1=512,故IPAD为64字节的”36″字符串)
  • • OPAD:将十六进制值”5C”重复L1/8次连接而成的位串(SM3中L1=512,故OPAD为64字节的”5C”字符串)
  • • K1 = K_padded ⊕ IPAD(内部填充密钥)
  • • K2 = K_padded ⊕ OPAD(外部填充密钥)

3.2.2 步骤2:杂凑操作

将内部填充密钥K1与消息D连接,作为SM3杂凑函数的输入,得到第一次杂凑结果H’:

H' = SM3(K1 || D)

3.2.3 步骤3:输出变换

将外部填充密钥K2与步骤2的结果H’连接,作为SM3杂凑函数的输入,得到第二次杂凑结果H”:

H'' = SM3(K2 || H')

3.2.4 步骤4:截断操作

根据安全需求,取位串H”最左侧m位作为最终MAC值(m不小于32位,不大于杂凑值长度LH):

MAC = MSBm(H'')

通常情况下,m取LH/2 = 128位,以平衡安全性和效率。

3.3 算法流程示意图

          +-------------------+     +-------------------+
          |  K_padded ⊕ IPAD = K1    |     |  K_padded ⊕ OPAD = K2    |
          +---------+---------+     +---------+---------+
                    |                           |
                    |                           |
          +---------v---------+     +---------v---------+
          |  K1 || D          |     |  K2 || H'         |
          +---------+---------+     +---------+---------+
                    |                           |
                    v                           v
          +-------------------+     +-------------------+
          |  SM3杂凑函数       |     |  SM3杂凑函数       |
          +---------+---------+     +---------+---------+
                    |                           |
                    |              +------------+
                    v              v
              +----------------------------+
              |  H' = SM3(K1 || D)         |
              +----------------------------+
                    |
                    v
              +----------------------------+
              |  H'' = SM3(K2 || H')        |
              +----------------------------+
                    |
                    v
              +----------------------------+
              |  MAC = MSBm(H'')            |
              +----------------------------+

4. 安全性与效率分析

4.1 安全特性

HMAC-SM3算法具有以下安全特性:

  • • 抗伪造性:在不知道密钥的情况下,即使获得多个(消息,MAC)对,也难以对新消息预测其MAC值
  • • 抗密钥恢复攻击:难以通过已知的(消息,MAC)对推导出密钥
  • • 抗碰撞攻击:继承了SM3算法的抗碰撞特性
  • • 量子安全性:在SM3是量子伪随机函数的假设下,HMAC-SM3被证明是量子安全的

4.2 安全证明

若满足以下假设,HMAC-SM3算法被证明是安全的:

  1. 1. 使用密钥为初始值IV的轮函数是一个强MAC算法
  2. 2. 迭代杂凑函数SM3是抗第二原像的

4.3 安全性强度

  • • 密钥长度:建议使用256位密钥,提供最高128位的安全性强度
  • • MAC长度:建议使用不小于128位的MAC长度,以抵抗生日攻击
  • • 消息长度:最大支持2^64-512位的消息长度

4.4 计算复杂度

  • • 轮函数调用次数:若填充后的消息包含q个分组,则HMAC-SM3需要调用q+3次轮函数
  • • 预计算优化:通过预计算IV1=φ(K1, IV)和IV2=φ(K2, IV),可将轮函数调用次数降低到q+1次
  • • 密钥预计算:密钥扩展步骤的结果可预计算并缓存,提高后续计算效率

4.5 实现效率

  • • 软件实现:适合各种计算环境,算法结构简单,易于优化
  • • 硬件实现:可通过并行化设计提高计算速度
  • • 内存需求:较低,主要依赖SM3杂凑函数的内存需求

5. 应用场景

HMAC-SM3算法可广泛应用于需要消息完整性验证和真实性鉴别的场景:

  1. 1. 网络通信安全
  • • 用于IPSec协议中的消息完整性验证
  • • 用于TLS/SSL协议中的MAC计算
  • • 用于安全电子邮件中的消息认证
  1. 2. 数据存储安全
  • • 用于数据库中数据完整性验证
  • • 用于文件系统的完整性保护
  • • 用于云存储服务中的数据认证
  1. 3. 金融交易安全
  • • 用于电子支付系统中的交易完整性验证
  • • 用于银行卡交易的MAC计算
  • • 用于证券交易系统中的消息认证
  1. 4. 物联网安全
  • • 用于物联网设备间通信的完整性验证
  • • 用于传感器数据的真实性认证
  • • 用于智能家居系统中的消息鉴别
  1. 5. 数字签名辅助
  • • 用于基于SM2椭圆曲线密码算法的数字签名中的杂凑计算
  • • 用于生成和验证数字签名的消息摘要
  1. 6. 实际应用案例
  • • 电子门禁系统:用于保护进出记录数据的存储完整性,防止数据篡改和伪造
  • • 服务器密码机:作为商用密码产品,用于提供HMAC-SM3完整性保护服务
  • • 等保三级系统:符合国家网络安全等级保护要求的信息系统中的数据完整性保护

6. 实现与测试

6.1 HMAC_SM3计算过程详解脚本

6.1.1 脚本功能与特点

工作区中提供了一个详细的HMAC-SM3计算过程脚本 HMAC_SM3计算过程详解.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from gmssl import sm3, func

defbytes_to_hex(data: bytes) -> str:
    return data.hex().upper()

defprint_separator(char='=', length=80):
    print(char * length)

defprint_title(title: str):
    print_separator()
    print(title.center(80))
    print_separator()

defprint_section(title: str):
    print(f"\n{'=' * 80}")
    print(f"  {title}")
    print(f"{'=' * 80}")

defprint_subsection(title: str):
    print(f"\n【{title}】")
    print_separator('-', 80)

defprint_item(label: str, value: str, indent: int = 2):
    spaces = ' ' * indent
    print(f"{spaces}{label}: {value}")

defprint_hex_block(label: str, hex_data: str, bytes_per_line: int = 32):
    print(f"\n  {label}:")
    for i inrange(0, len(hex_data), bytes_per_line * 2):
        line = hex_data[i:i + bytes_per_line * 2]
        print(f"    {line}")

defhmac_sm3_detailed():
    print_title("HMAC-SM3 算法详细计算过程")
    print("符合 GB/T 15852.2-2024 标准 第7章 MAC算法2(HMAC)")
    print_separator()

    print("\n请输入密钥 (十六进制格式):")
    print("示例: 00112233445566778899AABBCCDDEEFF")
    key_input = input("\n密钥: ").strip().replace(' ', '').upper()

    try:
        key_bytes = bytes.fromhex(key_input)
    except ValueError:
        print("错误: 密钥格式不正确,请输入有效的十六进制字符串!")
        return

    print("\n请选择消息输入类型:")
    print("  1. 字符串输入")
    print("  2. 十六进制输入")

    choice = input("\n请选择 (1/2): ").strip()

    if choice == "1":
        message_input = input("请输入消息 (字符串): ").strip()
        message_bytes = message_input.encode('ascii')
        message_type = "string"
    elif choice == "2":
        message_input = input("请输入消息 (十六进制): ").strip().replace(' ', '').upper()
        try:
            message_bytes = bytes.fromhex(message_input)
        except ValueError:
            print("错误: 消息格式不正确,请输入有效的十六进制字符串!")
            return
        message_type = "hex"
    else:
        print("错误: 无效选择!")
        return

    L1 = 64
    L2 = 32

    print_section("输入参数")

    print_subsection("密钥信息")
    print_item("密钥长度", f"{len(key_bytes)} 字节 ({len(key_bytes) * 8} 位)")
    print_item("密钥 (十六进制)", bytes_to_hex(key_bytes))

    print_subsection("消息信息")
    print_item("消息长度", f"{len(message_bytes)} 字节 ({len(message_bytes) * 8} 位)")
    print_item("消息输入类型", "字符串"if message_type == "string"else"十六进制")
    if message_type == "string":
        print_item("消息 (字符串)", message_input)
    print_item("消息 (十六进制)", bytes_to_hex(message_bytes))

    print_subsection("算法参数")
    print_item("L1 (轮函数数据输入长度)", f"{L1} 字节 ({L1 * 8} 位)")
    print_item("L2 (杂凑值长度)", f"{L2} 字节 ({L2 * 8} 位)")
    print_item("IPAD值", "0x36 (二进制: 00110110)")
    print_item("OPAD值", "0x5C (二进制: 01011100)")

    print_section("步骤1: 密钥扩展")

    print_subsection("1.1 密钥填充处理")
    print("算法要求:")
    print("  - 若密钥长度 k > L1,则对密钥进行杂凑运算: K' = SM3(K)")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- 若密钥长度 k < L1,则在右侧填充0: K' = K || 0x00...0x00")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- 若密钥长度 k = L1,则 K' = K")

&nbsp; &nbsp;&nbsp;iflen(key_bytes) > L1:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"\n输入密钥长度:&nbsp;{len(key_bytes)}&nbsp;字节 > L1 ({L1}&nbsp;字节)")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("执行操作: 对密钥进行SM3杂凑运算")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n输入:")
&nbsp; &nbsp; &nbsp; &nbsp; print_hex_block("原始密钥 K", bytes_to_hex(key_bytes))
&nbsp; &nbsp; &nbsp; &nbsp; key_padded =&nbsp;bytes.fromhex(sm3.sm3_hash(func.bytes_to_list(key_bytes)))
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n输出:")
&nbsp; &nbsp; &nbsp; &nbsp; print_hex_block("填充后密钥 K' = SM3(K)", bytes_to_hex(key_padded))
&nbsp; &nbsp;&nbsp;eliflen(key_bytes) < L1:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"\n输入密钥长度:&nbsp;{len(key_bytes)}&nbsp;字节 < L1 ({L1}&nbsp;字节)")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"执行操作: 在密钥右侧填充&nbsp;{L1 -&nbsp;len(key_bytes)}&nbsp;个 0x00 字节")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n输入:")
&nbsp; &nbsp; &nbsp; &nbsp; print_hex_block("原始密钥 K", bytes_to_hex(key_bytes))
&nbsp; &nbsp; &nbsp; &nbsp; key_padded = key_bytes +&nbsp;b'\x00'&nbsp;* (L1 -&nbsp;len(key_bytes))
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n输出:")
&nbsp; &nbsp; &nbsp; &nbsp; print_hex_block("填充后密钥 K' = K || 0x00...0x00", bytes_to_hex(key_padded))
&nbsp; &nbsp;&nbsp;else:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"\n输入密钥长度:&nbsp;{len(key_bytes)}&nbsp;字节 = L1 ({L1}&nbsp;字节)")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("执行操作: 无需填充")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n输入/输出:")
&nbsp; &nbsp; &nbsp; &nbsp; print_hex_block("密钥 K'", bytes_to_hex(key_bytes))
&nbsp; &nbsp; &nbsp; &nbsp; key_padded = key_bytes

&nbsp; &nbsp; print_subsection("1.2 生成 IPAD 和 OPAD")
&nbsp; &nbsp;&nbsp;print("算法要求:")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- IPAD = 0x36 重复 L1 次 (共64字节)")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- OPAD = 0x5C 重复 L1 次 (共64字节)")

&nbsp; &nbsp; ipad =&nbsp;b'\x36'&nbsp;* L1
&nbsp; &nbsp; opad =&nbsp;b'\x5c'&nbsp;* L1

&nbsp; &nbsp;&nbsp;print("\n输出:")
&nbsp; &nbsp; print_hex_block("IPAD (0x36 × 64)", bytes_to_hex(ipad))
&nbsp; &nbsp; print_hex_block("OPAD (0x5C × 64)", bytes_to_hex(opad))

&nbsp; &nbsp; print_subsection("1.3 计算子密钥 K1 和 K2")
&nbsp; &nbsp;&nbsp;print("算法要求:")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- K1 = K' ⊕ IPAD (按位异或)")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- K2 = K' ⊕ OPAD (按位异或)")

&nbsp; &nbsp; k1 =&nbsp;bytes(a ^ b&nbsp;for&nbsp;a, b&nbsp;inzip(key_padded, ipad))
&nbsp; &nbsp; k2 =&nbsp;bytes(a ^ b&nbsp;for&nbsp;a, b&nbsp;inzip(key_padded, opad))

&nbsp; &nbsp;&nbsp;print("\n输入:")
&nbsp; &nbsp; print_hex_block("填充后密钥 K'", bytes_to_hex(key_padded))
&nbsp; &nbsp; print_hex_block("IPAD", bytes_to_hex(ipad))
&nbsp; &nbsp; print_hex_block("OPAD", bytes_to_hex(opad))

&nbsp; &nbsp;&nbsp;print("\n输出:")
&nbsp; &nbsp; print_hex_block("子密钥 K1 = K' ⊕ IPAD", bytes_to_hex(k1))
&nbsp; &nbsp; print_hex_block("子密钥 K2 = K' ⊕ OPAD", bytes_to_hex(k2))

&nbsp; &nbsp; print_section("步骤2: 杂凑操作")

&nbsp; &nbsp; print_subsection("2.1 构造第一次杂凑输入")
&nbsp; &nbsp;&nbsp;print("算法要求:")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- 输入数据 = K1 || 消息")

&nbsp; &nbsp; h1_input = k1 + message_bytes

&nbsp; &nbsp;&nbsp;print("\n输入:")
&nbsp; &nbsp; print_hex_block("子密钥 K1", bytes_to_hex(k1))
&nbsp; &nbsp; print_hex_block("消息", bytes_to_hex(message_bytes))

&nbsp; &nbsp;&nbsp;print("\n输出:")
&nbsp; &nbsp; print_item("输入数据长度",&nbsp;f"{len(h1_input)}&nbsp;字节 ({len(h1_input) *&nbsp;8}&nbsp;位)")
&nbsp; &nbsp; print_hex_block("输入数据 = K1 || 消息", bytes_to_hex(h1_input))

&nbsp; &nbsp; print_subsection("2.2 计算第一次杂凑值")
&nbsp; &nbsp;&nbsp;print("算法要求:")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- H' = SM3(K1 || 消息)")

&nbsp; &nbsp;&nbsp;print("\n输入:")
&nbsp; &nbsp; print_hex_block("杂凑输入数据", bytes_to_hex(h1_input))

&nbsp; &nbsp; h1_hex = sm3.sm3_hash(func.bytes_to_list(h1_input))
&nbsp; &nbsp; h1_bytes =&nbsp;bytes.fromhex(h1_hex)

&nbsp; &nbsp;&nbsp;print("\n输出:")
&nbsp; &nbsp; print_hex_block("第一次杂凑值 H'", h1_hex.upper())
&nbsp; &nbsp; print_item("H' 长度",&nbsp;f"{len(h1_bytes)}&nbsp;字节 ({len(h1_bytes) *&nbsp;8}&nbsp;位)")

&nbsp; &nbsp; print_section("步骤3: 输出变换")

&nbsp; &nbsp; print_subsection("3.1 构造第二次杂凑输入")
&nbsp; &nbsp;&nbsp;print("算法要求:")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- 输入数据 = K2 || H'")

&nbsp; &nbsp; h2_input = k2 + h1_bytes

&nbsp; &nbsp;&nbsp;print("\n输入:")
&nbsp; &nbsp; print_hex_block("子密钥 K2", bytes_to_hex(k2))
&nbsp; &nbsp; print_hex_block("第一次杂凑值 H'", h1_hex.upper())

&nbsp; &nbsp;&nbsp;print("\n输出:")
&nbsp; &nbsp; print_item("输入数据长度",&nbsp;f"{len(h2_input)}&nbsp;字节 ({len(h2_input) *&nbsp;8}&nbsp;位)")
&nbsp; &nbsp; print_hex_block("输入数据 = K2 || H'", bytes_to_hex(h2_input))

&nbsp; &nbsp; print_subsection("3.2 计算第二次杂凑值")
&nbsp; &nbsp;&nbsp;print("算法要求:")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- H'' = SM3(K2 || H')")

&nbsp; &nbsp;&nbsp;print("\n输入:")
&nbsp; &nbsp; print_hex_block("杂凑输入数据", bytes_to_hex(h2_input))

&nbsp; &nbsp; h2_hex = sm3.sm3_hash(func.bytes_to_list(h2_input))
&nbsp; &nbsp; h2_bytes =&nbsp;bytes.fromhex(h2_hex)

&nbsp; &nbsp;&nbsp;print("\n输出:")
&nbsp; &nbsp; print_hex_block("第二次杂凑值 H''", h2_hex.upper())
&nbsp; &nbsp; print_item("H'' 长度",&nbsp;f"{len(h2_bytes)}&nbsp;字节 ({len(h2_bytes) *&nbsp;8}&nbsp;位)")

&nbsp; &nbsp; print_section("步骤4: 截断操作")

&nbsp; &nbsp; print_subsection("4.1 MAC值长度设置")
&nbsp; &nbsp; mac_length =&nbsp;128
&nbsp; &nbsp;&nbsp;print("算法要求:")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- MAC长度 m 通常取 L2/2 = 128 位 (16 字节)")
&nbsp; &nbsp;&nbsp;print(f"\n设置:")
&nbsp; &nbsp; print_item("MAC长度 m",&nbsp;f"{mac_length}&nbsp;位 =&nbsp;{mac_length //&nbsp;8}&nbsp;字节")

&nbsp; &nbsp; print_subsection("4.2 提取MAC值")
&nbsp; &nbsp;&nbsp;print("算法要求:")
&nbsp; &nbsp;&nbsp;print(" &nbsp;- MAC = MSB_m(H'')")
&nbsp; &nbsp;&nbsp;print(f" &nbsp;- 取 H'' 的最左侧&nbsp;{mac_length}&nbsp;位")

&nbsp; &nbsp; mac_hex = h2_hex[:mac_length //&nbsp;4].upper()
&nbsp; &nbsp; mac_bytes = h2_bytes[:mac_length //&nbsp;8]

&nbsp; &nbsp;&nbsp;print("\n输入:")
&nbsp; &nbsp; print_hex_block("第二次杂凑值 H''", h2_hex.upper())

&nbsp; &nbsp;&nbsp;print("\n输出:")
&nbsp; &nbsp; print_hex_block(f"MAC值 (前{mac_length}位)", mac_hex)
&nbsp; &nbsp; print_item("MAC长度",&nbsp;f"{len(mac_bytes)}&nbsp;字节 ({len(mac_bytes) *&nbsp;8}&nbsp;位)")

&nbsp; &nbsp; print_section("最终结果")

&nbsp; &nbsp; print_subsection("计算结果汇总")
&nbsp; &nbsp; print_item("完整杂凑值 H''", h2_hex.upper())
&nbsp; &nbsp; print_item("MAC值 (128位)", mac_hex)
&nbsp; &nbsp; print_item("MAC值 (256位)", h2_hex.upper())

&nbsp; &nbsp; print_subsection("算法流程回顾")
&nbsp; &nbsp;&nbsp;print("HMAC-SM3 算法完整流程:")
&nbsp; &nbsp;&nbsp;print(" &nbsp;步骤1: 密钥扩展")
&nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp;- K1 = K' ⊕ IPAD")
&nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp;- K2 = K' ⊕ OPAD")
&nbsp; &nbsp;&nbsp;print(" &nbsp;步骤2: 杂凑操作")
&nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp;- H' = SM3(K1 || 消息)")
&nbsp; &nbsp;&nbsp;print(" &nbsp;步骤3: 输出变换")
&nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp;- H'' = SM3(K2 || H')")
&nbsp; &nbsp;&nbsp;print(" &nbsp;步骤4: 截断操作")
&nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp;- MAC = MSB_m(H'')")
&nbsp; &nbsp; print_separator()

if&nbsp;__name__ ==&nbsp;"__main__":
&nbsp; &nbsp;&nbsp;whileTrue:
&nbsp; &nbsp; &nbsp; &nbsp; hmac_sm3_detailed()

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n是否继续计算? (y/n): ", end="")
&nbsp; &nbsp; &nbsp; &nbsp; continue_choice =&nbsp;input().strip().lower()
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;continue_choice !=&nbsp;'y':
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n程序结束。")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n")

该脚本具有以下特点:

  • • 符合国家标准:严格按照GB/T 15852.2-2024标准实现HMAC-SM3算法
  • • 详细步骤展示:展示完整的计算步骤,包括密钥扩展、杂凑操作、输出变换和截断操作
  • • 多种输入类型:支持字符串输入和十六进制输入两种方式
  • • 可视化计算过程:详细显示每一步的输入、输出和中间结果
  • • 清晰的结果展示:输出完整的杂凑值和截断后的MAC值
  • • 交互式操作:提供友好的命令行交互界面

6.1.2 脚本实现细节

主要依赖库

  • • gmssl:提供SM3杂凑函数实现
  • • func:用于字节串和列表之间的转换

核心函数

  • • bytes_to_hex:将字节串转换为十六进制字符串
  • • hmac_sm3_detailed:HMAC-SM3算法的详细计算过程实现

算法实现步骤

  1. 1. 密钥扩展:处理密钥,生成K1和K2子密钥
  2. 2. 杂凑操作:计算SM3(K1 || 消息)得到H’
  3. 3. 输出变换:计算SM3(K2 || H’)得到H”
  4. 4. 截断操作:提取H”的前128位作为MAC值

6.1.3 脚本使用方法

  1. 1. 运行脚本
   python HMAC_SM3计算过程详解.py
  1. 2. 输入密钥
  • • 输入十六进制格式的密钥,例如:00112233445566778899AABBCCDDEEFF
  1. 3. 选择消息输入类型
  • • 选项1:字符串输入
  • • 选项2:十六进制输入
  1. 4. 查看计算结果
  • • 脚本将显示详细的计算过程,包括每一步的输入、输出和中间结果
  • • 最终输出完整的杂凑值和截断后的MAC值

6.2 测试向量

6.2.1 测试环境

  • • 杂凑函数:SM3
  • • 密钥长度:128位
  • • MAC长度:128位
  • • 测试消息:表C.1中定义的9个输入位串

6.2.2 测试结果示例

密钥1:00112233445566778899AABBCCDDEEFF

| 序号 | 输入消息 | 128位MAC值 | | — | — | — | | 1 | 空位串 | C8E4E95012EB3D449B5DD0691947986E | | 2 | “a” | 5FD9F7568A24C438F14B7A22E799B068 | | 3 | “abc” | 0933617A88D312F6F9FB4B5F200E31A6 | | 4 | “messagedigest” | 9C9A22E8B5797B82CFF9BABA56893CC1 |

密钥2:0123456789ABCDEFFEDCBA9876543210

| 序号 | 输入消息 | 128位MAC值 | | — | — | — | | 1 | 空位串 | F14B797B559216B73D3816ADFB790250 | | 2 | “a” | 5BD1836B97C74F88A77BC309E77A2694 | | 3 | “abc” | 28D8A61BE67D8BF7652C4EDA7092B612 | | 4 | “messagedigest” | E0ACCC4DA77E77D135F17F5CA1EE3E60 |

7. 与其他MAC算法的比较

| 算法 | 基础原语 | 安全性强度 | 计算效率 | 实现复杂度 | 标准支持 | | — | — | — | — | — | — | | HMAC-SM3 | SM3杂凑函数 | 最高256位 | 中等 | 简单 | GB/T 15852.2—2024 | | HMAC-SHA256 | SHA-256杂凑函数 | 最高256位 | 中等 | 简单 | FIPS PUB 198-1 | | CMAC-AES | AES分组密码 | 最高256位 | 高 | 中等 | GB/T 15852.1—2020 | | GMAC | SM4分组密码 | 最高128位 | 高 | 复杂 | 商用密码算法标准 |

8. 实施建议

8.1 密钥管理

  • • 密钥生成:使用密码学安全的随机数生成器生成密钥
  • • 密钥长度:建议使用256位密钥,提供最高安全性
  • • 密钥更新:定期更新密钥,避免长期使用同一密钥
  • • 密钥存储:采用安全的密钥存储机制,防止密钥泄露
  • • 密钥传输:确保密钥在传输过程中的机密性和完整性
  • • 敏感数据清除:在使用完毕后立即清除内存中的密钥和敏感中间结果

8.2 实现注意事项

  • • 杂凑函数实现:确保SM3杂凑函数的正确实现,可使用经过认证的实现库
  • • 填充操作:严格按照标准要求执行密钥填充和消息填充
  • • 截断长度:根据安全需求选择合适的MAC长度,建议不小于128位
  • • 抗侧信道攻击:在硬件实现中考虑抗侧信道攻击措施
  • • 密钥预处理:支持可变长度密钥,添加密钥预处理逻辑(当密钥超长时先进行哈希)
  • • 防重放机制:添加防重放保护,如使用时间戳、序列号等

8.3 验证与测试

  • • 正确性验证:使用标准测试向量验证实现的正确性
  • • 性能测试:根据应用场景测试算法性能
  • • 安全性评估:定期进行安全性评估,及时修复漏洞
  • • 代码审计:对实现代码进行安全审计,检查潜在的安全问题

8.4 实际实现案例

8.4.1 基于密码服务接口的HMAC-SM3实现

// 假设已经获得了会话句柄hSessionHandle
intMAC(void&nbsp;*hSessionHandle,&nbsp;const&nbsp;unsigned&nbsp;char&nbsp;*key,&nbsp;const&nbsp;unsigned&nbsp;char&nbsp;*message,
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;unsigned&nbsp;int&nbsp;messageLen,&nbsp;unsigned&nbsp;char&nbsp;*mac)&nbsp;{
&nbsp; &nbsp;&nbsp;unsignedchar&nbsp;K_pad[64] = {0}; &nbsp;// 密钥填充缓冲区
&nbsp; &nbsp;&nbsp;unsignedchar&nbsp;ipad[64], opad[64]; &nbsp;// 内部和外部填充
&nbsp; &nbsp;&nbsp;unsignedchar&nbsp;innerHash[32]; &nbsp;// 内层哈希结果
&nbsp; &nbsp;&nbsp;unsignedint&nbsp;hashLen =&nbsp;32; &nbsp;// SM3输出长度
&nbsp; &nbsp;&nbsp;int&nbsp;i;

&nbsp; &nbsp;&nbsp;// 步骤1:密钥填充处理
&nbsp; &nbsp;&nbsp;memcpy(K_pad, key,&nbsp;32); &nbsp;// 复制32字节密钥到64字节缓冲区

&nbsp; &nbsp;&nbsp;// 步骤2:生成内部和外部填充
&nbsp; &nbsp;&nbsp;for&nbsp;(i =&nbsp;0; i <&nbsp;64; i++) {
&nbsp; &nbsp; &nbsp; &nbsp; ipad[i] = K_pad[i] ^&nbsp;0x36; &nbsp;// 内部填充:异或0x36
&nbsp; &nbsp; &nbsp; &nbsp; opad[i] = K_pad[i] ^&nbsp;0x5c; &nbsp;// 外部填充:异或0x5c
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;// 步骤3:计算内层哈希 H(ipad || message)
&nbsp; &nbsp; SDF_HashInit(hSessionHandle,&nbsp;0x00000001,&nbsp;NULL,&nbsp;NULL,&nbsp;0); &nbsp;// 初始化SM3算法
&nbsp; &nbsp; SDF_HashUpdate(hSessionHandle, ipad,&nbsp;64); &nbsp;// 添加内部填充
&nbsp; &nbsp; SDF_HashUpdate(hSessionHandle, message, messageLen); &nbsp;// 添加消息
&nbsp; &nbsp; SDF_HashFinal(hSessionHandle, innerHash, &hashLen); &nbsp;// 获得内层哈希

&nbsp; &nbsp;&nbsp;// 步骤4:计算外层哈希 H(opad || innerHash)
&nbsp; &nbsp; SDF_HashInit(hSessionHandle,&nbsp;0x00000001,&nbsp;NULL,&nbsp;NULL,&nbsp;0); &nbsp;// 重新初始化
&nbsp; &nbsp; SDF_HashUpdate(hSessionHandle, opad,&nbsp;64); &nbsp;// 添加外部填充
&nbsp; &nbsp; SDF_HashUpdate(hSessionHandle, innerHash,&nbsp;32); &nbsp;// 添加内层哈希
&nbsp; &nbsp; SDF_HashFinal(hSessionHandle, mac, &hashLen); &nbsp;// 获得最终MAC值

&nbsp; &nbsp;&nbsp;return0;
}

8.4.2 关键实现说明

  1. 1. HMAC结构:严格遵循RFC2104标准实现
  • • 内层哈希:H(K_ipad || message)
  • • 外层哈希:H(K_opad || 内层哈希结果)
  1. 2. 安全特性
  • • 密钥处理:通过固定长度填充(64字节)和异或操作消除密钥长度差异
  • • 双重哈希:有效防止长度扩展攻击
  • • 使用经过认证的密码服务接口(SDF_*函数)
  1. 3. 算法标识
  • • 0x00000001:表示使用SM3算法(输出32字节)

8.5 常见安全问题与最佳实践

8.5.1 常见安全问题

  1. 1. 密钥管理问题
  • • 密钥明文传输,未进行机密性和完整性保护
  • • 敏感数据未清除,残留在内存中
  • • 密钥长度不足或使用弱密钥
  1. 2. 实现问题
  • • 未添加防重放机制,容易遭受重放攻击
  • • 消息格式设计不合理,无法防止篡改
  • • 未使用链式完整性保护,无法检测记录删除或插入
  1. 3. 部署问题
  • • 密钥长期不更新
  • • 未定期进行安全性评估
  • • 缺乏监控和审计机制

8.5.2 最佳实践

  1. 1. 链式完整性保护
  • • 每条记录的MAC值作为下一条记录的输入,形成密码学链条
  • • 防止记录被删除、插入或重新排序
  1. 2. 防重放机制
  • • 使用时间戳+随机数确保每条消息唯一
  • • 添加消息序列号,防止重复处理
  1. 3. 合规性考虑
  • • 遵循等保要求,使用经过认证的密码产品
  • • 定期进行密码应用安全性评估
  • • 建立完善的密钥管理体系
  1. 4. 数据库设计最佳实践
  • • 添加integrity_type字段,明确标注使用的算法
  • • 添加msg_serial_no字段,实现防重放
  • • 添加prev_log_hash字段,实现链式完整性
  • • 分离敏感字段,采用不同的保护机制

9. 总结

HMAC-SM3算法是基于中国自主设计的SM3杂凑函数的消息鉴别码算法,具有高安全性、高效率和良好的实现特性。该算法通过两次SM3杂凑函数调用,结合密钥生成固定长度的MAC值,可有效用于消息完整性验证和真实性鉴别。

作为国家标准GB/T 15852.2—2024的重要组成部分,HMAC-SM3算法在网络通信、数据存储、金融交易和物联网等领域具有广泛的应用前景。随着中国商用密码体系的不断完善,HMAC-SM3算法将在保障国家信息安全方面发挥越来越重要的作用。

9.1 技术优势

  • • 自主可控:基于中国自主设计的SM3杂凑函数,具有自主知识产权
  • • 高安全性:提供最高256位的安全性强度,能够抵抗各种已知攻击
  • • 高效率:算法结构简单,易于实现和优化
  • • 广泛适用性:可应用于各种计算环境和应用场景
  • • 标准支持:符合国家标准,便于跨系统互操作

9.2 发展趋势

  • • 硬件加速:随着物联网和5G技术的发展,硬件加速实现将成为趋势
  • • 量子安全:算法设计考虑了量子安全特性,能够抵抗量子计算攻击
  • • 轻量级实现:针对资源受限设备的轻量级实现将得到更多关注
  • • 标准化应用:在更多国家标准和行业标准中得到应用

HMAC-SM3算法作为基于杂凑函数的消息鉴别码算法的重要代表,将在未来的网络安全领域中继续发挥重要作用,为数字经济的发展提供坚实的安全保障。

参考文献

  1. 1. GB/T 15852.2—2024《网络安全技术 消息鉴别码 第2部分:采用专门设计的杂凑函数的机制》
  2. 2. GB/T 32905—2016《信息安全技术 SM3密码杂凑算法》
  3. 3. GB/T 18238.3—2024《网络安全技术 杂凑函数 第3部分:专门设计的杂凑函数》
  4. 4. FIPS PUB 198-1《The Keyed-Hash Message Authentication Code (HMAC)》
  5. 5. ISO/IEC 10118-3《Information technology—Security techniques—Hash-functions—Part 3: Dedicated hash-functions》

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:利刃信安 利刃信安 利刃信安《【密码算法】HMAC-SM3 消息鉴别码》

评论:0   参与:  0