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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
| import base64
import binascii
import datetime
from typing import Tuple
from gmssl import sm2
from pyasn1.codec.der import decoder, encoder
from pyasn1.type import namedtype, univ
def sm2_encrypt(public_key_in_hex: str, data: bytes) -> Tuple[bytes, str]:
sm2_crypt = sm2.CryptSM2(public_key = public_key_in_hex, private_key = "", mode = 1, asn1 = True)
ciphertext = sm2_crypt.encrypt(data)
# print('cipher in hex:', ciphertext.hex(), len(ciphertext))
encrypted_text = base64.b64encode(ciphertext).decode(encoding = 'utf-8')
# print("encrypted_text in base64:", encrypted_text)
return ciphertext, encrypted_text
class SM2PubKeyASN1Sequence(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('field-0',
univ.Sequence(
componentType = namedtype.NamedTypes(
namedtype.NamedType('oid-1', univ.ObjectIdentifier()),
namedtype.NamedType('oid-2', univ.ObjectIdentifier())
)
)),
namedtype.NamedType('field-1', univ.BitString())
)
def get_pubkey_from_pem(pem_data: str) -> str:
origin_pem_data = base64.b64decode(pem_data)
# print(origin_pem_data.hex(), len(origin_pem_data))
decoded_data, _ = decoder.decode(base64.b64decode(pem_data), asn1Spec = SM2PubKeyASN1Sequence())
# print(decoded_data)
# 获取 field-1 的位串,并转换为十六进制字符串
bit_string = decoded_data['field-1'].asOctets()
hex_string = binascii.hexlify(bit_string).decode('utf-8')
# print("Hexadecimal string of field-1:", hex_string)
return hex_string
def parse_C1C3C2(cipher_bytes: bytes) -> Tuple[bytes, bytes, bytes]:
"""
解析密文,返回C1, C3, C2
SM2密文主要由C1、C2、C3三部分构成,
其中C1是随机数计算出的椭圆曲线、C2是密文数据、C3是SM3杂凑值,
C1固定为64字节,C2的长度与明文相同,C3的长度固定为32字节,
"""
c1 = cipher_bytes[0:64]
c3 = cipher_bytes[64: 32 + 64]
c2 = cipher_bytes[32 + 64:]
return c1, c3, c2
# 定义SM2 Ciphertext结构
class SM2_C1C3C2_ASN1_Ciphertext(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('c1x', univ.Integer()),
namedtype.NamedType('c1y', univ.Integer()),
namedtype.NamedType('c3', univ.OctetString()),
namedtype.NamedType('c2', univ.OctetString())
)
def do_sm2_c1c3c2_asn1_encode(raw_cipher_bytes: bytes) -> bytes:
c1, c3, c2 = parse_C1C3C2(raw_cipher_bytes)
c1x = c1[:32]
c1x_int = int.from_bytes(c1x, 'big')
c1y = c1[32:]
c1y_int = int.from_bytes(c1y, 'big')
# print('c1 part:', c1.hex(), len(c1))
# print('c2 part:', c2.hex(), len(c2))
# print('c3 part:', c3.hex(), len(c3))
ciphertext = SM2_C1C3C2_ASN1_Ciphertext()
ciphertext.setComponentByName('c1x', c1x_int)
ciphertext.setComponentByName('c1y', c1y_int)
ciphertext.setComponentByName('c3', c3)
ciphertext.setComponentByName('c2', c2)
encoded_ciphertext = encoder.encode(ciphertext)
return encoded_ciphertext
if __name__ == '__main__':
# 客户的公钥
public_key = """
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEwklCvM0vuIIigs0KymV81T6RV3wa
dtXQMKiAfTWtp0PtDTy+/PJEddUzMyATiPyV6lGMkOnNe3Y/fIuoeV28/A==
"""
# 我自己的公钥
# public_key = """
# MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEnM/twM3Ri9850urGRgu4fQN1ZQw9
# VroDpPkmXmAdHqWHb6BlkjmettDgA0ikHlFDdRDIwKTSRbFL9n9ohAlNSg==
# """
# 获取公钥的十六进制字符串
hex_pub_key = get_pubkey_from_pem(public_key)
print('hex_pub_key:', hex_pub_key)
# 待加密数据
data_bytes = datetime.datetime.now().isoformat(timespec = 'microseconds').encode('utf-8')
print('data_bytes:', data_bytes.hex())
# 使用外部开源库加密
ret_cipher_bytes, cipher_base64 = sm2_encrypt(hex_pub_key, data_bytes)
ret_asn1_cipher = do_sm2_c1c3c2_asn1_encode(ret_cipher_bytes)
print('asn1_cipher:', ret_asn1_cipher.hex())
print('asn1 base64 cipher:', base64.b64encode(ret_asn1_cipher).decode('utf-8'))
tmp, _ = decoder.decode(ret_asn1_cipher, asn1Spec = SM2_C1C3C2_ASN1_Ciphertext())
print('测试外部库生成的 C1C3C2 密文被自定义 ASN1编码后能否解密:', tmp)
|