本文档整合 2025-02-15 对 easy_gmssl 的完整 Vibecoding 优化实践,涵盖安装逻辑、Windows 平台支持、接口补全、Bug 修复、SM9/SM2 证书封装、命名风格统一、测试与文档增强,可作为国密算法库封装与测试的参考。


目录

  1. 总览与目标
  2. 安装逻辑优化
  3. Windows 平台支持
  4. 接口补全与 Bug 修复
  5. SM9 标识密码与 SM2 证书
  6. 接口命名风格统一
  7. 单元测试与 Demo 增强
  8. 变更日志与迁移指南
  9. 完整修改文件清单

一、总览与目标

easy_gmssl 是对 GmSSL 的 Python 接口封装库,在底层 C 库基础上提供更友好的 API,并增加了国密调试能力(如 SM2 多种密文格式输出)。

本次 Vibecoding 优化工程的目标:

模块目标
安装逻辑提升 setup.py 健壮性、可维护性与错误可诊断性
跨平台支持 Windows 平台 pip 安装与运行时库加载
接口补全封装 gmssl 已提供但 easy_gmssl 未暴露的接口
Bug 修复修正逻辑错误、参数校验、错误信息等问题
新能力SM9 标识密码、SM2 证书完整封装
命名统一对外接口统一为驼峰风格(PascalCase)
测试提升单元测试覆盖度,明确测试目标与边界
文档完善 demo 示例、README、TEST_README

重要约束:easy_gmssl 是对 GmSSL 3.1.1 固定执行版本的封装,本次优化不涉及依赖版本变更。


二、安装逻辑优化

2.1 背景

easy_gmssl 的核心优势之一是将 GmSSL 复杂的安装步骤封装为一条 pip install easy_gmssl 即可完成。本次对安装逻辑进行 review,在不改变依赖版本的前提下,提升安装步骤的健壮性、可维护性与错误可诊断性。

2.2 Review 结论

保持不变的部分

项目说明
GmSSL 版本固定为 3.1.1
安装目录~/.gmssl_3.1.1_install/,与 gmssl.py 中加载动态库的路径一致
CMake 参数CMAKE_INSTALL_PREFIXBUILD_SHARED_LIBS 逻辑不变
构建流程配置 → 构建 → 安装,整体流程不变

发现的问题

问题影响
路径依赖 cwdopen('./easy_gmssl/README.md')easy_gmssl/Core/GmSSL-3.1.1 依赖当前工作目录,在 pip install 等场景下可能解析错误
未设置 CMAKE_BUILD_TYPE单配置生成器(Unix Makefiles/Ninja)下默认可能为 Debug 或空,影响构建类型
无 cmake 可用性检查缺少 cmake 时直接失败,错误信息不明确
错误信息不足subprocess.check_call 失败时无 stderr/stdout 输出,难以排查
跨平台路径home_directory.endswith('/') 硬编码,未使用 os.sep

2.3 优化内容

路径健壮性

新增 _get_project_root():基于 os.path.dirname(os.path.abspath(__file__)) 获取项目根目录,确保无论从何处执行 setup.py 路径都正确。

1
2
3
def _get_project_root():
    """获取项目根目录,确保无论从何处执行 setup.py 路径都正确"""
    return os.path.dirname(os.path.abspath(__file__))

应用位置

  • GmSSL 源码路径:os.path.join(_get_project_root(), "easy_gmssl", "Core", "GmSSL-3.1.1")
  • README 路径:os.path.join(_get_project_root(), "easy_gmssl", "README.md")

long_description 安全读取

新增 _read_long_description():使用绝对路径读取 easy_gmssl/README.md,避免依赖 cwd;文件不存在时返回空字符串,防止 metadata 读取失败。

CMAKE_BUILD_TYPE

新增 -DCMAKE_BUILD_TYPE=Release:单配置生成器在配置阶段需要指定构建类型,否则默认可能为空或 Debug。

cmake 可用性检查

新增 _ensure_cmake_available():在构建前使用 shutil.which("cmake") 检查 cmake 是否在 PATH 中;若未找到,抛出 RuntimeError 并给出各平台的安装提示。

错误处理增强

