Python国密算法使用探索 | Mayx的博客
Author: mayx
Description: 使用罕见的算法是什么感受😁
Date: 2024-09-02T00:00:00+08:00

2 September 2024 - 字数统计：2149 - 阅读大约需要7分钟 - Hits: Loading...

# Python国密算法使用探索

by mayx

这是一篇创建于 天前的文章，其中的信息可能已经有所发展或是发生改变。

AI摘要

这篇文章讲述了作者在使用Python进行国密算法操作，特别是SM3和SM2算法时的经历。作者发现虽然Python标准库的新版OpenSSL支持国密，但旧版和一些第三方库如GmSSL-Python和gmssl存在兼容性问题。作者最终选择纯Python实现的gmssl库，解决了SM2验签时公钥转换和HMAC-SM3在旧版Python上的自定义适配问题。作者认为虽然国内国密算法进入了标准，但普及性不高，且安全性的疑虑仍存在。

- 起因
- 关于Python使用国密算法的方式
- 使用SM2withSM3进行验签
- 使用HMAC-SM3对数据进行消息验证
- 感想

使用罕见的算法是什么感受😁

#
起因

前段时间因为某些原因需要对某些东西进行密评改造，需要使用国密算法。虽然国密算法也算进入标准了，但是网上能搜到的资料还是太少了（尤其是Python的，大多资料都是Java的），所以我打算自己研究研究。

#
关于Python使用国密算法的方式

其实在新版OpenSSL中已经支持了国密算法，比如SM3还有SM4，不过pyOpenSSL似乎只有对非对称加密算法的支持……我倒是不在乎，因为在我实际应用里加解密都是服务器密码机处理的，我自己连密钥也看不到，所以不需要管怎么实现。但是签名验签还有摘要算法之类的理论上应该是可以自己实现的，毕竟算法是公开的。

关于摘要算法SM3我搜了一下，似乎因为它已经进入标准了，至少在新版的Python中可以用`hashlib.new("sm3")`这样的方式进行计算，但是旧版的Python用不了……所以如果要在旧版Python上处理还得自己想办法。

既然标准库不太能满足，那第三方库选哪个比较好呢？我看用的比较多的一个是封装C库GmSSL的GmSSL-Python，想要安装得先安装那个C库；还有一个是纯Python实现的gmssl。对我来说的话我更喜欢后面那个纯python实现的，虽然效率低了点，但是看起来比较简单（虽然看起来不是很专业🤣），那个C库包装的感觉有点复杂……而且这两个库有冲突，所以最终我选择了那个纯Python实现的版本。

#
使用SM2withSM3进行验签

在一些挑战应答方式的登录方式中就需要用到这种东西，服务器发送一个随机数让客户端用私钥签名，然后服务器用公钥进行验签。我看了一下那个库的“gmssl.sm2.CryptSM2”中有个verify_with_sm3方法挺符合需求的，但有个问题是它这个CryptSM2传入的公钥是串数字，但客户端传来的是证书……看来还得解析证书，我看pyOpenSSL库里有加载证书还有导出公钥的方法，但是那个导出的公钥也不是一串数字……后来看了半天，发现导出的公钥的倒数130位才是公钥😅……最终把所有的值带进去试了一下终于没问题了，最终的代码如下：

    import OpenSSL.crypto
    from gmssl import sm2
    import base64

    certSign = ""   # 证书
    signBytes = b"" # 签名
    inData = b""    # 被签名的值

    sm2.CryptSM2(
        private_key="",
        public_key=OpenSSL.crypto.dump_publickey(
            OpenSSL.crypto.FILETYPE_ASN1,
            OpenSSL.crypto.load_certificate(
                OpenSSL.crypto.FILETYPE_PEM,
                f"""-----BEGIN CERTIFICATE-----
    {certSign}
    -----END CERTIFICATE-----""".encode(),
            ).get_pubkey(),
        ).hex()[-128:],
        asn1=True,
    ).verify_with_sm3(signBytes.hex(), inData)

#
使用HMAC-SM3对数据进行消息验证

这个其实新版的Python可以直接用，因为新版Python的hashlib里有SM3，所以一句

    hmac.new(key, data, digestmod="sm3").hexdigest()

就可以了，但是我用的是旧版的Python（macOS自带的3.9.6🤣）不支持……那怎么办呢？我看了一下这个函数的注释写的“digestmod”这个参数除了传hashlib支持的方法之外还可以传符合PEP 247的模块。显然无论是GmSSL-Python还是gmssl都没有符合这个规范。不过我可以自己写个适配器来适配这个规范。所以最终只好自己写一下了：

    import copy
    import hmac
    from gmssl import sm3

    class sm3_adapter:
        def __init__(self):
            self.msg = []
            self.digest_size = 32
            self.block_size = 64

        def new(self):
            self.msg = []

        def update(self, data):
            self.msg += list(data)

        def copy(self):
            return copy.deepcopy(self)

        def digest(self):
            return bytes.fromhex(self.hexdigest())

        def hexdigest(self):
            return sm3.sm3_hash(self.msg)

    key = b""   # 密钥
    data = b""  # 数据
    hmac.new(key, data, digestmod=sm3_adapter).hexdigest()

#
感想

这么看来使用国密算法加密倒是也没很复杂，但是和国际标准相比也没什么优势。虽然有些地方强制使用那确实没啥办法，但是想要普及肯定是不用想了，另外我自己的东西肯定是不敢用国密，虽然进了标准而且也开放了算法，但是很难说会不会像Dual_EC_DRBG算法那样偷偷插了后门 （虽然我觉得他们应该没这个实力🤣） ，但国际算法有后门我不怕，国内算法有后门那就吓人了🤣。

tags: Python - GmSSL - 国密 查看原始文件

#### 推荐文章

Loading...

上一篇：Mac mini 2018使用体验
下一篇：用CF Vectorize把博客作为聊天AI的知识库
想问这篇文章
召唤伊斯特瓦尔