blog/_posts/2024-09-02-gmssl.md

81 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
layout: post
title: Python国密算法使用探索
tags: [Python, GmSSL, 国密]
---
使用罕见的算法是什么感受😁<!--more-->
# 起因
前段时间因为某些原因需要对某些东西进行密评改造需要使用国密算法。虽然国密算法也算进入标准了但是网上能搜到的资料还是太少了尤其是Python的大多资料都是Java的所以我打算自己研究研究。
# 关于Python使用国密算法的方式
其实在新版OpenSSL中已经支持了国密算法比如SM3还有SM4不过[pyOpenSSL](https://github.com/pyca/pyopenssl)似乎只有对非对称加密算法的支持……我倒是不在乎,因为在我实际应用里加解密都是服务器密码机处理的,我自己连密钥也看不到,所以不需要管怎么实现。但是签名验签还有摘要算法之类的理论上应该是可以自己实现的,毕竟算法是公开的。
关于摘要算法SM3我搜了一下似乎因为它已经进入标准了至少在新版的Python中可以用`hashlib.new("sm3")`这样的方式进行计算但是旧版的Python用不了……所以如果要在旧版Python上处理还得自己想办法。
既然标准库不太能满足那第三方库选哪个比较好呢我看用的比较多的一个是封装C库[GmSSL](https://github.com/guanzhi/GmSSL)的[GmSSL-Python](https://github.com/GmSSL/GmSSL-Python)想要安装得先安装那个C库还有一个是纯Python实现的[gmssl](https://github.com/duanhongyi/gmssl)。对我来说的话我更喜欢后面那个纯python实现的虽然效率低了点但是看起来比较简单虽然看起来不是很专业🤣那个C库包装的感觉有点复杂……而且这两个库有冲突所以最终我选择了那个纯Python实现的版本。
# 使用SM2withSM3进行验签
在一些挑战应答方式的登录方式中就需要用到这种东西服务器发送一个随机数让客户端用私钥签名然后服务器用公钥进行验签。我看了一下那个库的“gmssl.sm2.CryptSM2”中有个verify_with_sm3方法挺符合需求的但有个问题是它这个CryptSM2传入的公钥是串数字但客户端传来的是证书……看来还得解析证书我看pyOpenSSL库里有加载证书还有导出公钥的方法但是那个导出的公钥也不是一串数字……后来看了半天发现导出的公钥的倒数130位才是公钥😅……最终把所有的值带进去试了一下终于没问题了最终的代码如下
```python
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所以一句
```python
hmac.new(key, data, digestmod="sm3").hexdigest()
```
就可以了但是我用的是旧版的PythonmacOS自带的3.9.6🤣不支持……那怎么办呢我看了一下这个函数的注释写的“digestmod”这个参数除了传hashlib支持的方法之外还可以传符合[PEP 247](https://peps.python.org/pep-0247/)的模块。显然无论是GmSSL-Python还是gmssl都没有符合这个规范。不过我可以自己写个适配器来适配这个规范。所以最终只好自己写一下了
```python
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算法那样偷偷插了后门 ~~(虽然我觉得他们应该没这个实力🤣)~~ ,但国际算法有后门我不怕,国内算法有后门那就吓人了🤣。