文章总结: 本文详细解读SM3密码杂凑算法,作为中国国家标准GB/T32905—2016,其输出256比特摘要。文档系统阐述了算法概述、标准体系、核心术语及消息填充、迭代压缩等运算流程,解析了布尔函数与置换函数机制。内容对比了SM3与SHA系列算法特性,强调其高安全性与效率,并附带Python实现代码与运算示例,为掌握该国产密码算法提供了精准的技术指导与实践参考。 综合评分: 88 文章分类: 技术标准,数据安全,安全开发
【密码算法】SM3 密码杂凑算法
原创
利刃信安 利刃信安
利刃信安
2026年3月6日 14:03 北京
SM3 密码杂凑算法
1. 概述
SM3密码杂凑算法是中国专门设计的杂凑函数,可用于消息摘要的计算、数字签名和验证、消息鉴别码的生成与验证,以及随机数的生成,具有高安全性和高效率的特点,已被纳入国家标准体系。
1.1 标准信息
-
• 主要标准:GB/T 32905—2016《信息安全技术 SM3密码杂凑算法》
-
• 相关标准:GB/T 18238.3—2024《网络安全技术 杂凑函数 第3部分:专门设计的杂凑函数》
-
• 发布与实施:
-
• GB/T 32905—2016:2016-08-29发布,2017-03-01实施
-
• GB/T 18238.3—2024:2024-09-29发布,2025-04-01实施
-
• 起草单位:清华大学、国家密码管理局商用密码检测中心、解放军信息工程大学、中国科学院数据与通信保护研究教育中心等
-
• 标准关系:GB/T 18238.3—2024将SM3纳入专门设计的杂凑函数标准体系,对其算法模型、安全性要求等进行了进一步规范
1.2 算法基本概念
SM3是一种专门设计的杂凑函数,即在设计过程中不依赖其他密码原语(如分组密码等),直接设计形成的杂凑函数。它用于将输入为长度为l( l < 2^{64} )比特的消息 m,经过填充、迭代压缩,生成杂凑值,杂凑值输出长度为256比特,可用于消息摘要的计算、数字签名和验证、消息鉴别码的生成与验证,以及随机数的生成等密码学应用。
1.3 基本参数
- • 输入:长度为 l ( l < 2^{64} )比特的任意消息
- • 输出:256比特的固定长度杂凑值(消息摘要)
- • 分组长度:512比特( L1 = 512 )
- • 状态长度:256比特( L2 = 256 )
- • 杂凑值长度:256比特( LH = 256 )
1.4 算法模型
SM3采用基于轮函数的通用模型,主要包括以下组成部分:
- • 轮函数:输入两个位串(512比特消息分组和256比特当前状态),输出一个256比特新状态
- • 压缩函数CF:轮函数的具体实现,将当前状态和消息分组变换为新状态
- • 数据处理:填充后的消息以字节串形式处理,每组8位为一个字节,高位在前
- • 输出变换:采用恒等变换,直接输出最终状态作为杂凑值 H = V(n)
2. 术语和核心定义
2.1 术语定义
| 术语 | 定义 | | — | — | | 比特串 | 具有0或1值的二进制数字序列 | | 字节 | 由8个连续位构成的位串 | | 大端 | 数据在内存中的表示格式,左边为高有效位,右边为低有效位。数的高阶字节放在存储器的低地址,低阶字节放在高地址 | | 消息 | 任意有限长度的比特串,作为杂凑算法的输入数据 | | 杂凑值 | 杂凑算法作用于消息时输出的固定长度消息摘要 | | 专门设计的杂凑函数 | 在设计过程中不依赖其他密码原语(如分组密码等),直接设计形成的杂凑函数 | | 压缩函数 | 将固定长度的输入(如512比特)压缩为更短的输出(如256比特)的函数 | | 消息分组 | 将填充后的消息按固定长度(512比特)划分得到的块 | | 迭代压缩 | 对每个消息分组依次应用压缩函数,将结果传递给下一轮迭代的过程 | | 轮函数 | 杂凑函数中用于迭代处理的基本函数,对输入的状态和消息块进行变换 |
2.2 核心常量与函数
2.2.1 初始值
IV = 7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e
2.2.2 常量
Tj = 0x79cc4519 (0 ≤ j ≤ 15)
Tj = 0x7a879d8a (16 ≤ j ≤ 63)
2.2.3 布尔函数
FFj(X,Y,Z) = X⊕Y⊕Z (0 ≤ j ≤ 15)
FFj(X,Y,Z) = (X∧Y)∨(X∧Z)∨(Y∧Z) (16 ≤ j ≤ 63)
GGj(X,Y,Z) = X⊕Y⊕Z (0 ≤ j ≤ 15)
GGj(X,Y,Z) = (X∧Y)∨(¬X∧Z) (16 ≤ j ≤ 63)
2.2.4 置换函数
P0(X) = X⊕(X<<<9)⊕(X<<<17)
P1(X) = X⊕(X<<<15)⊕(X<<<23)
3. 算法运算步骤
3.1 消息填充
SM3的填充方法应采用GB/T 18238.1—2024中A.3规定的方法2,取预留位串长度r=64。具体步骤如下:
- 1. 将比特”1″添加到消息末尾
- 2. 添加k个”0″,使得 l+1+k ≡ 448 mod 512 (k为最小非负整数)
- 3. 添加一个64位比特串,表示消息原始长度l的二进制形式
- 4. 填充后消息长度为512的整数倍
填充后的数据串以字节串形式作为输入,每组连续8位为一个字节,每组的第一位为该字节的最高有效位。
3.2 迭代压缩
- 1. 将填充后的消息按512比特分组,得到 n 个分组 B(0), B(1), …, B(n-1)
- 2. 初始化压缩函数输入为初始值 V(0) = IV
- 3. 对每个分组 B(i) ,执行压缩函数 V(i+1) = CF(V(i), B(i)) ,其中 CF 为压缩函数
3.3 压缩函数CF
压缩函数 CF 的执行过程如下:
- 1. 消息扩展:将消息分组 B(i) 扩展为132个字:
- • 第一步:将512位消息分组划分为16个32位字 W_0, W_1, …, W_{15}
- • 第二步:生成 W[16-67] (52个32位字):
W_j = P1(W_{j-16} ⊕ W_{j-9} ⊕ (W_{j-3} <<< 15)) ⊕ (W_{j-13} <<< 7) ⊕ W_{j-6}
其中:j = 16 到 67
P1(X) = X ⊕ (X <<< 15) ⊕ (X <<< 23)
- • 第三步:生成 W'[0-63] (64个32位字):
W'_j = W_j ⊕ W_{j+4}
其中:j = 0 到 63
- 2. 初始化寄存器:将当前状态 V(i) 拆分为8个32位寄存器:
A, B, C, D, E, F, G, H = V(i)
- 3. 64轮迭代:对于 j = 0 到 63 ,执行以下步骤:
- 常量:
current_Tj = 0x79cc4519 if 0 <= j <= 15 else 0x7a879d8a
布尔函数:
FFj_val = A ^ B ^ C if 0 <= j <= 15 else (A & B) | (A & C) | (B & C)
GGj_val = E ^ F ^ G if 0 <= j <= 15 else (E & F) | ((~E) & G)
轮函数核心计算:
# 计算 SS1
A_rot12 = A <<< 12 # A循环左移12位
Tj_rot = current_Tj <<< (j % 32) # Tj循环左移j%32位
temp1 = (A_rot12 + E + Tj_rot) & 0xFFFFFFFF
SS1 = temp1 <<< 7 # 循环左移7位
# 计算 SS2
SS2 = SS1 ^ A_rot12
# 计算 TT1 和 TT2
TT1 = (FFj_val + D + SS2 + W'[j]) & 0xFFFFFFFF
TT2 = (GGj_val + H + SS1 + W[j]) & 0xFFFFFFFF
寄存器更新:
# 更新工作变量
new_A = TT1
new_B = A
new_C = B <<< 9 # 循环左移9位
new_D = C
new_E = P0(TT2) # 应用置换函数P0
new_F = E
new_G = F <<< 19 # 循环左移19位
new_H = G
# 将新值赋给工作变量
A, B, C, D, E, F, G, H = new_A, new_B, new_C, new_D, new_E, new_F, new_G, new_H
- 4. 更新中间值:
V(i+1) = (A,B,C,D,E,F,G,H) ⊕ V(i)
即新状态是当前轮计算结果与输入状态的异或。
3.4 输出杂凑值
SM3的输出变换为恒等变换,即直接输出最终状态 V(n) 作为256比特杂凑值。
4. 应用与特点
4.1 应用场景
- • 数字签名和验证:用于生成和验证数字签名
- • 消息认证码(MAC):用于消息完整性验证和认证
- • 随机数生成:用于生成密码学安全的随机数
- • 密码存储:用于安全存储密码哈希
- • 其他密码学应用:如哈希链、承诺方案等
4.2 算法特点
-
• 高安全性:
-
• 抗碰撞攻击:设计上考虑了现代密码分析技术,目前尚未发现有效的碰撞攻击方法
-
• 抗原像攻击:给定杂凑值,难以找到对应的原始消息
-
• 抗第二原像攻击:给定消息,难以找到具有相同杂凑值的另一消息
-
• 抗差分攻击和线性攻击:采用了复杂的布尔函数和置换函数
-
• 高效率:
-
• 适用于各种计算环境,包括软件和硬件实现
-
• 算法结构简单,基于字节处理,易于优化实现
-
• 轮函数设计平衡了安全性和效率
-
• 国家标准:
-
• 由中国国家标准化管理委员会发布,适用于商用密码应用
-
• 是中国商用密码体系的重要组成部分
-
• 具有自主知识产权,不受国外专利限制
-
• 良好的雪崩效应:输入的微小变化会导致输出的显著变化,符合密码学杂凑函数的要求
4.3 与其他杂凑算法的比较
| 算法 | 输出长度 | 设计年份 | 所属标准 | | — | — | — | — | | SM3 | 256比特 | 2010 | GB/T 32905—2016 | | SHA-256 | 256比特 | 2001 | FIPS PUB 180-4 | | SHA-3 | 可配置(224/256/384/512) | 2015 | FIPS PUB 202 |
SM3算法在设计上参考了SHA-256的结构,但进行了改进和优化,具有自主知识产权,是中国商用密码体系的重要组成部分。
4.4 应用前景
随着密码技术的发展和应用需求的增长,SM3算法将在更多领域得到广泛应用,特别是在网络安全、金融安全、物联网安全等领域。作为中国自主设计的密码算法,SM3对于保障国家信息安全具有重要意义。
5. 实现与示例
5.1 运算示例
5.1.1 示例1:短消息
- • 输入:”abc”(十六进制:616263)
- • 输出杂凑值:66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
5.1.2 示例2:512比特消息
- • 输入:61626364重复16次(共512比特)
- • 输出杂凑值:debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732
5.2 详细计算过程脚本
工作区中提供了一个详细的SM3计算过程脚本 SM3计算过程详解.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SM3密码杂凑算法完整实现 - 优化版
基于GB/T 32905-2016标准
支持字符串和十六进制输入,详细展示每一步的计算过程
"""
IV = [
0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600,
0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e
]
defleft_rotate(n, b):
"""32位循环左移"""
return ((n << b) | (n >> (32 - b))) & 0xFFFFFFFF
defTj(j):
"""常量Tj"""
return0x79cc4519if j < 16else0x7a879d8a
defFFj(X, Y, Z, j):
"""布尔函数FFj"""
if j < 16:
return X ^ Y ^ Z
else:
return (X & Y) | (X & Z) | (Y & Z)
defGGj(X, Y, Z, j):
"""布尔函数GGj"""
if j < 16:
return X ^ Y ^ Z
else:
return (X & Y) | ((~X) & Z)
defP0(X):
"""置换函数P0"""
return X ^ left_rotate(X, 9) ^ left_rotate(X, 17)
defP1(X):
"""置换函数P1"""
return X ^ left_rotate(X, 15) ^ left_rotate(X, 23)
defhex_to_binary(hex_str):
"""将十六进制字符串转换为二进制字符串"""
hex_str = hex_str.replace(' ', '')
ifnot hex_str:
return''
binary = bin(int(hex_str, 16))[2:]
padding = len(binary) % 8
if padding != 0:
binary = '0' * (8 - padding) + binary
return binary
defbinary_to_hex(binary_str):
"""将二进制字符串转换为十六进制字符串"""
ifnot binary_str:
return''
padding = len(binary_str) % 8
if padding != 0:
binary_str = '0' * (8 - padding) + binary_str
hex_str = hex(int(binary_str, 2))[2:].upper()
return' '.join([hex_str[i:i + 2] for i inrange(0, len(hex_str), 2)])
defstring_to_binary(string):
"""将字符串转换为二进制字符串"""
bytes_data = string.encode('utf-8')
binary = ''.join(format(byte, '08b') for byte in bytes_data)
return binary
defpad_message(message, length):
"""实现填充逻辑"""
padded = message + "1"
l_plus_1 = length + 1
remainder = l_plus_1 % 512
k = 448 - remainder if remainder <= 448else512 - (remainder - 448)
padded += "0" * k
l_bin = bin(length)[2:].zfill(64)
padded += l_bin
return padded
defmessage_extension_detailed(Bi, group_num=0):
"""消息扩展函数 - 详细版本"""
print(f"\n{'=' * 80}")
print(f"消息扩展 - 第{group_num}组")
print(f"{'=' * 80}")
W = []
print(f"\n【步骤1】将512位消息分组划分为16个32位字")
print(f"输入: {binary_to_hex(Bi).replace(' ', '')}")
print(f"\n输出 W[0-15]:")
for i inrange(0, 512, 32):
word = int(Bi[i:i + 32], 2)
W.append(word)
for i inrange(16):
print(f" W[{i:2d}] = {format(W[i], '08x').upper()}")
print(f"\n【步骤2】生成W[16-67]")
print(f"公式: W[j] = P1(W[j-16] ⊕ W[j-9] ⊕ ROTL(W[j-3],15)) ⊕ ROTL(W[j-13],7) ⊕ W[j-6]")
print(f"其中: P1(X) = X ⊕ ROTL(X,15) ⊕ ROTL(X,23)")
for j inrange(16, 68):
temp1 = W[j - 16] ^ W[j - 9] ^ left_rotate(W[j - 3], 15)
temp2 = P1(temp1)
temp3 = temp2 ^ left_rotate(W[j - 13], 7) ^ W[j - 6]
W.append(temp3)
if j < 20:
print(f"\n 计算 W[{j}]:")
print(f" W[{j - 16}] = {format(W[j - 16], '08x').upper()}")
print(f" W[{j - 9}] = {format(W[j - 9], '08x').upper()}")
print(f" W[{j - 3}] = {format(W[j - 3], '08x').upper()}")
print(f" W[{j - 13}] = {format(W[j - 13], '08x').upper()}")
print(f" W[{j - 6}] = {format(W[j - 6], '08x').upper()}")
print(f" ")
print(f" ROTL(W[{j - 3}],15) = {format(left_rotate(W[j - 3], 15), '08x').upper()}")
print(f" W[{j - 16}] ⊕ W[{j - 9}] ⊕ ROTL(W[{j - 3}],15) = {format(temp1, '08x').upper()}")
print(f" P1({format(temp1, '08x')}) = {format(temp2, '08x').upper()}")
print(f" ROTL(W[{j - 13}],7) = {format(left_rotate(W[j - 13], 7), '08x').upper()}")
print(
f" W[{j}] = {format(temp2, '08x')} ⊕ {format(left_rotate(W[j - 13], 7), '08x')} ⊕ {format(W[j - 6], '08x')}")
print(f" = {format(W[j], '08x').upper()}")
print(f"\n生成的W[16-67] (完整):")
for i inrange(16, 68, 4):
line = ' '.join([f"W[{j}]={format(W[j], '08x').upper()}"for j inrange(i, min(i + 4, 68))])
print(f" {line}")
W_prime = []
print(f"\n【步骤3】生成W'[0-63]")
print(f"公式: W'[j] = W[j] ⊕ W[j+4]")
for j inrange(64):
W_prime.append(W[j] ^ W[j + 4])
print(f"\n生成的W'[0-63] (完整):")
for i inrange(0, 64, 4):
line = ' '.join([f"W'[{j}]={format(W_prime[j], '08x').upper()}"for j inrange(i, min(i + 4, 64))])
print(f" {line}")
return W, W_prime
defcompression_function_detailed(Vi, W, W_prime, group_num=0, show_all_rounds=False):
"""压缩函数 - 详细版本"""
print(f"\n{'=' * 80}")
print(f"压缩函数 - 第{group_num}组")
print(f"{'=' * 80}")
print(f"\n【输入】Vi (256位初始值或中间值):")
for i inrange(8):
print(f" V[{i}] = {format(Vi[i], '08x').upper()}")
A, B, C, D, E, F, G, H = Vi
print(f"\n【初始化工作变量】")
print(f" A = {format(A, '08x').upper()}")
print(f" B = {format(B, '08x').upper()}")
print(f" C = {format(C, '08x').upper()}")
print(f" D = {format(D, '08x').upper()}")
print(f" E = {format(E, '08x').upper()}")
print(f" F = {format(F, '08x').upper()}")
print(f" G = {format(G, '08x').upper()}")
print(f" H = {format(H, '08x').upper()}")
print(f"\n【开始64轮迭代压缩】")
print(f"迭代公式:")
print(f" SS1 = ROTL(ROTL(A,12) + E + ROTL(Tj,j), 7)")
print(f" SS2 = SS1 ⊕ ROTL(A,12)")
print(f" TT1 = FFj(A,B,C,j) + D + SS2 + W'[j]")
print(f" TT2 = GGj(E,F,G,j) + H + SS1 + W[j]")
print(f" ")
print(f" 新A = TT1")
print(f" 新B = A")
print(f" 新C = ROTL(B,9)")
print(f" 新D = C")
print(f" 新E = P0(TT2)")
print(f" 新F = E")
print(f" 新G = ROTL(F,19)")
print(f" 新H = G")
for j inrange(64):
A_rot12 = left_rotate(A, 12)
Tj_rot = left_rotate(Tj(j), j % 32)
SS1 = left_rotate((A_rot12 + E + Tj_rot) & 0xFFFFFFFF, 7)
SS2 = SS1 ^ A_rot12
TT1 = (FFj(A, B, C, j) + D + SS2 + W_prime[j]) & 0xFFFFFFFF
TT2 = (GGj(E, F, G, j) + H + SS1 + W[j]) & 0xFFFFFFFF
show_this_round = show_all_rounds or j < 4or j >= 60
if show_this_round:
print(f"\n{'─' * 80}")
print(f"【第{j}轮迭代】")
print(f"\n 计算SS1:")
print(f" Tj = {format(Tj(j), '08x').upper()} {'(j<16)' if j < 16 else '(j≥16)'}")
print(f" ROTL(A,12) = ROTL({format(A, '08x')},12) = {format(A_rot12, '08x').upper()}")
print(f" ROTL(Tj,j mod 32) = ROTL({format(Tj(j), '08x')},{j % 32}) = {format(Tj_rot, '08x').upper()}")
print(f" SS1 = ROTL({format(A_rot12, '08x')} + {format(E, '08x')} + {format(Tj_rot, '08x')}, 7)")
print(f" = ROTL({format((A_rot12 + E + Tj_rot) & 0xFFFFFFFF, '08x')}, 7)")
print(f" = {format(SS1, '08x').upper()}")
print(f"\n 计算SS2:")
print(f" SS2 = SS1 ⊕ ROTL(A,12) = {format(SS1, '08x')} ⊕ {format(A_rot12, '08x')}")
print(f" = {format(SS2, '08x').upper()}")
print(f"\n 计算TT1:")
ffj_result = FFj(A, B, C, j)
print(f" FFj(A,B,C,{j}) = {'A⊕B⊕C' if j < 16 else '(A∧B)∨(A∧C)∨(B∧C)'}")
print(f" = {format(ffj_result, '08x').upper()}")
print(f" TT1 = FFj + D + SS2 + W'[{j}]")
print(
f" = {format(ffj_result, '08x')} + {format(D, '08x')} + {format(SS2, '08x')} + {format(W_prime[j], '08x')}")
print(f" = {format(TT1, '08x').upper()}")
print(f"\n 计算TT2:")
ggj_result = GGj(E, F, G, j)
print(f" GGj(E,F,G,{j}) = {'E⊕F⊕G' if j < 16 else '(E∧F)∨(¬E∧G)'}")
print(f" = {format(ggj_result, '08x').upper()}")
print(f" TT2 = GGj + H + SS1 + W[{j}]")
print(
f" = {format(ggj_result, '08x')} + {format(H, '08x')} + {format(SS1, '08x')} + {format(W[j], '08x')}")
print(f" = {format(TT2, '08x').upper()}")
print(f"\n 计算P0(TT2):")
p0_result = P0(TT2)
print(f" P0(TT2) = TT2 ⊕ ROTL(TT2,9) ⊕ ROTL(TT2,17)")
print(
f" = {format(TT2, '08x')} ⊕ {format(left_rotate(TT2, 9), '08x')} ⊕ {format(left_rotate(TT2, 17), '08x')}")
print(f" = {format(p0_result, '08x').upper()}")
temp_A, temp_B, temp_C, temp_D = A, B, C, D
temp_E, temp_F, temp_G, temp_H = E, F, G, H
A = TT1
B = temp_A
C = left_rotate(temp_B, 9)
D = temp_C
E = P0(TT2)
F = temp_E
G = left_rotate(temp_F, 19)
H = temp_G
if show_this_round:
print(f"\n 更新工作变量:")
print(f" 新A = TT1 = {format(A, '08x').upper()}")
print(f" 新B = 旧A = {format(B, '08x').upper()}")
print(f" 新C = ROTL(旧B,9) = ROTL({format(temp_B, '08x')},9) = {format(C, '08x').upper()}")
print(f" 新D = 旧C = {format(D, '08x').upper()}")
print(f" 新E = P0(TT2) = {format(E, '08x').upper()}")
print(f" 新F = 旧E = {format(F, '08x').upper()}")
print(f" 新G = ROTL(旧F,19) = ROTL({format(temp_F, '08x')},19) = {format(G, '08x').upper()}")
print(f" 新H = 旧G = {format(H, '08x').upper()}")
print(f"\n{'=' * 80}")
print(f"【64轮迭代完成】")
print(f"{'=' * 80}")
print(f"\n最终工作变量值:")
print(f" A = {format(A, '08x').upper()}")
print(f" B = {format(B, '08x').upper()}")
print(f" C = {format(C, '08x').upper()}")
print(f" D = {format(D, '08x').upper()}")
print(f" E = {format(E, '08x').upper()}")
print(f" F = {format(F, '08x').upper()}")
print(f" G = {format(G, '08x').upper()}")
print(f" H = {format(H, '08x').upper()}")
Vi_new = [
A ^ Vi[0], B ^ Vi[1], C ^ Vi[2], D ^ Vi[3],
E ^ Vi[4], F ^ Vi[5], G ^ Vi[6], H ^ Vi[7]
]
print(f"\n【输出】Vi+1 = Vi ⊕ (A,B,C,D,E,F,G,H):")
for i inrange(8):
print(
f" V[{i}] = {format(Vi[i], '08x')} ⊕ {format([A, B, C, D, E, F, G, H][i], '08x')} = {format(Vi_new[i], '08x').upper()}")
return Vi_new
defsm3_hash_detailed(input_data, input_type='hex', show_all_rounds=False):
"""SM3杂凑算法主函数 - 详细版本"""
print("\n" + "=" * 80)
print("SM3密码杂凑算法完整计算过程")
print("=" * 80)
if input_type == 'string':
print(f"\n【输入类型】字符串")
print(f"【输入内容】{input_data}")
binary_message = string_to_binary(input_data)
hex_message = binary_to_hex(binary_message).replace(' ', '')
print(f"【十六进制】{hex_message}")
else:
print(f"\n【输入类型】十六进制")
print(f"【输入内容】{input_data}")
binary_message = hex_to_binary(input_data)
hex_message = input_data.replace(' ', '')
length = len(binary_message)
print(f"【消息长度】{length} 比特 ({length // 8} 字节)")
print(f"\n{'=' * 80}")
print("第一步: 消息填充")
print(f"{'=' * 80}")
print(f"\n【填充规则】")
print(f" 1. 在消息末尾添加一个比特'1'")
print(f" 2. 添加k个'0',使得 (l+1+k) mod 512 = 448")
print(f" 3. 添加64位二进制表示的消息长度l")
print(f" 4. 填充后消息长度为512的倍数")
l_plus_1 = length + 1
remainder = l_plus_1 % 512
k = 448 - remainder if remainder <= 448else512 - (remainder - 448)
print(f"\n【填充参数计算】")
print(f" 原始消息长度 l = {length}")
print(f" l + 1 = {length} + 1 = {l_plus_1}")
print(f" (l + 1) mod 512 = {l_plus_1} mod 512 = {remainder}")
print(f" 需要填充的0的个数 k = 448 - {remainder} = {k}")
print(f" 填充后总长度 = {length} + 1 + {k} + 64 = {length + 1 + k + 64}")
padded_message = pad_message(binary_message, length)
print(f"\n【填充过程】")
print(f" 步骤1: 添加'1'")
print(f" 输入: {binary_message[:80]}{'...' if len(binary_message) > 80 else ''}")
print(f" 输出: {binary_message[:80]}{'...' if len(binary_message) > 80 else ''}1")
print(f"\n 步骤2: 添加{k}个'0'")
print(f" 输出长度: {len(binary_message) + 1 + k} 比特")
print(f"\n 步骤3: 添加64位长度表示")
l_bin = bin(length)[2:].zfill(64)
print(f" 长度l的二进制(64位): {l_bin}")
print(f" 长度l的十六进制: {format(length, '016x').upper()}")
padded_hex = binary_to_hex(padded_message)
print(f"\n【填充后消息】(十六进制):")
print(f" {padded_hex.replace(' ', '')}")
num_blocks = len(padded_message) // 512
print(f"\n【消息分组】{num_blocks}组,每组512比特")
print(f"\n{'=' * 80}")
print("第二步: 迭代压缩")
print(f"{'=' * 80}")
print(f"\n【初始值IV】")
for i inrange(8):
print(f" V[{i}] = {format(IV[i], '08x').upper()}")
V = IV[:]
for i inrange(num_blocks):
print(f"\n{'#' * 80}")
print(f"# 处理第{i}组消息分组B{i}")
print(f"{'#' * 80}")
Bi = padded_message[i * 512:(i + 1) * 512]
print(f"\n【消息分组B{i}】")
print(f" 二进制: {Bi[:80]}{'...' if len(Bi) > 80 else ''}")
print(f" 十六进制: {binary_to_hex(Bi).replace(' ', '')}")
W, W_prime = message_extension_detailed(Bi, i)
V = compression_function_detailed(V, W, W_prime, i, show_all_rounds)
print(f"\n{'=' * 80}")
print("第三步: 输出杂凑值")
print(f"{'=' * 80}")
hash_value = ''.join([format(v, '08x').upper() for v in V])
print(f"\n【最终杂凑值】(256位):")
print(f" {hash_value}")
print(f"\n【分组显示】:")
for i inrange(8):
print(f" V[{i}] = {format(V[i], '08x').upper()}")
print(f"\n{'=' * 80}")
print("计算完成")
print(f"{'=' * 80}")
return hash_value
defmain():
"""主函数"""
print("=" * 80)
print("SM3密码杂凑算法实现")
print("基于GB/T 32905-2016标准")
print("=" * 80)
print("\n请选择输入类型:")
print(" 1. 字符串输入")
print(" 2. 十六进制输入")
whileTrue:
choice = input("\n请选择(1-2): ").strip()
if choice in ['1', '2']:
break
print("输入错误,请重新选择!")
if choice == '1':
input_data = input("请输入字符串: ").strip()
input_type = 'string'
else:
input_data = input("请输入十六进制(例如: 616263): ").strip()
input_type = 'hex'
print("\n是否显示所有64轮迭代的详细过程?")
print(" 1. 显示前4轮和后4轮(推荐)")
print(" 2. 显示所有64轮(输出较多)")
whileTrue:
detail_choice = input("\n请选择(1-2): ").strip()
if detail_choice in ['1', '2']:
break
print("输入错误,请重新选择!")
show_all_rounds = (detail_choice == '2')
result = sm3_hash_detailed(input_data, input_type, show_all_rounds)
print(f"\n最终结果: {result}")
if __name__ == "__main__":
main()
该脚本可以:
- 1. 展示完整的计算步骤:包括消息填充、消息扩展、64轮迭代压缩等
- 2. 支持多种输入类型:字符串输入和十六进制输入
- 3. 可视化迭代过程:默认显示前4轮和后4轮迭代,可选择显示所有64轮
- 4. 详细的中间结果:每轮迭代中显示SS1、SS2、TT1、TT2等中间值的计算过程
5.3 脚本使用方法
- 1. 运行脚本:
python SM3计算过程详解.py
- 2. 选择输入类型:
- • 选项1:字符串输入
- • 选项2:十六进制输入
- 3. 选择详细程度:
- • 选项1:显示前4轮和后4轮(推荐)
- • 选项2:显示所有64轮
5.4 第三方库实现
实际应用中,建议使用成熟的密码学库,如gmssl,它提供了经过严格测试的SM3实现:
# 使用gmssl库的SM3实现示例
# 安装:pip install gmssl
from gmssl import sm3
message = "abc"
hash_value = sm3.sm3_hash(message.encode())
print(hash_value) # 输出:66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
6. 对象标识符
SM3密码杂凑算法有以下对象标识符(OID):
6.1 主要OID
- • id-dhf-sm3:{iso(1) member-body(2) cn(156) scctc(10197) algorithm(1) sm3(401)}
- • 用于在密码协议和标准中唯一标识SM3算法
6.2 ASN.1定义
DedicatedHashFunctions {
iso(1) standard(0) hash-functions(10118) part3(3)
asn1-module(1) dedicated-hash-functions(0)}
DEFINITIONS EXPLICIT TAGS ::= BEGIN
-- 省略部分定义 --
id-scctc-algorithm OID ::= {iso(1) member-body(2) cn(156) scctc(10197) algorithm(1)}
id-sm3 OID ::= {id-scctc-algorithm sm3(401)}
id-dhf-sm3 OID ::= {id-scctc-algorithm sm3(401)}
-- 省略部分定义 --
END -- DedicatedHashFunctions --
6.3 用途
对象标识符用于在密码协议、数字证书和其他安全应用中明确标识所使用的SM3杂凑算法,确保不同系统之间的互操作性。
7. 总结
SM3密码杂凑算法是中国自主设计的专门密码学杂凑函数,具有高安全性和高效率的特点。作为国家标准,SM3在商用密码应用中发挥着重要作用,为数字签名、消息认证等安全服务提供了基础支持。
7.1 标准演进
- • 2016年发布GB/T 32905—2016,首次规定SM3算法
- • 2024年发布GB/T 18238.3—2024,将SM3纳入专门设计的杂凑函数标准体系
7.2 技术特点
- • 采用基于轮函数的通用模型
- • 不依赖其他密码原语,独立设计
- • 具有良好的抗碰撞、抗原像和抗第二原像能力
- • 适合软件和硬件实现
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:利刃信安 利刃信安 利刃信安《【密码算法】SM3 密码杂凑算法》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论