国密sm2与sm4加密解密教程

国密sm2与sm4加密解密教程

一、加密过程

安装

pip install

1.1 导包

import base64
from gmssl import sm2,func
from gmssl.sm4 import  CryptSM4, SM4_ENCRYPT, SM4_DECRYPT
  • 其中func用来生成随机数,
  • CryptSM4用来创建sm4对象,
  • SM4_ENCRYPT加密时候sm4的参数,
  • SM4_DECRYPT解密时候sm4的参数

1.2 公私钥生成

国密的公私钥格式有规定,gmssl(python)没有生成工具,gmssl(c)、java跟openSSL,以及支付宝开放平台助手生成的公私钥带入后虽然可以加密解密,但是解密结果是错误的.故自己写一个公私钥生成代码,sm2utils.py.文件内容放最后.如下为生成的公私钥:

private_key= "228a9707053e1b333fb8cb839567a9db4ca1cf5381e9a6a539774e6c3563cdfa"
public_key="893cb9392dabd2fac095f657a7e0bc308e32f4b79380d478547f57123dccb3bc4a3a2d009f5826b6624c99dd41baf470a8baf46722f2d36b1d26f19af112c5cd"

1.3 创建sm4Key和sm4对象

sm4Key_str = func.random_hex(16)    # 随机产生16位 'a2bc65bca8e41795'
sm4Key = bytes(sm4Key_str,encoding='utf-8') # 字符串转bytes
sm4_crypt =CryptSM4()   # 初始化CryptSM4
sm4_crypt.set_key(sm4Key,mode=SM4_ENCRYPT)  # 初始化key到CryptSM4 这里传的是SM_DECRYPT

1.4 sm4对象对数据进行加密

data = [1,2,3,4,5,6,6,7]
data= str(data).encode("utf-8")  # 列表转字符串转bytes
encryptData = sm4_crypt.crypt_ecb(data)   #对数据(bytes)加密 两种方式crypt_ecb跟crypt_cbc
encryptData= base64.b64encode(encryptData) #bytes 转base64
encryptData = encryptData.decode("utf-8")  # 由于转为base64,还是bytes,json不支持,故转为str

1.5 创建sm2对象(附公钥),对sm4Key进行加密

sm2_crypt =sm2.CryptSM2(private_key=None,public_key=public_key)   # 附公钥
encryptKey = sm2_crypt.encrypt(sm4Key)   # 对sm4Key(bytes) 进行加密,返回bytes
encryptKey =base64.b64encode(encryptKey) #bytes 转base64
encryptKey = encryptKey.decode("utf-8")  # 由于转为base64,还是bytes,json不支持,故转为str

1.6 sm2(附私钥)对sm4Key签名

sm2_crypt_s =sm2.CryptSM2(private_key=private_key,public_key=None)  #私钥签名, 公钥验证
random_hex_str = func.random_hex(sm2_crypt.para_len)   # para_len为64, 生成64位随机字符串
sign = sm2_crypt_s.sign(sm4Key,random_hex_str)  # 签名需要用私钥 , sign为字符串格式
sign = base64.b64encode(bytes(sign,encoding='utf-8')) # 字符串转base64 
sign = sign.decode("utf-8") # bytes转字符串

1.7 返回结果

result = {"sign":sign,"encryptKey":encryptKey,"encryptData":encryptData}

二、解密

sign = base64.b64decode(result['sign'])
encryptKey =base64.b64decode(result["encryptKey"])
encryptData = base64.b64decode(result["encryptData"])

2.1 sm2(附私钥)解密sm4Key

sm2_crypt_r =sm2.CryptSM2(private_key=private_key,public_key=None)   
sm4Key_r = sm2_crypt_r.decrypt(encryptKey)  # 解密, 返回bytes
# assert sm4Key_r==sm4Key # 开发者验证, 工程中无法使用

2.2 公钥签名验证

sm2_crypt_sr =sm2.CryptSM2(private_key=None,public_key=public_key)
assert sm2_crypt_sr.verify(sign,sm4Key_r)  

验证对了,说明j解密出来的钥匙sm4Key_r正确,即提供encrytKey正确,可以进行下一步解密数据,否则会报错

2.3 sm4解密数据

sm4_crypt_r=CryptSM4()
sm4_crypt_r.set_key(sm4Key_r,mode=SM4_DECRYPT)   # todo 这里传的是SM_DECRYPT
data_r=sm4_crypt_r.crypt_ecb(encryptData)
# assert data_r == data   # 实际应用无法用此来验证,只能用签名验证
data_r = eval(data_r.decode('utf-8')) # 转为列表

三、sm2uils.py

from random import SystemRandom

class CurveFp:
    def __init__(self, A, B, P, N, Gx, Gy, name):
        self.A = A
        self.B = B
        self.P = P
        self.N = N
        self.Gx = Gx
        self.Gy = Gy
        self.name = name

sm2p256v1 = CurveFp(
    name="sm2p256v1",
    A=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC,
    B=0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93,
    P=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF,
    N=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123,
    Gx=0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7,
    Gy=0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0
)

a=SystemRandom().randrange(1, sm2p256v1.N)
print(".N=",sm2p256v1.N,"\na=",a)

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//low
        nm, new = hm-lm*r, high-low*r
        lm, 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_Zp
    z = 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) % P
    S = (4 * Xp * ysq) % P
    M = (3 * Xp ** 2 + A * Zp ** 4) % P
    nx = (M**2 - 2 * S) % P
    ny = (M * (S - nx) - 8 * ysq ** 2) % P
    nz = (2 * Yp * Zp) % P
    return (nx, ny, nz)

def jacobianAdd(Xp_Yp_Zp, Xq_Yq_Zq, A, P):
    Xp, Yp, Zp = Xp_Yp_Zp
    Xq, Yq, Zq = Xq_Yq_Zq
    if not Yp:
        return (Xq, Yq, Zq)
    if not Yq:
        return (Xp, Yp, Zp)
    U1 = (Xp * Zq ** 2) % P
    U2 = (Xq * Zp ** 2) % P
    S1 = (Yp * Zq ** 3) % P
    S2 = (Yq * Zp ** 3) % P
    if U1 == U2:
        if S1 != S2:
            return (0, 0, 1)
        return jacobianDouble((Xp, Yp, Zp), A, P)
    H = U2 - U1
    R = S2 - S1
    H2 = (H * H) % P
    H3 = (H * H2) % P
    U1H2 = (U1 * H2) % P
    nx = (R ** 2 - H3 - 2 * U1H2) % P
    ny = (R * (U1H2 - nx) - S1 * H3) % P
    nz = (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 = curve
        self.secret = secret or SystemRandom().randrange(1, curve.N)
        

    def publicKey(self):
        curve = self.curve
        xPublicKey, 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 = x
        self.y = y
        self.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))

[参考]https://github.com/guanzhi/GmSSL

你可能感兴趣的:(国密sm2与sm4加密解密教程)