subprocess.check_call 改为 subprocess.run:捕获 stderrstdout,失败时在 RuntimeError 中输出完整命令、退出码及 cmake 输出,便于排查。

跨平台路径

使用 os.sep:将 home_directory.endswith('/') 改为 home_directory.endswith(os.sep),适配不同操作系统的路径分隔符。

常量集中管理

新增 _GMSSL_VERSION_GMSSL_INSTALL_DIR:将安装目录名提取为常量,并注释说明需与 gmssl.py 中加载路径保持一致。

2.4 优化前后对比

项目优化前优化后
项目根目录依赖 cwd_get_project_root() 基于 __file__
long_descriptionopen('./easy_gmssl/README.md')_read_long_description() 绝对路径
CMAKE_BUILD_TYPE未设置-DCMAKE_BUILD_TYPE=Release
cmake 检查_ensure_cmake_available()
错误输出无 stderr/stdout完整命令 + stderr + stdout
路径分隔符endswith('/')endswith(os.sep)
安装目录常量硬编码_GMSSL_INSTALL_DIR

2.5 Windows 平台支持

背景

此前 gmssl.py 仅显式处理 Linux 与 macOS 的库加载路径,Windows 会落入 find_library("gmssl") 回退逻辑。由于 pip 安装时 DLL 位于 ~/.gmssl_3.1.1_install/bin/,不在系统 PATH 中,导致 Windows 上安装后无法加载库。

优化内容

gmssl.py 动态库加载

  • 新增 is_win = sys.platform == "win32" 平台检测
  • 使用 os.path.join 替代字符串拼接,保证跨平台路径正确
  • 为 Windows 增加显式加载逻辑:从 ~/.gmssl_3.1.1_install/bin/gmssl.dll 加载(CMake 在 Windows 下将 DLL 安装到 bin 目录)
  • 对未知平台抛出明确 ValueError,便于排查
  • 移除冗余的 finally: pass

setup.py classifiers

  • 新增 PyPI 平台分类:Operating System :: OS IndependentOperating System :: Microsoft :: WindowsOperating System :: POSIX :: LinuxOperating System :: MacOS

各平台库路径对照

平台动态库路径
Linux~/.gmssl_3.1.1_install/lib/libgmssl.so.3.1
macOS~/.gmssl_3.1.1_install/lib/libgmssl.3.1.dylib
Windows~/.gmssl_3.1.1_install/bin/gmssl.dll

Windows 安装前置条件

  1. 安装 CMake
  2. 安装 C 编译器:Visual Studio Build Tools 或 MinGW
  3. 执行 pip install easy_gmssl

三、接口补全与 Bug 修复

3.1 gmssl 接口封装审查

已封装接口(完整覆盖核心能力)

gmssl 底层easy_gmssl 封装状态
rand_bytesEasyRandomData.GetRandomData
Sm3EasySM3Digest
Sm3HmacEasySM3Hmac
Sm3KdfEasySM3Kdf
sm3_pbkdf2EasySM3Pbkdf2.DeriveKey
Sm4CbcEasySm4CBC
Sm4CtrEasySm4CTR
Sm4GcmEasySm4GCM
ZucEasyZuc
Sm2KeyEasySm2Key, EasySm2EncryptionKey
Sm2SignatureEasySM2SignKey, EasySM2VerifyKey
Sm9EasySM9EncMasterKey, EasySM9EncKey 等✅ (2025-02-15)
Sm2CertificateEasySm2Certificate✅ (2025-02-15)

本次补全的遗漏项

遗漏项补全方案
SM3 KDF在 gmssl.py 中绑定 Sm3Kdfsm3_kdf_init/update/finish,新增 EasySM3Kdf
PBKDF2-HMAC-SM3封装已有 sm3_pbkdf2EasySM3Pbkdf2.DeriveKey()
SM4-CTR封装 Sm4CtrEasySm4CTR
SM3 一次性哈希EasySM3Digest 中增加静态方法 Hash(data)

3.2 Bug 修复

GetSm2PrivateKeyInHex 逻辑错误

问题:仅加载公钥时,GetSm2PrivateKeyInHex() 仍可能返回私钥(因误用 has_public_key() 判断)。

