美文网首页
国密sm2与sm4加密解密教程

国密sm2与sm4加密解密教程

作者: 一个摸鱼AI喵 | 来源:发表于2021-10-17 09:30 被阅读0次

    国密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加密解密教程

          本文链接:https://www.haomeiwen.com/subject/yhronltx.html