Python3使用国密SM2生成密钥、签名

Python3 使用国密 SM2 生成密钥、签名、加密、解密

因项目需用到国密不熟悉,网上python使用SM2资料较少,苦苦寻找并测试,最后签名验证完成,亲测可用。操作方式记录如下,特此记录,方便日后回顾。包含生成密钥、签名、加密、解密

1、安装包

#安装gmssl
pip install gmssl

2、全部复制直接用

import binascii

from gmssl import sm2 as SM2
from random import SystemRandom
from base64 import b64encode, b64decode

from gmssl.func import random_hex


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


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

    @staticmethod
    def multiply(a, n, N, A, P):
        return SM2Key.fromJacobian(SM2Key.jacobianMultiply(SM2Key.toJacobian(a), n, N, A, P), P)

    @staticmethod
    def add(a, b, A, P):
        return SM2Key.fromJacobian(SM2Key.jacobianAdd(SM2Key.toJacobian(a), SM2Key.toJacobian(b), A, P), P)

    @staticmethod
    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

    @staticmethod
    def toJacobian(Xp_Yp):
        Xp, Yp = Xp_Yp
        return Xp, Yp, 1

    @staticmethod
    def fromJacobian(Xp_Yp_Zp, P):
        Xp, Yp, Zp = Xp_Yp_Zp
        z = SM2Key.inv(Zp, P)
        return (Xp * z ** 2) % P, (Yp * z ** 3) % P

    @staticmethod
    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

    @staticmethod
    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 SM2Key.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

    @staticmethod
    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 SM2Key.jacobianMultiply((Xp, Yp, Zp), n % N, N, A, P)
        if (n % 2) == 0:
            return SM2Key.jacobianDouble(SM2Key.jacobianMultiply((Xp, Yp, Zp), n // 2, N, A, P), A, P)
        if (n % 2) == 1:
            mv = SM2Key.jacobianMultiply((Xp, Yp, Zp), n // 2, N, A, P)
            return SM2Key.jacobianAdd(SM2Key.jacobianDouble(mv, A, P), (Xp, Yp, Zp), A, P)


class PrivateKey:
    def __init__(self, curve=SM2Key.sm2p256v1, secret=None):
        self.curve = curve
        self.secret = secret or SystemRandom().randrange(1, curve.N)
        print(self.secret)

    def PublicKey(self):
        curve = self.curve
        xPublicKey, yPublicKey = SM2Key.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 '04' + {
            True: str(hex(self.x))[2:],
            False: "{}{}".format(str(hex(self.x))[2:].zfill(64), str(hex(self.y))[2:].zfill(64))
        }.get(compressed)


class SM2Util:
    def __init__(self, pub_key=None, pri_key=None):
        self.pub_key = pub_key
        self.pri_key = pri_key
        self.sm2 = SM2.CryptSM2(public_key=self.pub_key, private_key=self.pri_key)

    def Encrypt(self, data):
        info = self.sm2.encrypt(data.encode())
        return b64encode(info).decode()

    def Decrypt(self, data):
        info = b64decode(data.encode())
        return self.sm2.decrypt(info).decode()

    def Sign(self, data):

        # random_hex_str = random_hex(self.sm2.para_len)
        """有要求配置ID可配置"""
        random_hex_str = '1234567812345678'.encode('utf-8').hex()

        self.sm2_crypt = SM2.CryptSM2(public_key=self.pub_key, private_key=self.pri_key)
        sign = self.sm2_crypt.sign_with_sm3(data.encode(), random_hex_str)
        print('sign:%s' % sign)
        # 验签
        verify = self.sm2_crypt.verify_with_sm3(sign, data.encode())
        print('verify:%s' % verify)

        return sign

    def Verify(self, data, sign):
        return self.sm2_crypt.verify_with_sm3(sign, data.encode())

    @staticmethod
    def GenKeyPair(secret):
        pri = PrivateKey(secret=secret)
        pub = pri.PublicKey()
        return pri.ToString(), pub.ToString(compressed=False)


if __name__ == '__main__':
    data = 'hahahaa12323'
    print('原数据:{}'.format(data))
    secret_int = None
    # secret_int = int('54a1edf8a404fa8e52dc2c6d37d7bbe0bf915f85e85a0af350478271e5f60cd3', 16)


    e = SM2Util.GenKeyPair(secret_int)
    print('私钥:{} 公钥:{}'.format(e[0], e[1]))
    sm2 = SM2Util(pri_key=e[0], pub_key=e[1][2:])

    sign = sm2.Sign(data)
    print('签名:{} 验签:{}'.format(sign, sm2.Verify(data, sign)))

    cipher = sm2.Encrypt(data)
    print('加密:{}\n解密:{}'.format(cipher, sm2.Decrypt(cipher)))
    
  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
实现SM2数字签名,加密和解密需要使用SM2算法库,可以使用Python的第三方库pycryptodome或gmssl。以下是使用pycryptodome实现SM2数字签名,加密和解密的示例代码: 1. SM2数字签名 ```python from Crypto.PublicKey import ECC from Crypto.Signature import DSS from Crypto.Hash import SHA256 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad from binascii import b2a_hex, a2b_hex # 生成SM2密钥对 private_key = ECC.generate(curve='sm2') public_key = private_key.public_key() # 待签名数据 data = b'hello, world' # 计算消息摘要 digest = SHA256.new(data) # 对消息摘要进行数字签名 signer = DSS.new(private_key, 'fips-186-3') signature = signer.sign(digest) # 验证数字签名 verifier = DSS.new(public_key, 'fips-186-3') try: verifier.verify(digest, signature) print("Signature is valid.") except ValueError: print("Signature is invalid.") ``` 2. SM2加密和解密 ```python from Crypto.Cipher import SM2Cipher from Crypto.PublicKey import ECC from Crypto.Util.Padding import pad, unpad from binascii import b2a_hex, a2b_hex # 生成SM2密钥对 private_key = ECC.generate(curve='sm2') public_key = private_key.public_key() # 加密数据 plaintext = b'hello, world' cipher = SM2Cipher.new(public_key) ciphertext = cipher.encrypt(plaintext) # 解密数据 cipher = SM2Cipher.new(private_key) decrypttext = cipher.decrypt(ciphertext) print("Plaintext:", plaintext) print("Ciphertext:", b2a_hex(ciphertext)) print("Decrypttext:", decrypttext) ``` 注意,以上代码只是示例,实际使用时需要注意安全性和数据格式转换等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值