修复:改为使用 has_private_key() 判断。

EasySm4CBC / EasySm4GCM IV 错误信息

问题:IV 长度校验失败时,错误信息中误用 len(key) 而非 len(iv)

修复:统一为 len(iv)

EasySm4GCM 参数校验过严

问题:GCM 的 iv 被限制为 16 字节,tag_len 被限制为 816。而 GmSSL 支持 iv 164 字节、tag_len 1~16 字节。

修复:按 GmSSL 规范调整校验范围。

EasyRandomData 参数校验顺序

问题GetRandomData(0) 时先调用 rand_bytes(0) 再检查长度,可能产生未定义行为。

修复:先校验 length >= 1,再调用 rand_bytes

3.3 新增接口使用示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# EasySM3Kdf - 流式输入、固定输出长度
kdf = EasySM3Kdf(outlen=16)
kdf.UpdateData(b"shared_secret")
key, data_len = kdf.GetKey()

# EasySM3Pbkdf2 - 从密码派生密钥
dk = EasySM3Pbkdf2.DeriveKey(
    password="pwd",
    salt=b"randomsalt",
    iterations=10000,
    keylen=32,
)

# EasySm4CTR - SM4-CTR 流式加解密
ctr = EasySm4CTR(key, iv)
cipher = ctr.Update(plain) + ctr.Finish()

# EasySM3Digest.Hash - 一次性 SM3 哈希
h = EasySM3Digest.Hash(b"hello,world")

四、SM9 标识密码与 SM2 证书

4.1 SM9 标识密码

新增类与说明

类名说明
EasySM9EncMasterKeySM9 加密主密钥(KGC 持有),支持主密钥生成、用户密钥提取、加密、PEM 导入导出
EasySM9EncKeySM9 用户加密私钥,支持解密、PEM 导入导出
EasySM9SignMasterKeySM9 签名主密钥(KGC 持有),支持主密钥生成、用户签名密钥提取、PEM 导入导出
EasySM9SignKeySM9 用户签名私钥,支持 Sign() 一次性签名、UpdateData+GetSignValue 流式签名、PEM 导入导出
EasySM9VerifyKeySM9 验签,仅需主密钥公钥与签名者标识,支持 Verify() 一次性验签、UpdateData+VerifySignature 流式验签

参数边界

  • 标识(identity):1 ~ 63 字节(SM9_MAX_ID_SIZE)
  • 明文:1 ~ 255 字节(SM9_MAX_PLAINTEXT_SIZE)
  • 密码:1 ~ 32 字节

使用示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# SM9 加密
from easy_gmssl import EasySM9EncMasterKey, EasySM9EncKey

master = EasySM9EncMasterKey()
master.GenerateMasterKey()
user_key = master.ExtractKey('alice@example.com')
cipher = master.Encrypt(b'hello', 'alice@example.com')
plain = user_key.Decrypt(cipher)

# SM9 签名
from easy_gmssl import EasySM9SignMasterKey, EasySM9SignKey, EasySM9VerifyKey

master = EasySM9SignMasterKey()
master.GenerateMasterKey()
sign_key = master.ExtractKey('bob@example.com')
master.ExportPublicKeyToPem('pub.pem')
sig = sign_key.Sign(b'data')
verify_key = EasySM9VerifyKey('bob@example.com', 'pub.pem')
ok = verify_key.Verify(b'data', sig)

4.2 SM2 证书

新增类与说明

类名说明
EasySm2CertificateSM2 X.509 证书封装,支持 ImportPem、ExportPem、GetSerialNumber、GetIssuer、GetSubject、GetSubjectPublicKey、GetValidity、VerifyByCaCertificate、VerifyDigestWithSubjectKey

使用示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from easy_gmssl import EasySm2Certificate
from easy_gmssl.gmssl import SM2_DEFAULT_ID

cert = EasySm2Certificate(pem_file='cert.pem')
serial = cert.GetSerialNumber()
issuer = cert.GetIssuer()
subject = cert.GetSubject()
validity = cert.GetValidity()
pub_key = cert.GetSubjectPublicKey()
ok = cert.VerifyByCaCertificate(ca_cert, SM2_DEFAULT_ID)
ok2 = cert.VerifyDigestWithSubjectKey(digest, signature)

