0%

Python生成SM2公私密钥对进行签名验签

最近要生成SM2签名验签测试数据,使用了Python的gmssl库,里面包含了SM2加解密、签名验签的函数,但是要从别的地方生成公私钥对比较麻烦,因此通过SM2内部实现的私有函数实现公私钥对的生成,密钥对生成规则如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from gmssl import sm2, func

# 继承SM2类
class Generator_SM2_Key(sm2.CryptSM2):
def __init__(self, private_key = None, public_key = None, ecc_table = sm2.default_ecc_table, mode = 0):
super().__init__(private_key, public_key, ecc_table, mode)

def get_private_key(self):
if self.private_key is None:
self.private_key = func.random_hex(self.para_len) # d∈[1, n-2]
return self.private_key

def get_public_key(self):
if self.public_key is None:
self.public_key = self._kg(int(self.get_private_key(), 16), self.ecc_table['g']) # P=[d]G
return self.public_key


sm2key = Generator_SM2_Key()
private_key = sm2key.get_private_key()
public_key = sm2key.get_public_key()
print('private_key:',private_key)
print('public_key: ',public_key)

sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key)

#数据和加密后数据为bytes类型
data = bytes.fromhex('91cacfd230122fc832fc1b0b2aa07d93')
enc_data = sm2_crypt.encrypt(data)
dec_data =sm2_crypt.decrypt(enc_data)
assert dec_data == data
print('Enc: ',enc_data.hex())

random_hex_str = func.random_hex(sm2_crypt.para_len)
sign = sm2_crypt.sign_with_sm3(data, random_hex_str)
assert sm2_crypt.verify_with_sm3(sign, data)
print('Sign:',sign)

输出如下:

1
2
3
4
private_key: df67f088cc94143a51c060acb4357cfc86ad14492476caf418480385de72439
public_key: ce343dae8cd86d3342cab71b1e33375332a89d01cc2565b207e8bedd2a33e17779e36b052217de31fb8a8230fbfd06e93c445261852a7f610b28dd29146bafda
Enc: 88c8bf8f2e1bf0bca22a7c788e971d5402d08a903ec1493769bd837fe153faffe0668e6006788b18069e5837a208345743808c3d326507099c4240601dc90aece3bcb8243b70e57cd2976e040d573b782976144f8206af242b974fc7e27d0b2a7ec491484f9040d5dcdec885b8412904
Sign: 7567a7266cf70080f11b5c0c1aed84e7ff4a173fdded1959d5df8e2c25857371f660844cf7dbb1feda68585b387a6823e4c79ee819833fbe31332428a02ffd96

:gmssl库中的随机数发生器random_hex函数是不符合要求的,其定义如下:

1
random_hex = lambda x: ''.join([choice('0123456789abcdef') for _ in range(x)])

可以看到random_hex有概率为0,而数字签名中的k∈[1, n-1],密钥对生成中的d∈[1, n-2]