生活随笔
收集整理的這篇文章主要介紹了
SM2算法
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
簡述
SM2是非對稱加密算法
它是基于橢圓曲線密碼的公鑰密碼算法標(biāo)準(zhǔn),其秘鑰長度256bit,包含數(shù)字簽名、密鑰交換和公鑰加密,用于替換RSA/DH/ECDSA/ECDH等國際算法。可以滿足電子認(rèn)證服務(wù)系統(tǒng)等應(yīng)用需求,由國家密碼管理局于2010年12月17號發(fā)布。
SM2采用的是ECC 256位的一種,其安全強(qiáng)度比RSA 2048位高,且運(yùn)算速度快于RSA。隨著密碼技術(shù)和計(jì)算技術(shù)的發(fā)展,目前常用的1024位RSA算法面臨嚴(yán)重的安全威脅,我們國家密碼管理部門經(jīng)過研究,決定采用SM2橢圓曲線算法替換RSA算法。SM2算法在安全性、性能上都具有優(yōu)勢。
基礎(chǔ)知識:橢圓曲線知識點(diǎn)、SM3算法
獲取公私鑰:
橢圓曲線方程:y2=x3+ax+bmodpy^2=x^3+ax+b \mod p y 2 = x 3 + a x + b m o d p
確認(rèn)a、b、p,確認(rèn)曲線。確認(rèn)a、b、p,確認(rèn)曲線。 確 認(rèn) a 、 b 、 p , 確 認(rèn) 曲 線 。 選擇一個(gè)點(diǎn)P(xg,yg)為基點(diǎn)。選擇一個(gè)點(diǎn)P(x_g,y_g)為基點(diǎn)。 選 擇 一 個(gè) 點(diǎn) P ( x g ? , y g ? ) 為 基 點(diǎn) 。 對曲線做切線、x對稱點(diǎn)運(yùn)行。次數(shù)為d,運(yùn)算倍點(diǎn)為Q對曲線做切線、x對稱點(diǎn)運(yùn)行。次數(shù)為 d,運(yùn)算倍點(diǎn)為Q 對 曲 線 做 切 線 、 x 對 稱 點(diǎn) 運(yùn) 行 。 次 數(shù) 為 d , 運(yùn) 算 倍 點(diǎn) 為 Q d為私鑰,Q為公鑰d 為私鑰,Q為公鑰 d 為 私 鑰 , Q 為 公 鑰
密鑰對的生成:
產(chǎn)生隨機(jī)整數(shù)d[1,n?2]產(chǎn)生隨機(jī)整數(shù) d [1,n-2] 產(chǎn) 生 隨 機(jī) 整 數(shù) d [ 1 , n ? 2 ] G為基點(diǎn),計(jì)算點(diǎn)P=(xP,yP)=[d]G;G為基點(diǎn),計(jì)算點(diǎn) P=(xP,yP)=[d]G; G 為 基 點(diǎn) , 計(jì) 算 點(diǎn) P = ( x P , y P ) = [ d ] G ; 密鑰對為:(d,P)其中,d為私鑰,P為公鑰密鑰對為: (d,P) 其中,d為私鑰,P為公鑰 密 鑰 對 為 : ( d , P ) 其 中 , d 為 私 鑰 , P 為 公 鑰
一個(gè)很典型的例子:
a
= 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC
b
= 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93
p
= 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF
x_g
= 0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7
y_g
= 0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0
n
= 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123
SM簽名
MM M 為待簽名消息,數(shù)字簽名結(jié)果為(r,s)(r,s) ( r , s ) ,用戶密鑰對(d,P)(d,P) ( d , P ) 。
實(shí)現(xiàn)步驟:
e=hash(M)?獲取消息散列值e=hash(M) \qquad \Rightarrow獲取消息散列值 e = h a s h ( M ) ? 獲 取 消 息 散 列 值 產(chǎn)生隨機(jī)數(shù)k?以便即使是同一個(gè)消息,每次簽名出來的結(jié)果不同。產(chǎn)生隨機(jī)數(shù) k \qquad \Rightarrow以便即使是同一個(gè)消息,每次簽名出來的結(jié)果不同。 產(chǎn) 生 隨 機(jī) 數(shù) k ? 以 便 即 使 是 同 一 個(gè) 消 息 , 每 次 簽 名 出 來 的 結(jié) 果 不 同 。 使用隨機(jī)數(shù),計(jì)算橢圓曲線點(diǎn)(x1,y1)=[k]G使用隨機(jī)數(shù),計(jì)算橢圓曲線點(diǎn)(x_1,y_1)=[k]G 使 用 隨 機(jī) 數(shù) , 計(jì) 算 橢 圓 曲 線 點(diǎn) ( x 1 ? , y 1 ? ) = [ k ] G r=(e+x1)modn?判斷:r=0或者r+k=n,繼續(xù)第2步。r=(e+x1) \mod n \qquad \Rightarrow判斷:r=0 或者 r+k=n, 繼續(xù)第2步。 r = ( e + x 1 ) m o d n ? 判 斷 : r = 0 或 者 r + k = n , 繼 續(xù) 第 2 步 。 s=((1+d)?1?(k?r?d))modn,若s=0,繼續(xù)第2步s= ((1+d)^{-1} * (k-r*d)) \mod n , 若s=0,繼續(xù)第2步 s = ( ( 1 + d ) ? 1 ? ( k ? r ? d ) ) m o d n , 若 s = 0 , 繼 續(xù) 第 2 步 r,s為簽名信息。r,s 為簽名信息。 r , s 為 簽 名 信 息 。
SM驗(yàn)簽
MM M 為明文,(r,s)(r,s) ( r , s ) 為簽名結(jié)果,用戶公鑰PP P
實(shí)現(xiàn)步驟:
e=hash(M)e=hash(M) e = h a s h ( M ) t=(r+s)modnt=(r+s) \mod n t = ( r + s ) m o d n (x,y)=[s]G+[t]P(x,y)=[s]G + [t]P ( x , y ) = [ s ] G + [ t ] P R=(e+x)modnR=(e+x)\mod n R = ( e + x ) m o d n 計(jì)算R是否等于r計(jì)算R是否等于r 計(jì) 算 R 是 否 等 于 r
[s]G[s]G [ s ] G +[t]P[t]P [ t ] P 的結(jié)果可以推導(dǎo)出等于[k]G[k]G [ k ] G 。
驗(yàn)證原理
[s]G+[t]P??=sG+(r+s)P[s]G+[t]P??=sG+(r+s)P [ s ] G + [ t ] P ? ? = s G + ( r + s ) P =sG+(r+s)dG\qquad \qquad \quad=sG+(r+s)dG = s G + ( r + s ) d G =sG+sd?G+rd?G\qquad \qquad \quad=sG+sd?G+rd?G = s G + s d ? G + r d ? G =(1+d?)sG+rd?G\qquad \qquad \quad=(1+d?)sG+rd?G = ( 1 + d ? ) s G + r d ? G =(1+d?)(1+d)?1(k?rd)G+rdG\qquad \qquad \quad=(1+d?)(1+d)^{?1}(k?rd)G+rdG = ( 1 + d ? ) ( 1 + d ) ? 1 ( k ? r d ) G + r d G =(k?rd?)G+rd?G\qquad \qquad \quad=(k?rd?)G+rd?G = ( k ? r d ? ) G + r d ? G =kG?rdG+rdG\qquad \qquad \quad=kG?rdG+rdG = k G ? r d G + r d G =kG=(x1?,y1?)?\qquad \qquad \quad=kG=(x1?,y1?)? = k G = ( x 1 ? , y 1 ? ) ?
SM加密
M為明文字符串
獲取隨機(jī)數(shù)k獲取隨機(jī)數(shù) k 獲 取 隨 機(jī) 數(shù) k (x1,y1)=[k]G(x1, y1) = [k]G ( x 1 , y 1 ) = [ k ] G S=[h]P?h為余因子S=[h]P \qquad \Rightarrow h為余因子 S = [ h ] P ? h 為 余 因 子 C1=(x2,y2)=[k]PC1=(x2,y2)= [k]P C 1 = ( x 2 , y 2 ) = [ k ] P t=KDF(x2∥y2,klen)?klen為M的長度。KDF是sm2的密鑰派生函數(shù)t=KDF(x2\parallel y2,klen) \qquad \Rightarrow klen為M的長度。KDF是sm2的密鑰派生函數(shù) t = K D F ( x 2 ∥ y 2 , k l e n ) ? k l e n 為 M 的 長 度 。 K D F 是 s m 2 的 密 鑰 派 生 函 數(shù) C2=M+tC2 = M+t C 2 = M + t C3=Hash(x2∥M∥y2)C3 = Hash(x2\parallel M\parallel y2) C 3 = H a s h ( x 2 ∥ M ∥ y 2 ) C=C1∥C2∥C3C = C1\parallel C2\parallel C3 C = C 1 ∥ C 2 ∥ C 3
SM解密
C為密文字符串,klen為密文中C2的長度
C1=C里面獲取,驗(yàn)證C1是否滿足橢圓曲線。?C2長度確定,可以獲取C1內(nèi)容。C1 = C里面獲取 ,驗(yàn)證C1是否滿足橢圓曲線。 \qquad \Rightarrow C2長度確定,可以獲取C1內(nèi)容。 C 1 = C 里 面 獲 取 , 驗(yàn) 證 C 1 是 否 滿 足 橢 圓 曲 線 。 ? C 2 長 度 確 定 , 可 以 獲 取 C 1 內(nèi) 容 。 S=[h]C1,S為無窮點(diǎn),退出。S=[h]C1,S為無窮點(diǎn),退出。 S = [ h ] C 1 , S 為 無 窮 點(diǎn) , 退 出 。 (x2,y2)=[d]C1(x2,y2)=[d]C1 ( x 2 , y 2 ) = [ d ] C 1 t=KDF(m2∥y2,klen)t=KDF(m2\parallel y2,klen) t = K D F ( m 2 ∥ y 2 , k l e n ) M~=C2+t\widetilde{M} = C2+t M = C 2 + t u=Hash(x2∥M~∥y2),u?==C3u=Hash(x2\parallel \widetilde{M} \parallel y2), u ?== C3 u = H a s h ( x 2 ∥ M ∥ y 2 ) , u ? = = C 3 M~為明文\widetilde{M}為明文 M 為 明 文
代碼實(shí)現(xiàn)
首先,需要導(dǎo)入包gmssl
pip install gmssl
生成公私鑰算法 sm2utils.py
from random
import SystemRandom
class CurveFp : def __init__ ( self
, A
, B
, P
, N
, Gx
, Gy
, name
) : self
. A
= Aself
. B
= Bself
. P
= Pself
. N
= Nself
. Gx
= Gxself
. Gy
= Gyself
. name
= namesm2p256v1
= CurveFp
( name
= "sm2p256v1" , A
= 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC , B
= 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93 , P
= 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF , N
= 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123 , Gx
= 0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7 , Gy
= 0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0
) def multiply ( a
, n
, N
, A
, P
) : return fromJacobian
( jacobianMultiply
( toJacobian
( a
) , n
, N
, A
, P
) , P
) def add ( a
, b
, A
, P
) : return fromJacobian
( jacobianAdd
( toJacobian
( a
) , toJacobian
( b
) , A
, P
) , P
) def inv ( a
, n
) : if a
== 0 : return 0 lm
, hm
= 1 , 0 low
, high
= a
% n
, n
while low
> 1 : r
= high
// lownm
, new
= hm
- lm
* r
, high
- low
* rlm
, low
, hm
, high
= nm
, new
, lm
, low
return lm
% n
def toJacobian ( Xp_Yp
) : Xp
, Yp
= Xp_Yp
return ( Xp
, Yp
, 1 ) def fromJacobian ( Xp_Yp_Zp
, P
) : Xp
, Yp
, Zp
= Xp_Yp_Zpz
= inv
( Zp
, P
) return ( ( Xp
* z
** 2 ) % P
, ( Yp
* z
** 3 ) % P
) def jacobianDouble ( Xp_Yp_Zp
, A
, P
) : Xp
, Yp
, Zp
= Xp_Yp_Zp
if not Yp
: return ( 0 , 0 , 0 ) ysq
= ( Yp
** 2 ) % PS
= ( 4 * Xp
* ysq
) % PM
= ( 3 * Xp
** 2 + A
* Zp
** 4 ) % Pnx
= ( M
** 2 - 2 * S
) % Pny
= ( M
* ( S
- nx
) - 8 * ysq
** 2 ) % Pnz
= ( 2 * Yp
* Zp
) % P
return ( nx
, ny
, nz
) def jacobianAdd ( Xp_Yp_Zp
, Xq_Yq_Zq
, A
, P
) : Xp
, Yp
, Zp
= Xp_Yp_ZpXq
, Yq
, Zq
= Xq_Yq_Zq
if not Yp
: return ( Xq
, Yq
, Zq
) if not Yq
: return ( Xp
, Yp
, Zp
) U1
= ( Xp
* Zq
** 2 ) % PU2
= ( Xq
* Zp
** 2 ) % PS1
= ( Yp
* Zq
** 3 ) % PS2
= ( Yq
* Zp
** 3 ) % P
if U1
== U2
: if S1
!= S2
: return ( 0 , 0 , 1 ) return jacobianDouble
( ( Xp
, Yp
, Zp
) , A
, P
) H
= U2
- U1R
= S2
- S1H2
= ( H
* H
) % PH3
= ( H
* H2
) % PU1H2
= ( U1
* H2
) % Pnx
= ( R
** 2 - H3
- 2 * U1H2
) % Pny
= ( R
* ( U1H2
- nx
) - S1
* H3
) % Pnz
= ( H
* Zp
* Zq
) % P
return ( nx
, ny
, nz
) def jacobianMultiply ( Xp_Yp_Zp
, n
, N
, A
, P
) : Xp
, Yp
, Zp
= Xp_Yp_Zp
if Yp
== 0 or n
== 0 : return ( 0 , 0 , 1 ) if n
== 1 : return ( Xp
, Yp
, Zp
) if n
< 0 or n
>= N
: return jacobianMultiply
( ( Xp
, Yp
, Zp
) , n
% N
, N
, A
, P
) if ( n
% 2 ) == 0 : return jacobianDouble
( jacobianMultiply
( ( Xp
, Yp
, Zp
) , n
// 2 , N
, A
, P
) , A
, P
) if ( n
% 2 ) == 1 : return jacobianAdd
( jacobianDouble
( jacobianMultiply
( ( Xp
, Yp
, Zp
) , n
// 2 , N
, A
, P
) , A
, P
) , ( Xp
, Yp
, Zp
) , A
, P
) class PrivateKey : def __init__ ( self
, curve
= sm2p256v1
, secret
= None ) : self
. curve
= curveself
. secret
= secret
or SystemRandom
( ) . randrange
( 1 , curve
. N
) def publicKey ( self
) : curve
= self
. curvexPublicKey
, yPublicKey
= multiply
( ( curve
. Gx
, curve
. Gy
) , self
. secret
, A
= curve
. A
, P
= curve
. P
, N
= curve
. N
) return PublicKey
( xPublicKey
, yPublicKey
, curve
) def toString ( self
) : return "{}" . format ( str ( hex ( self
. secret
) ) [ 2 : ] . zfill
( 64 ) ) class PublicKey : def __init__ ( self
, x
, y
, curve
) : self
. x
= xself
. y
= yself
. curve
= curve
def toString ( self
, compressed
= True ) : return { True : str ( hex ( self
. x
) ) [ 2 : ] , False : "{}{}" . format ( str ( hex ( self
. x
) ) [ 2 : ] . zfill
( 64 ) , str ( hex ( self
. y
) ) [ 2 : ] . zfill
( 64 ) ) } . get
( compressed
) if __name__
== "__main__" : priKey
= PrivateKey
( ) pubKey
= priKey
. publicKey
( ) print ( priKey
. toString
( ) ) print ( pubKey
. toString
( compressed
= False ) )
加解密算法 封裝類 sm2encryp.py
from gmssl
import sm2
from base64
import b64encode
, b64decode
SM2_PRIVATE_KEY
= '00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5'
SM2_PUBLIC_KEY
= 'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207' sm2_crypt
= sm2
. CryptSM2
( public_key
= SM2_PUBLIC_KEY
, private_key
= SM2_PRIVATE_KEY
) class sm2Encrypt : def encrypt ( self
, info
) : encode_info
= sm2_crypt
. encrypt
( info
. encode
( encoding
= "utf-8" ) ) encode_info
= b64encode
( encode_info
) . decode
( ) return encode_info
def decrypt ( self
, info
) : decode_info
= b64decode
( info
. encode
( ) ) decode_info
= sm2_crypt
. decrypt
( decode_info
) . decode
( encoding
= "utf-8" ) return decode_info
if __name__
== "__main__" : origin_pwd
= '123456' sm2
= sm2Encrypt
( ) encrypy_pwd
= sm2
. encrypt
( origin_pwd
) print ( encrypy_pwd
) decrypt_pwd
= sm2
. decrypt
( encrypy_pwd
) print ( decrypt_pwd
)
當(dāng)跟sm2encryp.py在一個(gè)文件夾是可以直接引用它
from sm2encryp
import sm2Encrypt
pass_encrypt
= sm2Encrypt
( )
pwd
= pass_encrypt
. decrypt
( "H24OlVZgSTtevCW138O+C5PlZp8OiD920JnpVr7r9ndkGBWFZUVDD48iIVrZRnamgosV5910m9k0438WpIyi0guEt8F5inG7Y5A51whRfdPZ+qdvWVQxI857CBEzkb3h1bMp1ETQ" )
print ( pwd
)
參考
https://www.jianshu.com/p/efc43060e0aa https://blog.csdn.net/u013137970/article/details/84573200 https://blog.csdn.net/u014651560/article/details/113744296
總結(jié)
以上是生活随笔 為你收集整理的SM2算法 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。