4.3 Demo 文件

文件说明
demo_easy_gmssl/sm9_encryption.pySM9 加密完整流程
demo_easy_gmssl/sm9_sign.pySM9 签名完整流程
demo_easy_gmssl/sm2_certificate.pySM2 证书解析与验证
demo_easy_gmssl/sm3_kdf_pbkdf2.pySM3 KDF 与 PBKDF2 使用示例
demo_easy_gmssl/sm4_ctr.pySM4-CTR 加解密示例

五、接口命名风格统一

5.1 背景

easy_gmssl 对外接口存在 snake_case 与 PascalCase 混用的情况。本次统一对外暴露的公共方法采用 驼峰命名(PascalCase),与 EasySM2SignKey、EasySm4CBC 等已有风格保持一致。

5.2 具体变更(Breaking Change)

EasySm2Key

原方法名(snake_case)新方法名(PascalCase)
reset_keyResetKey
new_keyNewKey
export_to_pem_fileExportToPemFile
load_sm2_pub_keyLoadSm2PubKey
load_sm2_private_keyLoadSm2PrivateKey
get_sm2_public_key_in_hexGetSm2PublicKeyInHex
get_sm2_private_key_in_hexGetSm2PrivateKeyInHex
get_point_in_hexGetPointInHex
get_zGetZ
sign_digestSignDigest
verify_digest_signatureVerifyDigestSignature

EasySM3Digest

原方法名新方法名
hash (静态方法)Hash

EasySM3Pbkdf2

原方法名新方法名
derive_key (静态方法)DeriveKey

其他模块

  • EasySm2EncryptionKey:Encrypt、Decrypt(已是驼峰,未变更)
  • EasySM2SignKey / EasySM2VerifyKey:UpdateData、GetSignValue、VerifySignature(已是驼峰)
  • EasySM3Digest / EasySM3Hmac / EasySM3Kdf:UpdateData、Reset、GetHash、GetHmac、GetKey(已是驼峰)
  • EasySm4CBC / EasySm4CTR / EasySm4GCM:Update、Finish(已是驼峰)
  • EasyZuc:Update、Finish(已是驼峰)
  • EasyRandomData:GetRandomData(已是驼峰)

六、单元测试与 Demo 增强

6.1 测试文档化

每个测试文件增加模块级 docstring,说明:

  • 测试目标:覆盖的功能与场景
  • 参数边界:关键参数的合法范围
  • 运行预期:正常路径与异常路径的预期结果

6.2 用例数量与覆盖

模块原用例现用例新增重点
SM2 Key1117GetZ、export 空前缀、无公钥加密、SignDigest 非法长度
SM2 Sign46错误签名、RS 模式长度校验
SM3714空输入、HMAC Reset、PBKDF2 边界
SM4711GCM iv/tag_len 边界、CTR key 校验
ZUC14key/iv 长度、空输入
Random15length=0/-1、随机性
SM9-11加密、签名、PEM、边界、异常
SM2 Certificate-4导入、解析、CA 验证、验签

合计:30+ → 68+ 个用例

6.3 边界与异常用例设计

  • SM2:明文 256 字节、密文 367 字节、空密码、密码 33 字节、无公钥加密、无私钥解密
  • SM3:HMAC 密钥 15/65 字节;PBKDF2 salt 65、iter 9999/16777217、keylen 257
  • SM4:GCM iv 0/65、tag_len 0/17;CTR key/iv 15 字节
  • SM9:空明文、超长明文、超长标识、空密码
  • ZUC:key/iv 15 字节
  • Random:length 0、-1

6.4 运行方式

1
2
3
4
5
6
7
8
# pytest
python -m pytest easy_gmssl/ -v

# unittest
python -m unittest discover -s easy_gmssl -p '*_test.py' -v

# 脚本
./run_unittest.sh

七、变更日志与迁移指南

7.1 迁移指南

