1.范围
本文本规定了SM3密码杂凑算法的计算方法和计算步骤,并给出了运算示例。
本文本适用于商用密码应用中的数字签名和验证、消息认证码的生成与验证以及随机数的生成,可满足多种密码应用的安全需求。同时,本文本还可为安全产品生产商提供产品和技术的标准定位以及标准化的参考,提高安全产品的可信性与互操作性。
2.术语和定义
2.1 比特串 bit string
由0和1组成的的二进制数字序列
2.2 大端 bigf-endian
数据在内存中的一种表示格式,规定左边为高有效位,右边为低有效位。数的高阶字节放在存储器的低地址,数的低阶字节放在存储器的高地址。
2.3 消息 message
任意有限长度的比特串。本文文本中消息作为杂凑算法的输入数据。
2.4 杂凑值 hash value
杂凑算法作用于消息后输出的特定长度的比特串,本文本中的杂凑值的长度为256比特。
2.5 字 word
长度为32的比特串。
3.符号
下列符号适用于本文本。
ABCDEFGH:8个字寄存器或它们的值的串联
B(i):第i个消息分组
CF:压缩函数
FFj:布尔函数,随j的变化取不同的表达式
GGj:布尔函数,随j的变化取不同的表达式
IV:初始值,用于确定压缩函数寄存器的初态
P0:压缩函数中的置换函数
P1:消息扩展中的置换函数
Tj:常量,随j的变化取不同的值
m:消息
m′:填充后的消息
mod:模运算
^:32比特与运算
⊕:32比特异或运算
¬:32比特非运算
+:mod232算术加运算
≪ k:循环左移k比特运算
←:左向赋值运算符
4.常数与函数
4.1 术语和定义
IV =7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e
4.2 常量
4.3 布尔函数
4.4 置换函数
5 算法描述
5.1 概述
对长度为l(l < 264) 比特的消息m,SM3杂凑算法经过填充和迭代压缩,生成杂凑值,杂凑值长度为256比特。
5.2 填充
假设消息m 的长度为 l 比特。首先将比特“1”添加到消息的末尾,再添加k 个“0”,k是满足l + 1 + k ≡ 448mod512 的最小的非负整数。然后再添加一个64位比特串,该比特串是长度l的二进制表示。填充后的消息m′ 的比特长度为512的倍数。
例如:对消息01100001 01100010 01100011,其长度l=24,经填充得到比特串:
5.3 迭代压缩
5.3.1 迭代过程
将填充后的消息m′按512比特进行分组:m′ = B(0)B(1)· · · B(n-1)
其中n=(l+k+65)/512。 对m′按下列方式迭代:
FOR i=0 TO n-1
V(i+1-1) = CF(V (i), B(i))
ENDFOR
其中CF是压缩函数,V(0)为256比特初始值IV,B(i)为填充后的消息分组,迭代压缩的结果
为V(n)。
5.3.2 消息扩展
将消息分组B(i)按以下方法扩展生成132个字W0, W1, · · · , W67, W′0
, W′1, · · · , W′63,用于压缩函数CF:
a)将消息分组B(i)划分为16个字W0, W1, · · · , W15。
b)FOR j=16 TO 67
Wj ← P1(Wj-16 ⊕ Wj-9 ⊕ (Wj-3≪ 15)) ⊕ (Wj-13 ≪ 7) ⊕ Wj-6
ENDFOR
c)FOR j=0 TO 63
Wj′ = Wj ⊕ Wj+4
ENDFOR
5.3.3 压缩函数
令A,B,C,D,E,F,G,H为字寄存器,SS1,SS2,TT1,TT2为中间变量,压缩函数V i+1 = CF(V (i), B(i)), 0 ≤ i ≤ n-1。计算过程描述如下:
ABCDEFGH ← V (i)
FOR j=0 TO 63
SS1 ← ((A ≪ 12) + E + (Tj ≪ j)) ≪ 7
SS2 ← SS1 ⊕ (A ≪ 12)
TT1 ← FFj (A, B, C) + D + SS2 + Wj′
TT2 ← GGj (E, F, G) + H + SS1 + Wj
D ← C
C ← B ≪ 9
B ← A
A ← TT1
H ← G
G ← F ≪ 19
F ← E E ← P0(TT2)
ENDFOR
V (i+1) ← ABCDEFGH ⊕ V (i)
其中,字的存储为大端(big-endian)格式。
5.4 杂凑值
ABCDEFGH ← V (n)
输出256比特的杂凑值y = ABCDEFGH。
python 源码
IV = [
1937774191, 1226093241, 388252375, 3666478592,
2842636476, 372324522, 3817729613, 2969243214,
]
T_j = [
2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169,
2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169,
2043430169, 2043430169, 2043430169, 2043430169, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042
]
rotl = lambda x, n:((x << n) & 0xffffffff) | ((x >> (32 - n)) & 0xffffffff)
def sm3_ff_j(x, y, z, j):
if 0 <= j and j < 16:
ret = x ^ y ^ z
elif 16 <= j and j < 64:
ret = (x & y) | (x & z) | (y & z)
return ret
def sm3_gg_j(x, y, z, j):
if 0 <= j and j < 16:
ret = x ^ y ^ z
elif 16 <= j and j < 64:
#ret = (X | Y) & ((2 ** 32 - 1 - X) | Z)
ret = (x & y) | ((~ x) & z)
return ret
def sm3_p_0(x):
return x ^ (rotl(x, 9 % 32)) ^ (rotl(x, 17 % 32))
def sm3_p_1(x):
return x ^ (rotl(x, 15 % 32)) ^ (rotl(x, 23 % 32))
def sm3_cf(v_i, b_i):
w = []
for i in range(16):
weight = 0x1000000
data = 0
for k in range(i*4,(i+1)*4):
data = data + b_i[k]*weight
weight = int(weight/0x100)
w.append(data)
for j in range(16, 68):
w.append(0)
w[j] = sm3_p_1(w[j-16] ^ w[j-9] ^ (rotl(w[j-3], 15 % 32))) ^ (rotl(w[j-13], 7 % 32)) ^ w[j-6]
str1 = "%08x" % w[j]
w_1 = []
for j in range(0, 64):
w_1.append(0)
w_1[j] = w[j] ^ w[j+4]
str1 = "%08x" % w_1[j]
a, b, c, d, e, f, g, h = v_i
for j in range(0, 64):
ss_1 = rotl(
((rotl(a, 12 % 32)) +
e +
(rotl(T_j[j], j % 32))) & 0xffffffff, 7 % 32
)
ss_2 = ss_1 ^ (rotl(a, 12 % 32))
tt_1 = (sm3_ff_j(a, b, c, j) + d + ss_2 + w_1[j]) & 0xffffffff
tt_2 = (sm3_gg_j(e, f, g, j) + h + ss_1 + w[j]) & 0xffffffff
d = c
c = rotl(b, 9 % 32)
b = a
a = tt_1
h = g
g = rotl(f, 19 % 32)
f = e
e = sm3_p_0(tt_2)
a, b, c, d, e, f, g, h = map(
lambda x:x & 0xFFFFFFFF ,[a, b, c, d, e, f, g, h])
v_j = [a, b, c, d, e, f, g, h]
return [v_j[i] ^ v_i[i] for i in range(8)]
def sm3_hash(msg):
# print(msg)
len1 = len(msg)
reserve1 = len1 % 64
msg.append(0x80)
reserve1 = reserve1 + 1
# 56-64, add 64 byte
range_end = 56
if reserve1 > range_end:
range_end = range_end + 64
for i in range(reserve1, range_end):
msg.append(0x00)
bit_length = (len1) * 8
bit_length_str = [bit_length % 0x100]
for i in range(7):
bit_length = int(bit_length / 0x100)
bit_length_str.append(bit_length % 0x100)
for i in range(8):
msg.append(bit_length_str[7-i])
group_count = round(len(msg) / 64)
B = []
for i in range(0, group_count):
B.append(msg[i*64:(i+1)*64])
V = []
V.append(IV)
for i in range(0, group_count):
V.append(sm3_cf(V[i], B[i]))
y = V[i+1]
result = ""
for i in y:
result = '%s%08x' % (result, i)
return result
bytes_to_list = lambda data: [i for i in data]
strs = "20210201173824975258"
str_b = bytes(strs, encoding='utf-8')
result = sm3_hash(bytes_to_list(str_b))
print(result) #50f03b05d10fa07f1169aff1d1e119ae3169107035b1abd24f76009ee05a8e2c
直接安装gmssl模块
from gmssl import sm3, func
strs = "20210201173824975258"
str_b = bytes(strs, encoding='utf-8')
result = sm3.sm3_hash(func.bytes_to_list(str_b))
print(result) #50f03b05d10fa07f1169aff1d1e119ae3169107035b1abd24f76009ee05a8e2c