日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

SM2算法

發(fā)布時間:2025/3/21 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SM2算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

簡述

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ù)和計算技術(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 py2=x3+ax+bmodp

  • 確認(rèn)a、b、p,確認(rèn)曲線。確認(rèn)a、b、p,確認(rèn)曲線。認(rèn)abp認(rèn)
  • 選擇一個點(diǎn)P(xg,yg)為基點(diǎn)。選擇一個點(diǎn)P(x_g,y_g)為基點(diǎn)。點(diǎn)P(xg?,yg?)點(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)為Qx點(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),計算點(diǎn)P=(xP,yP)=[d]G;G為基點(diǎn),計算點(diǎn) P=(xP,yP)=[d]G;G點(diǎn)點(diǎn)P=(xP,yP)=[d]G;
  • 密鑰對為:(d,P)其中,d為私鑰,P為公鑰密鑰對為: (d,P) 其中,d為私鑰,P為公鑰:(d,P)dP
  • 一個很典型的例子:

    a = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC b = 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93 p = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF x_g = 0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7 y_g = 0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0 n = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123

    SM簽名

    MMM為待簽名消息,數(shù)字簽名結(jié)果為(r,s)(r,s)(r,s) ,用戶密鑰對(d,P)(d,P)(d,P)

    實現(xiàn)步驟:

  • e=hash(M)?獲取消息散列值e=hash(M) \qquad \Rightarrow獲取消息散列值e=hash(M)?
  • 產(chǎn)生隨機(jī)數(shù)k?以便即使是同一個消息,每次簽名出來的結(jié)果不同。產(chǎn)生隨機(jī)數(shù) k \qquad \Rightarrow以便即使是同一個消息,每次簽名出來的結(jié)果不同。產(chǎn)機(jī)數(shù)k?便使結(jié)
  • 使用隨機(jī)數(shù),計算橢圓曲線點(diǎn)(x1,y1)=[k]G使用隨機(jī)數(shù),計算橢圓曲線點(diǎn)(x_1,y_1)=[k]G使機(jī)數(shù)點(diǎn)(x1?,y1?)=[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+x1)modn?r=0r+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))modn,s=0續(xù)2
  • r,s為簽名信息。r,s 為簽名信息。r,s
  • SM驗簽

    MMM為明文,(r,s)(r,s)(r,s)為簽名結(jié)果,用戶公鑰PPP

    實現(xiàn)步驟:

  • e=hash(M)e=hash(M)e=hash(M)
  • t=(r+s)modnt=(r+s) \mod nt=(r+s)modn
  • (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 nR=(e+x)modn
  • 計算R是否等于r計算R是否等于rRr
  • [s]G[s]G[s]G +[t]P[t]P[t]P的結(jié)果可以推導(dǎo)出等于[k]G[k]G[k]G

    驗證原理

    [s]G+[t]P??=sG+(r+s)P[s]G+[t]P??=sG+(r+s)P[s]G+[t]P??=sG+(r+s)P
    =sG+(r+s)dG\qquad \qquad \quad=sG+(r+s)dG=sG+(r+s)dG
    =sG+sd?G+rd?G\qquad \qquad \quad=sG+sd?G+rd?G=sG+sd?G+rd?G
    =(1+d?)sG+rd?G\qquad \qquad \quad=(1+d?)sG+rd?G=(1+d?)sG+rd?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?rd)G+rdG
    =(k?rd?)G+rd?G\qquad \qquad \quad=(k?rd?)G+rd?G=(k?rd?)G+rd?G
    =kG?rdG+rdG\qquad \qquad \quad=kG?rdG+rdG=kG?rdG+rdG
    =kG=(x1?,y1?)?\qquad \qquad \quad=kG=(x1?,y1?)?=kG=(x1?,y1?)?

    SM加密

    M為明文字符串

  • 獲取隨機(jī)數(shù)k獲取隨機(jī)數(shù) k機(jī)數(shù)k
  • (x1,y1)=[k]G(x1, y1) = [k]G(x1,y1)=[k]G
  • S=[h]P?h為余因子S=[h]P \qquad \Rightarrow h為余因子S=[h]P?h
  • C1=(x2,y2)=[k]PC1=(x2,y2)= [k]PC1=(x2,y2)=[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=KDF(x2y2,klen)?klenMKDFsm2數(shù)
  • C2=M+tC2 = M+tC2=M+t
  • C3=Hash(x2∥M∥y2)C3 = Hash(x2\parallel M\parallel y2)C3=Hash(x2My2)
  • C=C1∥C2∥C3C = C1\parallel C2\parallel C3C=C1C2C3
  • SM解密

    C為密文字符串,klen為密文中C2的長度

  • C1=C里面獲取,驗證C1是否滿足橢圓曲線。?C2長度確定,可以獲取C1內(nèi)容。C1 = C里面獲取 ,驗證C1是否滿足橢圓曲線。 \qquad \Rightarrow C2長度確定,可以獲取C1內(nèi)容。C1=CC1滿?C2C1內(nèi)
  • S=[h]C1,S為無窮點(diǎn),退出。S=[h]C1,S為無窮點(diǎn),退出。S=[h]C1S點(diǎn)退
  • (x2,y2)=[d]C1(x2,y2)=[d]C1(x2,y2)=[d]C1
  • t=KDF(m2∥y2,klen)t=KDF(m2\parallel y2,klen)t=KDF(m2y2,klen)
  • M~=C2+t\widetilde{M} = C2+tM=C2+t
  • u=Hash(x2∥M~∥y2),u?==C3u=Hash(x2\parallel \widetilde{M} \parallel y2), u ?== C3u=Hash(x2My2),u?==C3
  • M~為明文\widetilde{M}為明文M
  • 代碼實現(xiàn)

    首先,需要導(dǎo)入包gmssl

    pip install gmssl

    生成公私鑰算法
    sm2utils.py

    from random import SystemRandomclass 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 0lm, hm = 1, 0low, high = a % n, nwhile low > 1:r = high//lownm, new = hm-lm*r, high-low*rlm, low, hm, high = nm, new, lm, lowreturn lm % ndef toJacobian(Xp_Yp):Xp, Yp = Xp_Ypreturn (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_Zpif 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) % Preturn (nx, ny, nz)def jacobianAdd(Xp_Yp_Zp, Xq_Yq_Zq, A, P):Xp, Yp, Zp = Xp_Yp_ZpXq, Yq, Zq = Xq_Yq_Zqif 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) % Pif 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) % Preturn (nx, ny, nz)def jacobianMultiply(Xp_Yp_Zp, n, N, A, P):Xp, Yp, Zp = Xp_Yp_Zpif 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 = curvedef 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的公私鑰 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() # 將二進(jìn)制bytes通過base64編碼return encode_info# 解密def decrypt(self, info):decode_info = b64decode(info.encode()) # 通過base64解碼成二進(jìn)制bytesdecode_info = sm2_crypt.decrypt(decode_info).decode(encoding="utf-8")return decode_infoif __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在一個文件夾是可以直接引用它

    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)容還不錯,歡迎將生活随笔推薦給好友。