• 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")
    
    
  • 相关阅读:
    Zookeeper 系列(五)Curator API
    Zookeeper 系列(四)ZKClient API
    Zookeeper 系列(三)Zookeeper API
    Zookeeper 系列(二)安装配制
    [bzoj 2393] Cirno的完美算数教室 (容斥原理+dfs剪枝)
    [Sdoi2013] [bzoj 3198] spring (hash+容斥原理)
    [bzoj 1471] 不相交路径 (容斥原理)
    [bzoj 3701] Olympic Games (莫比乌斯反演)
    [bzoj 2693] jzptab & [bzoj 2154] Crash的数字表格 (莫比乌斯反演)
    [51Nod 1244]
  • 原文地址:https://www.cnblogs.com/Yogile/p/16414422.html
Copyright © 2020-2023  润新知