一、加解密互操作:云上密钥派生 + 本地解密

场景描述

通过腾讯云KMS生成数据加密密钥(DEK),生成时上传本地SM2公钥到KMS加密DEK,再由本地私钥解密,实现云端和本地端无缝密钥交换。

腾讯云 KMS 在生成数据密钥时,接口中允许传入一把本地的 SM2 公钥。

生成数据密钥的接口会使用这把公钥对数据密钥明文做加密,然后将密文返回,本地使用 SM2 私钥进行解密得到密文,通过这种方式实现信道安全传输,完成安全且合规的密钥交换。

img

 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
from __future__ import annotations
import base64
import os
from easy_gmssl import EasySm2EncryptionKey , SM2CipherMode
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.kms.v20190118 import kms_client , models
cred = credential.Credential(os.getenv("CLOUD_SECRET_ID") ,
                             os.getenv("CLOUD_SECRET_KEY"))
client = kms_client.KmsClient(cred , "ap-guangzhou")
try:
    # 生成本地 SM2密钥对
    #  KMS-API 侧生成 DEK并使用本地的 SM2公钥加密 DEK 明文得到 DEK 密文
    with open('test_sm2_public.pem' , 'rb') as f:
        sm2_pub_key_bytes = f.read()
    req = models.GenerateDataKeyRequest()
    req.KeyId = '7bab23ea-1a0e-11ee-a405-52540078f78b'
    req.NumberOfBytes = 32
    req.EncryptionAlgorithm = 'SM2_C1C3C2_ASN1'
    req.EncryptionPublicKey = sm2_pub_key_bytes.decode('utf-8')
    resp = client.GenerateDataKey(req)
    print(resp.to_json_string(indent = 4))
    ####################################################
    # 使用本地的 SM2私钥解密 KMS 返回的 DEK 密文数据
    decrypt_sm2 = EasySm2EncryptionKey()
    decrypt_sm2.load_sm2_private_key('./test_sm2_private.pem' , '12345678')
    cipher = base64.b64decode(resp.Plaintext)
    plain_data = decrypt_sm2.Decrypt(cipher_data = cipher ,
                                     cipher_mode = SM2CipherMode.C1C3C2_ASN1)
    print(f'original dek data: {plain_data}, length: {len(plain_data)}')
except TencentCloudSDKException as err:
    print(err)

img

二、加解密互操作:本地SM2公钥加密数据 + 云端SM2私钥解密数据

场景描述

本地使用 KMS SM2 公钥加密明文得到密文,KMS 控制台或云 API 使用 SM2 私钥解密密文得到明文,实现云端和本地端无缝明文数据交换。

腾讯云 KMS 的 SM2 解密接口,允许传入格式为 C1C3C2_ASN1 的密文进行解密。

img

控制台也提供了 SM2 解密的工具,可以快速进行解密验证。

img

本地使用 EasyGmSSL 和 腾讯云 KMS 进行 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
from __future__ import annotations
import base64
import os
from easy_gmssl import EasySm2EncryptionKey , SM2CipherMode
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.kms.v20190118 import kms_client , models
cred = credential.Credential(os.getenv("CLOUD_SECRET_ID") ,
                             os.getenv("CLOUD_SECRET_KEY"))
client = kms_client.KmsClient(cred , "ap-guangzhou")
try:
    # KMS公钥加密然后去 KMS 控制台使用私钥解密
    # 密钥 ID5f6b0824-bbf1-11ee-968e-5254000a5333
    encrypt_sm2 = EasySm2EncryptionKey()
    encrypt_sm2.load_sm2_pub_key('./sm2_encrypt.pem')
    plain = b'hello,world\n'
    ret = encrypt_sm2.Encrypt(plain)
    print(f'using kms sm2 public key to encrypt plain, got cipher in base64: {ret}')
    req = models.AsymmetricSm2DecryptRequest()
    req.KeyId = '5f6b0824-bbf1-11ee-968e-5254000a5333'
    req.Ciphertext = ret
    resp = client.AsymmetricSm2Decrypt(req)
    print(resp.to_json_string(indent = 4) , base64.b64decode(resp.Plaintext) == plain)
    assert base64.b64decode(resp.Plaintext) == plain , 'kms decrypt failed, decrypted data is invalid'
except TencentCloudSDKException as err:
    print(err)

img

三、签名验签互操作:双模式全兼容

腾讯云 KMS 提供非对称密钥的签名验签云 API 接口

img

img

控制台也提供针对消息原文和消息摘要的签名验签工具,用户可以在控制台快速完成签名验签的验证流程。

img

场景1:原始消息签名(RAW模式)

云端签名 → 本地验签

 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
