Python GmSSL(KeyStory、SM2、SM4)

依赖

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")

posted @ 2022-06-26 21:27  Yogile  阅读(2124)  评论(0编辑  收藏  举报