python SM3密碼雜湊演算法
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