若您此前使用了 snake_case 方法名,请按上表替换为新方法名。例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 旧代码
test = EasySm2Key()
pub = test.get_sm2_public_key_in_hex()
test.load_sm2_pub_key("pub.pem")
h = EasySM3Digest.hash(b"data")
dk = EasySM3Pbkdf2.derive_key("pwd", b"salt", 10000, 32)

# 新代码
test = EasySm2Key()
pub = test.GetSm2PublicKeyInHex()
test.LoadSm2PubKey("pub.pem")
h = EasySM3Digest.Hash(b"data")
dk = EasySM3Pbkdf2.DeriveKey("pwd", b"salt", 10000, 32)

7.2 验证

  • python setup.py egg_info:正常完成
  • python setup.py build_ext:cmake 配置与编译可正常完成
  • 在正常环境下执行 pip install easy_gmssl 时,安装流程应能顺利完成

八、完整修改文件清单

8.1 安装与构建

文件变更类型
setup.py路径健壮性、CMAKE_BUILD_TYPE、cmake 检查、错误处理、常量管理、Windows 平台 classifiers

8.2 核心库

文件变更类型
gmssl.py新增 Sm3Kdf 绑定;Windows 平台 DLL 加载、os.path.join 跨平台路径
easy_sm2_key.py修复 GetSm2PrivateKeyInHex、方法重命名
easy_sm2_sign_key.py内部调用 LoadSm2PubKey、LoadSm2PrivateKey
easy_sm3_key.py新增 EasySM3Kdf、EasySM3Pbkdf2、Hash()、方法重命名
easy_sm4_key.py修复 IV 校验、新增 EasySm4CTR
easy_random_data.py修复 GetRandomData 参数校验顺序
easy_sm9_key.py新增
easy_sm2_certificate.py新增
__init__.py导出新接口

8.3 测试

文件变更类型
easy_sm2_key_test.py重写并增强,17 用例
easy_sm2_sign_test.py重写并增强,6 用例
easy_sm3_key_test.py重写并增强,14 用例
easy_sm4_test.py重写并增强,11 用例
easy_zuc_test.py重写并增强,4 用例
easy_random_data_test.py重写并增强,5 用例
easy_sm9_test.py新增,11 用例
easy_sm2_certificate_test.py新增,4 用例

8.4 Demo 与文档

文件变更类型
demo_easy_gmssl/sm3_kdf_pbkdf2.py新增
demo_easy_gmssl/sm4_ctr.py新增
demo_easy_gmssl/sm9_encryption.py新增
demo_easy_gmssl/sm9_sign.py新增
demo_easy_gmssl/sm2_certificate.py新增
demo_easy_gmssl/sm2_encryption_decryption.py示例更新
demo_easy_gmssl/sm2_sign.py示例更新
README.md补充示例与 API 说明
easy_gmssl/README.md示例更新
TEST_README.md新增/更新
run_unittest.sh更新为支持 pytest / unittest

8.5 相关文件说明

  • setup.py:安装逻辑主文件,含 Windows 平台 PyPI classifiers
  • easy_gmssl/gmssl.py:运行时加载 ~/.gmssl_3.1.1_install/ 下的动态库(Linux/macOS 为 lib/,Windows 为 bin/),安装目录名需与 setup.py 保持一致

九、实践要点小结

  1. 安装健壮性:基于 __file__ 获取项目根目录,避免 cwd 依赖;增加 cmake 可用性检查与详细错误输出。
  2. 跨平台支持:gmssl.py 显式处理 Linux、macOS、Windows 的库加载路径;使用 os.path.join 保证路径正确;Windows 下 DLL 位于 bin/ 目录。
  3. 接口补全:对照底层库 API 逐项检查,对未封装能力补充封装并保持风格一致。
  4. Bug 修复:关注条件判断(如 has_private_key vs has_public_key)、错误信息准确性、参数校验顺序。
  5. 测试文档化:为每个用例写明测试目标、参数边界和预期结果,便于维护和回归。
  6. 边界用例:对长度、范围、空值等边界设计专门用例,提高健壮性。
  7. Demo 与文档:新接口配套示例和 README 更新,降低使用门槛。
  8. 命名统一:对外接口统一为 PascalCase,提升 API 一致性。