依赖
pip install gmssl re requests
参考
源码
# -*- coding: utf-8 -*-
import binascii
import re
import requests
import logging
from gmssl import sm2, func, sm4
class GmSSLDefine:
class KeyStore:
"""
SM2 密钥对类,包含密钥对生成、获取方法
"""
_PRIVATE_KEY = ""
_PUBLIC_KEY = ""
_CREATE_WEB_URL = "https://const.net.cn/tool/sm2/genkey/"
_CREATE_WEB_POST_BODY = {
"prikey": "",
"pubkey": ""
}
def __init__(self) -> None:
pass
def setInit(self, priKey: str, pubKey: str) -> bool:
"""
简单判断密钥对格式
:param priKey: 私钥 64 byte.
:param pubKey: 公钥 128 byte.
:return: bool
"""
result = re.match(r"^[a-fA-F\d]{64}$", priKey)
if result is None:
logging.error("KeyStore.setInit() -> priKey is invalid.")
return False
result = re.match(r"^[a-fA-F\d]{128}$", pubKey)
if result is None:
logging.error("KeyStore.setInit() -> pubKey is invalid.")
return False
self._PRIVATE_KEY = priKey
self._PUBLIC_KEY = pubKey
return True
def createByNet(self) -> bool:
"""
通过网络获取密钥对,返回 True/False.
:return: bool
"""
counts = [0, 0]
keys = ["", ""]
response = requests.request(
"post", self._CREATE_WEB_URL, json=self._CREATE_WEB_POST_BODY
)
pattern = re.compile(r"value=\"[a-fA-F\d]{64,128}\"")
results = pattern.findall(response.text)
for result in results:
if len(result) == 72:
pattern = re.compile(r"\"[a-fA-F\d]{64}\"")
keys[0] = pattern.findall(result)[0].lstrip("\"").rstrip("\"")
counts[0] = counts[0] + 1
elif len(result) == 136:
pattern = re.compile(r"\"[a-fA-F\d]{128}\"")
keys[1] = pattern.findall(result)[0].lstrip("\"").rstrip("\"")
counts[1] = counts[1] + 1
# 和为 2 ,正常
if counts[0] + counts[1] != 2:
logging.error("KeyStore.createByNet() can't get the correct return by url. ",
"Please call the Lib's Designer. ")
return False
self._PRIVATE_KEY = keys[0]
self._PUBLIC_KEY = keys[1]
return True
def createLocal(self) -> bool:
"""
本地创建密钥对
:return: bool
"""
class _Generator_SM2_Key(sm2.CryptSM2):
"""
取自 https://samo.fun/2021/03/24/Python_Generate_SM2_key/
"""
def __init__(self, private_key=None, public_key=None, ecc_table=sm2.default_ecc_table):
super().__init__(private_key, public_key, ecc_table)
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
try:
_sm2Generator = _Generator_SM2_Key()
self._PRIVATE_KEY = _sm2Generator.get_private_key()
self._PUBLIC_KEY = _sm2Generator.get_public_key()
return True
except:
logging.error("KeyStore.createLocal() can't create the correct keys. ",
"Please call the Lib's Designer. ")
return False
def getSelf(self) -> dict:
"""
获取创建的密钥对
:return: dict: keyStore 格式:
{
"PRIVATE_KEY": "",
"PUBLIC_KEY": ""
}
"""
return {
"PRIVATE_KEY": self._PRIVATE_KEY,
"PUBLIC_KEY": self._PUBLIC_KEY
}
def getPrivateKey(self) -> str:
"""
返回公钥
:return: str
"""
return self._PRIVATE_KEY
def getPublicKey(self) -> str:
"""
返回私钥
:return: str
"""
return self._PUBLIC_KEY
class SM2_Crypt(Exception):
"""
SM2 加解密类
"""
_SM2_CRYPT = None
def __init__(self, exception="") -> None:
"""
构造函数
:param exception: 默认参数,用于自定义异常
"""
self._EXCPTION = None
self._INIT_FLAG = False
def setInit(self, keyStore: dict) -> bool:
"""
初始化密钥对
:param keyStore: dict: keyStore 格式:
{
"PRIVATE_KEY": "",
"PUBLIC_KEY": ""
}
:return: bool
"""
try:
# 判断是否为全为英文和数字,且是 16 个字符的字符串
# 不是,则抛出异常
if re.match(r"^[a-fA-F\d]{64}$", keyStore["PRIVATE_KEY"]) is None:
raise GmSSLDefine.SM2_Crypt(exception="SM2_Crypt.setInit() -> PRIVATE_KEY is invalid.")
if re.match(r"^[a-fA-F\d]{128}$", keyStore["PUBLIC_KEY"]) is None:
raise GmSSLDefine.SM2_Crypt(exception="SM2_Crypt.setInit() -> PUBLIC_KEY is invalid.")
except GmSSLDefine.SM2_Crypt as e:
logging.error(e._EXCPTION)
return False
self._SM2_CRYPT = sm2.CryptSM2(public_key=keyStore["PUBLIC_KEY"], private_key=keyStore["PRIVATE_KEY"])
self._INIT_FLAG = True
return True
def getSelf(self) -> sm2.CryptSM2:
"""
获取加解密类对象
:return: sm2.CryptSM2 类实例
"""
return self._SM2_CRYPT
def encrypt(self, data: str):
"""
进行 SM2 加密操作
:param data: String 格式的原文 data
:return: String 格式的密文 enc_data
"""
data_utf8 = data.encode("utf-8")
enc_data = self._SM2_CRYPT.encrypt(data_utf8)
enc_data = binascii.b2a_hex(enc_data).decode("utf-8")
return enc_data
def decrypt(self, enc_data: str):
"""
进行 SM2 解密操作
:param enc_data: String 格式的密文 enc_data
:return: String 格式的原文 data
"""
enc_data = binascii.a2b_hex(enc_data.encode("utf-8"))
dec_data = self._SM2_CRYPT.decrypt(enc_data)
dec_data = dec_data.decode("utf-8")
return dec_data
class SM4_Crypt(Exception):
"""
SM4 加解密类
作为 Exception 异常类的子类,可用于自定义异常
"""
_KEY = None
_IV = None
_SM4_CRYPT = None
_EXCPTION = None
_INIT_FLAG = False
def __init__(self, exception="") -> None:
"""
构造函数
:param exception: 默认参数,用于自定义异常
"""
self._EXCPTION = exception
pass
def setInit(self, key: str, iv: str) -> bool:
"""
设置 Key 和 IV
:param key: 16 字节长度的 String , 只能包含大小写英文、阿拉伯数字
:param iv: 16 字节长度的 String , 只能包含大小写英文、阿拉伯数字
:return: bool
"""
try:
# 判断是否为全为英文和数字,且是 16 个字符的字符串
# 不是,则抛出异常
if re.match(r"^[a-zA-Z\d]{16}$", key) is None:
raise GmSSLDefine.SM4_Crypt(exception="SM4_Crypt.setInit() -> key is invalid.")
if re.match(r"^[a-zA-Z\d]{16}$", iv) is None:
raise GmSSLDefine.SM4_Crypt(exception="SM4_Crypt.setInit() -> iv is invalid.")
except GmSSLDefine.SM4_Crypt as e:
logging.error(e._EXCPTION)
return False
self._KEY = key.encode("utf-8")
self._IV = iv.encode("utf-8")
self._SM4_CRYPT = sm4.CryptSM4()
self._INIT_FLAG = True
return True
def _hadInit(self) -> bool:
"""
判断是否初始化 KEY 和 IV
:return: bool
"""
try:
if not self._INIT_FLAG:
raise GmSSLDefine.SM4_Crypt(exception="SM4_Crypt.setInit() has not been used.")
else:
return True
except GmSSLDefine.SM4_Crypt as e:
logging.error(e._EXCPTION)
return False
def getSelf(self) -> sm4.CryptSM4:
"""
获取自身 SM4 加解密类对象
:return: sm4.CryptSM4 类实例
"""
if self._hadInit():
return self._SM4_CRYPT
else:
pass
def encrypt_ECB(self, data: str) -> str:
"""
进行 ECB 方式的 SM4 加密操作
:param data: String 格式的原文 data
:return: String 格式的密文 enc_data
"""
data_utf8 = data.encode("utf-8")
self._SM4_CRYPT.set_key(self._KEY, sm4.SM4_ENCRYPT)
enc_data = self._SM4_CRYPT.crypt_ecb(data_utf8) # bytes类型
enc_data = binascii.b2a_hex(enc_data).decode("utf-8")
return enc_data
def decrypt_ECB(self, enc_data: str) -> str:
"""
进行 ECB 方式的 SM4 解密操作
:param enc_data: String 格式的密文 enc_data
:return: String 格式的原文 data
"""
enc_data = binascii.a2b_hex(enc_data.encode("utf-8"))
self._SM4_CRYPT.set_key(self._KEY, sm4.SM4_DECRYPT)
dec_data = self._SM4_CRYPT.crypt_ecb(enc_data) # bytes类型
dec_data = binascii.b2a_hex(enc_data).decode("utf-8")
return dec_data
def encrypt_CBC(self, data: str) -> str:
"""
进行 CBC 方式的 SM4 加密操作
:param data: String 格式的原文 data
:return: String 格式的密文 enc_data
"""
data_utf8 = data.encode("utf-8")
self._SM4_CRYPT.set_key(self._KEY, sm4.SM4_ENCRYPT)
enc_data = self._SM4_CRYPT.crypt_cbc(self._IV, data_utf8)
enc_data = binascii.b2a_hex(enc_data).decode("utf-8")
return enc_data
def decrypt_CBC(self, enc_data: str) -> str:
"""
进行 CBC 方式的 SM4 解密操作
:param enc_data: String 格式的密文 enc_data
:return: String 格式的原文 data
"""
enc_data = binascii.a2b_hex(enc_data.encode("utf-8"))
self._SM4_CRYPT.set_key(self._KEY, sm4.SM4_DECRYPT)
dec_data = self._SM4_CRYPT.crypt_cbc(self._IV, enc_data)
dec_data = binascii.b2a_hex(enc_data).decode("utf-8")
return dec_data
# 示例
# """
# SM2
# """
# keyStore = GmSSLDefine.KeyStore()
# sm2_crypt = GmSSLDefine.SM2_Crypt()
# # if keyStore.createByNet():
# if keyStore.createLocal():
# keysDict = keyStore.getSelf()
# sm2_crypt.setInit(keysDict)
# data = "明文"
# print("data: " + data)
# enc_data = sm2_crypt.encrypt(data)
# print("enc_data: " + enc_data)
# dec_data = sm2_crypt.decrypt(enc_data)
# print("dec_data: " + dec_data)
# if data == dec_data:
# print("data == dec_data: True")
# else:
# print("create f")
# """
# SM4
# """
# data = "明文"
# sm4_crypt = GmSSLDefine.SM4_Crypt()
# if sm4_crypt.setInit("zzzzzzzzzzzzzzzz", "1234567890123456") == True:
# if sm4_crypt != False:
# enc_data = sm4_crypt.encrypt_ECB(data)
# print("enc_data: " + enc_data)
# dec_data = sm4_crypt.decrypt_ECB(enc_data)
# print("dec_data: " + dec_data)
# if data == dec_data:
# print("data == dec_data: True")
# # enc_data = sm4_crypt.encrypt_CBC(data)
# # print("enc_data: " + enc_data)
# # dec_data = sm4_crypt.decrypt_CBC(enc_data)
# # print("dec_data: " + dec_data)
# # if data == dec_data:
# # print("data == dec_data: True")
# else:
# print("sm4 f")
# else:
# print("sm4 init f")