生活随笔
收集整理的這篇文章主要介紹了
python实现sm3算法
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
背景
sm3密碼雜湊算法是中國(guó)國(guó)家密碼管理局頒布的一種密碼Hash函數(shù),它與sm4分組密碼、sm2橢圓曲線公鑰密鑰一起都是中國(guó)商用密碼的重要組成部分。
SM3密碼Hash算法的輸入數(shù)據(jù)長(zhǎng)度為 l 比特,1≤ l ≤ 264-1,輸出Hash值的長(zhǎng)度為256比特。
1.常量與函數(shù)
SM3密碼Hash函數(shù)使用以下常數(shù)與函數(shù)。
(1)常量
初始值IV=7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e
(2)函數(shù)
布爾函數(shù):
式中X、Y、Z為32位字。
def FF_j(X
,Y
,Z
,j
):if j
<=15:a
= or_16
(X
,Y
)a
= or_16
(a
,Z
)else:a
= and_Cal
(X
,Y
)b
= and_Cal
(X
,Z
)c
= and_Cal
(Y
,Z
)a
= or_Cal
(a
,b
)a
= or_Cal
(a
,c
)return a
def GG_j(X
, Y
, Z
, j
):if j
<= 15:a
= or_16
(X
, Y
)a
= or_16
(a
, Z
)else:a
= and_Cal
(X
,Y
)b
= qufan
(X
)b
= and_Cal
(b
,Z
)a
= or_Cal
(a
,b
)return a
置換函數(shù):
P0(X) = X ? (X<<<9)?(X<<<17)
P1(X) = X ? (X<<<15)?(X<<<23)
式中X為32位字,符號(hào)a<<<n表示把a(bǔ)循環(huán)左移n位。
def Replace_P1(X
):X_15
= Cyc_shift
(X
,15) X_23
= Cyc_shift
(X
,23)a
= or_16
(X
,X_15
)a
= or_16
(a
,X_23
)return a
def Replace_P0(X
):X_9
= Cyc_shift
(X
,9)X_17
= Cyc_shift
(X
,17)a
= or_16
(X
,X_9
)a
= or_16
(a
,X_17
)return a
2.算法描述
SM3密碼Hash算法對(duì)數(shù)據(jù)進(jìn)行填充和迭代壓縮后生成Hash值。
(1)填充
對(duì)數(shù)據(jù)進(jìn)行填充的目的是使填充后的數(shù)據(jù)長(zhǎng)度為512的整數(shù)倍。后面進(jìn)行的迭代壓縮式對(duì)512位的數(shù)據(jù)塊進(jìn)行的,如果數(shù)據(jù)的長(zhǎng)度不是512的整數(shù)倍,最后一塊數(shù)據(jù)塊將是短塊,這將無法處理。
假設(shè)消息m的長(zhǎng)度為l 比特。首先將比特“1”添加到消息m的末尾,再添加k個(gè)“0”。其中,k 是滿足 l+1+k=448 mod 512 的最小非負(fù)整數(shù)。然后再添加一個(gè)64位比特串,該比特串是長(zhǎng)度l 的二進(jìn)制表示。填充后的消息m的比特串長(zhǎng)度一定是512的倍數(shù)。
例如,對(duì)消息 01100001 01100010 01100011,其長(zhǎng)度為l=24,經(jīng)填充后得到比特串:
def filling(m
):length_b
= len(m
)*4b
= mb
= b
+ '8'c
= len(b
)%128c
= 112 - cd
= '0'*cb
= b
+ dlength_m
= '{:016x}'.format(length_b
)b
= b
+ length_m
return b
(2)迭代壓縮
將填充后的信息m’ 按512比特進(jìn)行分組:m’ = B(0) B(1) … B(n-1) ,其中 n = (l+k+65)/512
對(duì)m’ 按下列方式迭代壓縮:
FOR i=0 TO n-1
V(i+1) = CF(V(i),B(i) )
ENDFOR
其中:CF是壓縮函數(shù);V(0) 為256比特初始值IV;B(i) 為填充后的消息分組;迭代壓縮的結(jié)果為V(n) 即為消息m的Hash值。
(3)消息擴(kuò)展
在對(duì)消息分組B(i) 進(jìn)行迭代壓縮之前,首先對(duì)其進(jìn)行消息擴(kuò)展。進(jìn)行消息擴(kuò)展有兩個(gè)目的。目的之一是將16個(gè)字的消息分組B(i) 擴(kuò)展成下式(1)的132個(gè)字,供壓縮函數(shù)CF使用。目的之二是通過消息擴(kuò)展把原消息位打亂,隱蔽了原信息之間的關(guān)聯(lián),增強(qiáng)了Hash函數(shù)的安全性。
W0,W1,...W67,W0′,W1′,...W63′??????(1)W_0,W_1,... W_{67},W'_0,W'_1,... W'_{63} ------(1) W0?,W1?,...W67?,W0′?,W1′?,...W63′???????(1)
消息擴(kuò)展的步驟如下:
消息分組B(i) 經(jīng)消息擴(kuò)展后就可以進(jìn)行迭代壓縮了。
def expand(m
,n
):B
= fenzu
(m
)W
= ['0' for i
in range(68)]W_0
= ['0' for i
in range(64)]for i
in range(int(len(B
[n
])/8)):w
= B
[n
][i
*8:(i
+1)*8]W
[i
] = w
for j
in range(16,68):a
= or_16
(W
[j
-16],W
[j
-9])W_j_3
= Cyc_shift
(W
[j
-3],15)a
= or_16
(a
,W_j_3
)a
= Replace_P1
(a
)W_j_13
=Cyc_shift
(W
[j
-13],7)a
= or_16
(a
,W_j_13
)a
= or_16
(a
,W
[j
-6])W
[j
]=a
for j
in range(64):W_0
[j
]=or_16
(W
[j
],W
[j
+4])return W
,W_0
(4)壓縮函數(shù)
令A(yù),B,C,D,E,F,G,H為字寄存器,SS1,SS2,TT1,TT2為中間變量,壓縮函數(shù)V(i+1) =CF(V(i) ,B(i) ),0 ≤ i ≤ n-1 計(jì)算過程描述如下,
其中壓縮函數(shù)中的+運(yùn)算為mod 232 算術(shù)加運(yùn)算,字的存儲(chǔ)為大端格式。
由SM3的壓縮函數(shù)的算法可以看出,壓縮函數(shù)進(jìn)行了64次循環(huán)迭代。SM3的壓縮函數(shù)CF把每一個(gè)512位的消息分組 B(i) 壓縮成256位。經(jīng)過個(gè)數(shù)據(jù)分組之間的迭代處理后把 l 位的信息壓縮成256位的hash值。其中布爾函數(shù)FFj(X,Y,Z)和GGj(X,Y,Z)是非線性函數(shù),經(jīng)過循環(huán)迭代后提供混淆作用。置換函數(shù)P0(X)和P1(X)是線性函數(shù),經(jīng)過循環(huán)迭代后提供擴(kuò)散作用,確保算法的安全性。
def CF(m
,n
,k
):w
= expand
(m
, n
)W
= w
[0]W_0
= w
[1]A
=V
[k
][0:8]B
=V
[k
][8:16]C
=V
[k
][16:24]D
=V
[k
][24:32]E
=V
[k
][32:40]F
=V
[k
][40:48]G
=V
[k
][48:56]H
=V
[k
][56:64]all=''for j
in range(64):b
= a
= Cyc_shift
(A
,12)T
= T_j
(j
)T
= Cyc_shift
(T
,j
)a
= add
(a
,E
)a
= add
(a
,T
)SS1
= Cyc_shift
(a
,7)SS2
= or_16
(SS1
,b
)b
= FF_j
(A
,B
,C
,j
)b
= add
(b
,D
)b
= add
(b
,SS2
)TT1
= add
(b
,W_0
[j
]) b
= GG_j
(E
,F
,G
,j
)b
= add
(b
, H
)b
= add
(b
, SS1
)TT2
= add
(b
, W
[j
]) D
= CC
= Cyc_shift
(B
,9)B
= AA
= TT1H
= GG
= Cyc_shift
(F
,19)F
= EE
= Replace_P0
(TT2
) all = A
+B
+C
+D
+E
+F
+G
+HV
[k
+1]=or_16
(V
[k
],all)
(5)雜湊值
ABCDEFGH←V(n)ABCDEFGH ←V^{(n)} ABCDEFGH←V(n)
輸出256比特的雜湊值 y = ABCDEFGH。處理過程如下:
實(shí)現(xiàn)示例:
512比特消息:
61626364 61626364 61626364 61626364 61626364 61626364 61626364 61626364
61626364 61626364 61626364 61626364 61626364 61626364 61626364 61626364
填充后消息:
61626364 61626364 61626364 61626364 61626364 61626364 61626364 61626364
61626364 61626364 61626364 61626364 61626364 61626364 61626364 61626364
80000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
80000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
雜湊值:
debe9ff9 2275b8a1 38604889 c18e5a4d 6fdb70e5 387e5765 293dcba3 9c0c5732
全部代碼:sm3.py
m
='61626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364'
IV
='7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e'
def filling(m
):length_b
= len(m
)*4b
= mb
= b
+ '8'c
= len(b
)%128c
= 112 - cd
= '0'*cb
= b
+ dlength_m
= '{:016x}'.format(length_b
)b
= b
+ length_m
return b
def fenzu(m
):m
= filling
(m
)len_m
= len(m
)/128m_list
= []for i
in range(int(len_m
)):a
= m
[0+128*i
:+128*(i
+1)]m_list
.append
(a
)return m_list
def expand(m
,n
):B
= fenzu
(m
)W
= ['0' for i
in range(68)]W_0
= ['0' for i
in range(64)]for i
in range(int(len(B
[n
])/8)):w
= B
[n
][i
*8:(i
+1)*8]W
[i
] = w
for j
in range(16,68):a
= or_16
(W
[j
-16],W
[j
-9])W_j_3
= Cyc_shift
(W
[j
-3],15)a
= or_16
(a
,W_j_3
)a
= Replace_P1
(a
)W_j_13
=Cyc_shift
(W
[j
-13],7)a
= or_16
(a
,W_j_13
)a
= or_16
(a
,W
[j
-6])W
[j
]=a
for j
in range(64):W_0
[j
]=or_16
(W
[j
],W
[j
+4])return W
,W_0
def Replace_P1(X
):X_15
= Cyc_shift
(X
,15) X_23
= Cyc_shift
(X
,23)a
= or_16
(X
,X_15
)a
= or_16
(a
,X_23
)return a
def Replace_P0(X
):X_9
= Cyc_shift
(X
,9)X_17
= Cyc_shift
(X
,17)a
= or_16
(X
,X_9
)a
= or_16
(a
,X_17
)return a
def or_16(A
,B
):A
= int(A
,16)B
= int(B
,16)C
= A
^ BC
= '{:08x}'.format(C
)return C
def Cyc_shift(W
,n
):a
= int(W
,16)a
= '{:032b}'.format(a
)while n
>=32:n
=n
-32a
= a
[n
:] + a
[:n
]a
= int(a
,2)a
= '{:08x}'.format(a
)return a
def T_j(j
):if j
<=15:T_j
='79cc4519'else:T_j
='7a879d8a'return T_j
def add(x
,y
):x
= int(x
,16)x
= '{:032b}'.format(x
)x
= list(x
)y
= int(y
, 16)y
= '{:032b}'.format(y
)y
= list(y
)a
= [0 for _
in range(32)]carry
= 0for i
in range(32):m
= int(x
[31-i
])+int(y
[31-i
])+carry
if m
>=2:d
=m
-2a
[31-i
]=str(d
)carry
=1else:carry
=0d
=ma
[31 - i
] = str(d
)b
=''.join
(a
)b
=int(b
,2)b
='{:08x}'.format(b
)return b
def FF_j(X
,Y
,Z
,j
):if j
<=15:a
= or_16
(X
,Y
)a
= or_16
(a
,Z
)else:a
= and_Cal
(X
,Y
)b
= and_Cal
(X
,Z
)c
= and_Cal
(Y
,Z
)a
= or_Cal
(a
,b
)a
= or_Cal
(a
,c
)return a
def GG_j(X
, Y
, Z
, j
):if j
<= 15:a
= or_16
(X
, Y
)a
= or_16
(a
, Z
)else:a
= and_Cal
(X
,Y
)b
= qufan
(X
)b
= and_Cal
(b
,Z
)a
= or_Cal
(a
,b
)return a
def and_Cal(a
,b
):a
= int(a
,16)b
= int(b
,16)a_b
= a
& ba_b
= '{:08x}'.format(a_b
)return a_b
def or_Cal(a
,b
):a
= int(a
, 16)b
= int(b
, 16)a_b
= a
| ba_b
= '{:08x}'.format(a_b
)return a_b
def qufan(A
):A
= int(A
,16)A
= '{:032b}'.format(A
)A
= list(A
)for i
in range(32):if A
[i
]=='0':A
[i
]='1'else:A
[i
]='0'A
= ''.join
(A
)A
= int(A
,2)A
= '{:08x}'.format(A
)return A
m_list
= fenzu
(m
)
m_len
= len(m_list
)
V
= ['0' for i
in range(m_len
+1)]
V
[0]=IV
def CF(m
,n
,k
):w
= expand
(m
, n
)W
= w
[0]W_0
= w
[1]A
=V
[k
][0:8]B
=V
[k
][8:16]C
=V
[k
][16:24]D
=V
[k
][24:32]E
=V
[k
][32:40]F
=V
[k
][40:48]G
=V
[k
][48:56]H
=V
[k
][56:64]all=''for j
in range(64):b
= a
= Cyc_shift
(A
,12)T
= T_j
(j
)T
= Cyc_shift
(T
,j
)a
= add
(a
,E
)a
= add
(a
,T
)SS1
= Cyc_shift
(a
,7)SS2
= or_16
(SS1
,b
)b
= FF_j
(A
,B
,C
,j
)b
= add
(b
,D
)b
= add
(b
,SS2
)TT1
= add
(b
,W_0
[j
]) b
= GG_j
(E
,F
,G
,j
)b
= add
(b
, H
)b
= add
(b
, SS1
)TT2
= add
(b
, W
[j
]) D
= CC
= Cyc_shift
(B
,9)B
= AA
= TT1H
= GG
= Cyc_shift
(F
,19)F
= EE
= Replace_P0
(TT2
) all = A
+B
+C
+D
+E
+F
+G
+HV
[k
+1]=or_16
(V
[k
],all)
def hash(m
=m
):for i
in range(m_len
):v_n
=CF
(m
,i
,i
)print(V
[-1])return V
[-1]
hash()
注意:循環(huán)移位以字(32bit)處理,所以要模32后再移位,否則壓縮函數(shù)在Tj<<<j時(shí)后續(xù)會(huì)出錯(cuò)。
總結(jié)
以上是生活随笔為你收集整理的python实现sm3算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。