from __future__ import annotations
import base64
import os
from easy_gmssl import EasySM2VerifyKey , EasySM3Digest , EasySm2Key , SignatureMode
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.kms.v20190118 import kms_client , models
cred = credential.Credential(os.getenv("CLOUD_SECRET_ID") ,
                             os.getenv("CLOUD_SECRET_KEY"))
client = kms_client.KmsClient(cred , "ap-guangzhou")
try:
    plain = os.urandom(2048)
    req = models.SignByAsymmetricKeyRequest()
    req.KeyId = '6b9a11ff-bbf1-11ee-829f-5254007a9eec'
    req.Algorithm = 'SM2DSA'
    req.Message = base64.b64encode(plain).decode('utf-8')
    req.MessageType = 'RAW'
    resp = client.SignByAsymmetricKey(req)
    print(resp.to_json_string(indent = 4))
    signature = resp.Signature
    signature_bytes = base64.b64decode(signature)
    test_verify = EasySM2VerifyKey(pem_public_key_file = './sm2_verify.pem')
    test_verify.UpdateData(plain)
    ret = test_verify.VerifySignature(signature_data = signature_bytes , signature_mode = SignatureMode.RS_ASN1)
    print(f'verify sm2 signature for plain data: {ret}')
except TencentCloudSDKException as err:
    print(err)

img

场景2:摘要签名(DIGEST模式)

img

使用 EasyGmSSL 进行本地摘要验签时的流程

本地摘要 → 云端签名 → 本地验签

 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
from __future__ import annotations
import base64
import os
from easy_gmssl import EasySM2VerifyKey , EasySM3Digest , EasySm2Key , SignatureMode
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.kms.v20190118 import kms_client , models
cred = credential.Credential(os.getenv("CLOUD_SECRET_ID") ,
                             os.getenv("CLOUD_SECRET_KEY"))
client = kms_client.KmsClient(cred , "ap-guangzhou")
try:
    plain = os.urandom(2048)
    h = EasySM3Digest()
    h.UpdateData(plain)
    hash_bytes , hash_len , plain_len = h.GetHash()
    print(f'plain sm3 hash:{base64.b64encode(hash_bytes).decode()}, length:{hash_len}, plain_len:{plain_len}')
    req = models.SignByAsymmetricKeyRequest()
    req.KeyId = '6b9a11ff-bbf1-11ee-829f-5254007a9eec'
    req.Algorithm = 'SM2DSA'
    req.Message = base64.b64encode(hash_bytes).decode('utf-8')
    req.MessageType = 'DIGEST'
    resp = client.SignByAsymmetricKey(req)
    print(resp.to_json_string(indent = 4))
    signature = resp.Signature
    signature_bytes = base64.b64decode(signature)
    verify = EasySm2Key()
    verify.load_sm2_pub_key('./sm2_verify.pem')
    ret = verify.verify_digest_signature(hash_bytes , signature_bytes)
    print(f'verify sm2 digest signature for plain sm3 hash: {ret}')
except TencentCloudSDKException as err:
    print(err)

img

双模式全支持

  • RAW模式:直接处理原始数据
  • DIGEST模式:无缝对接SM3摘要

四、关于EasyGmSSL的易用性

安装简单

pip install easy_gmssl

MacOS/Linux安装一条命令搞定。

密文格式灵活转换

密钥加解密模式多样化 新增了多种SM2密钥加解密模式选择,包括C1C3C2、C1C3C2_ASN1、C1C2C3、C1C2C3_ASN1。这些模式为不同应用需求提供了更灵活的加密策略,无论是在对加密效率有要求,还是对加密数据格式兼容性有考量的场景下,都能找到合适的解决方案。

签名验签模式扩展 在SM2签名验签时,增加了RS_ASN1、RS两种模式选择,适应不同的签名规范和验证场景,使签名验签操作更加贴合实际业务需求。

img

1
2
3
4
5
6
7
8
9
from __future__ import annotations
from easy_gmssl import EasySm2EncryptionKey, SM2CipherFormat, SM2CipherMode
enc = EasySm2EncryptionKey()
plain = 'hello,world'
# 遍历当前支持的所有 SM2 加解密算法模式
# 当前支持的模式包括
# C1C3C2_ASN1C1C3C2C1C2C3_ASN1C1C2C3
for mode in SM2CipherMode:
    print(mode, '密文 in Hex:', enc.Encrypt('hello,world'.encode('utf-8'), mode, SM2CipherFormat.HexStr))

SM2公钥、私钥十六进制简单读取

密钥读取便捷化 允许用户轻松读取SM2公钥、私钥的十六进制明文,方便在调试、密钥管理等环节快速获取关键信息,提升开发效率。

1
2
3
4
5
from __future__ import annotations
from easy_gmssl import EasySm2Key
test = EasySm2Key()
print('公钥数据 In Hex:', test.get_sm2_public_key_in_hex())
print('私钥数据 In Hex:', test.get_sm2_private_key_in_hex())