easy-gmssl 2.0.1
easy gmssl for python
Requires Python: >=3.10

# EasyGmSSL for Python

**easy_gmssl** 是基于 [GmSSL](https://github.com/guanzhi/GmSSL)（北京大学 GuanZhi 老师团队开源国密算法库）的 Python 封装，提供更友好、更易用的国密算法开发接口。

- **Git 仓库**：https://github.com/bowenerchen/GmSSL-Python  
- **示例代码**：https://github.com/bowenerchen/GmSSL-Python/tree/main/demo_easy_gmssl  

---

## 一、easy_gmssl 支持的能力

| 类别 | 能力 | 说明 |
|------|------|------|
| **SM2** | 加解密 | 支持 C1C3C2、C1C3C2_ASN1、C1C2C3、C1C2C3_ASN1 多种密文格式 |
| **SM2** | 签名验签 | 支持 RS、RS_ASN1 模式，流式与一次性签名 |
| **SM2** | 证书 | X.509 证书解析、CA 验证、摘要验签 |
| **SM3** | 哈希 / HMAC / KDF | 一次性哈希 `Hash()`、流式 HMAC、SM3 KDF、PBKDF2-HMAC-SM3 |
| **SM4** | 对称加密 | CBC、CTR、GCM 模式，流式加解密 |
| **SM9** | 标识密码 | 加密（主密钥/用户密钥）、签名（主密钥/用户密钥/验签） |
| **其他** | ZUC / 随机数 | 祖冲之序列密码、安全随机数生成 |

所有对外接口统一采用 **PascalCase** 命名，便于记忆与 IDE 补全。

---

## 二、支持的系统

| 平台 | 支持情况 | 前置条件 |
|------|----------|----------|
| **Linux** | ✅ | 需安装 CMake、C 编译器 |
| **macOS** | ✅ | 需安装 CMake、Xcode Command Line Tools |
| **Windows** | ✅ | 需安装 CMake、Visual Studio Build Tools 或 MinGW |

安装时自动编译底层 C 库，并将动态库安装到 `~/.gmssl_3.1.1_install/`，不污染系统路径。

---

## 三、AI 对本版本的贡献（Vibecoding 优化 2025-02-15）

本版本在 AI 辅助下完成了 **Vibecoding 优化工程**，主要改进包括：

- **安装逻辑**：路径健壮性、cmake 可用性检查、错误输出增强、并行构建
- **跨平台**：Windows 平台 DLL 加载支持，Linux/macOS/Windows 全平台可用
- **接口补全**：EasySM3Kdf、EasySM3Pbkdf2、EasySm4CTR、EasySM3Digest.Hash
- **Bug 修复**：GetSm2PrivateKeyInHex 逻辑、IV 错误信息、GCM 参数校验、RandomData 参数顺序
- **新能力**：SM9 标识密码、SM2 证书完整封装
- **命名统一**：对外接口统一为 PascalCase（Breaking Change）
- **测试与文档**：单元测试 30+ → 68+，新增 SM9/SM2 证书 Demo

详见 `docs/VIBECODING_OPTIMIZATION_PROJECT_20250215.md`。

---

## 四、基于 GmSSL 3.1.1 及选择该版本的原因

easy_gmssl 固定基于 **GmSSL 3.1.1**，原因包括：

1. **算法覆盖完整**：3.1.1 已稳定支持 SM2、SM3、SM4、SM9、ZUC 等国密算法及 X.509 证书
2. **API 稳定**：该版本接口稳定，便于长期封装与维护
3. **版本锁定**：固定版本可避免上游变更带来的兼容性问题，保证 `pip install` 行为可预期

安装时会将 GmSSL 3.1.1 源码编译并安装至 `~/.gmssl_3.1.1_install/`，与 `gmssl.py` 的加载路径一致。

---

## 五、为什么有了 GmSSL 还要做 easy_gmssl？

GmSSL 是 C 库，直接使用需要处理编译、链接、ctypes 绑定等。easy_gmssl 在此基础上提供：

1. **一键安装**：`pip install easy_gmssl` 即可，自动完成 GmSSL 编译与安装
2. **更友好的 API**：面向 Python 的类封装，参数说明清晰，降低使用门槛
3. **调试能力**：支持 SM2 多种密文格式输出、公钥/私钥十六进制读取，便于调试与密钥管理
4. **模式扩展**：SM2 加解密多种格式、签名 RS/RS_ASN1 模式，适配不同业务需求
5. **接口统一**：PascalCase 命名、流式与一次性接口并存，符合 Python 使用习惯

---

## 六、特色功能

1. **便捷安装**
    - 在通过pip安装本SDK时，具备自动编译底层C库的能力，并且会智能地安装编译好的二进制文件，避免对系统路径造成污染，确保了安装过程的简洁性与独立性，让您无需繁琐的手动配置即可快速上手。

2. **SM2增强功能**
    - **密钥加解密模式多样化**
      新增了多种SM2密钥加解密模式选择，包括C1C3C2、C1C3C2_ASN1、C1C2C3、C1C2C3_ASN1。这些模式为不同应用需求提供了更灵活的加密策略，无论是在对加密效率有要求，还是对加密数据格式兼容性有考量的场景下，都能找到合适的解决方案。

    - **签名验签模式扩展**
      在SM2签名验签时，增加了RS_ASN1、RS两种模式选择，适应不同的签名规范和验证场景，使签名验签操作更加贴合实际业务需求。

    - **密钥读取便捷化**
      允许用户轻松读取SM2公钥、私钥的十六进制明文，方便在调试、密钥管理等环节快速获取关键信息，提升开发效率。

3. **基础算法优化**

   对于SM4和SM3以及随机数生成部分，虽然核心算法基于底层库，但在接口层着重增加了参数说明。这使得即使是初次接触国密算法的开发者，也能迅速理解每个参数的含义与用途，降低了开发门槛，加速项目开发进程。

## 七、安装指南

只需在命令行中执行以下pip命令即可完成安装：

```bash
pip install easy_gmssl
```

安装过程中，系统会自动处理底层C库的编译与安装事宜，待编译安装完成后即可开启国密算法开发之旅。

## 八、使用示例

1. **SM2密钥加解密**
    - 输出多种模式下的密文：
   ```python
   from __future__ import annotations
   
   from easy_gmssl import EasySm2EncryptionKey, SM2CipherFormat, SM2CipherMode
   
   enc = EasySm2EncryptionKey()
   plain = 'hello,world'
   # 遍历当前支持的所有 SM2 加解密算法模式
   # 当前支持的模式包括：
   # C1C3C2_ASN1、C1C3C2、C1C2C3_ASN1、C1C2C3
   for mode in SM2CipherMode:
       print(mode, '密文 in Hex:', enc.Encrypt('hello,world'.encode('utf-8'), mode, SM2CipherFormat.HexStr))
   ```

2. **SM2公钥、私钥读取**
   ```python
   from __future__ import annotations
   
   from easy_gmssl import EasySm2Key
   
   test = EasySm2Key()
   print('公钥数据 In Hex:', test.GetSm2PublicKeyInHex())
   print('私钥数据 In Hex:', test.GetSm2PrivateKeyInHex())
   ```

3. **SM2签名验签**

    - 以RS_ASN1模式为例：
   ```python
   from __future__ import annotations
   
   import random
   
   from easy_gmssl import EasySM2SignKey, EasySM2VerifyKey, SignatureMode
   
   signer_id = 'test_signer'
   print('signer_id hex:', signer_id.encode('utf-8').hex())
   # 初始化用于签名验签的 SM2 密钥，此时不需要关心签名值的模式
   test = EasySM2SignKey(signer_id = signer_id, pem_private_key_file = './test_keys/tmp_test_sm2_private.pem',
                         password = '123456')
   plain = bytes([random.randint(0, 255) for _ in range(0, 64)])
   print('plain hex:', plain.hex())
   print('private key hex:', test.GetSm2PrivateKeyInHex())
   print('public key hex:', test.GetSm2PublicKeyInHex())
   
   # 计算签名
   test.UpdateData(plain)
   # 指定签名值模式为 RS 模式，可选 RS、RS_ASN1
   sign_value = test.GetSignValue(signature_mode = SignatureMode.RS)
   print('signature hex:', sign_value.hex())
   
   # 初始化用于验证签名的 SM2 密钥
   verify_test = EasySM2VerifyKey(signer_id = signer_id, pem_public_key_file = './test_keys/tmp_test_sm2_public.pem')
   # 验证签名
   verify_test.UpdateData(plain)
   # 验证签名时同样指定签名值格式为 RS 模式
   ret = verify_test.VerifySignature(sign_value, signature_mode = SignatureMode.RS)
   ```

4. **SM3 哈希、KDF 与 PBKDF2**
   ```python
   from easy_gmssl import EasySM3Digest, EasySM3Kdf, EasySM3Pbkdf2
   from easy_gmssl.gmssl import SM3_PBKDF2_MIN_ITER

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

   # SM3 KDF 密钥派生
   kdf = EasySM3Kdf(outlen=16)
   kdf.UpdateData(b'shared_secret')
   key, _ = kdf.GetKey()

   # PBKDF2-HMAC-SM3
   dk = EasySM3Pbkdf2.DeriveKey('password', b'salt', SM3_PBKDF2_MIN_ITER, 32)
   ```

5. **SM4-CBC / SM4-GCM / SM4-CTR**
   ```python
   from easy_gmssl import EasySm4CBC, EasySm4GCM, EasySm4CTR
   from easy_gmssl.gmssl import SM4_BLOCK_SIZE, SM4_CBC_IV_SIZE, SM4_CTR_IV_SIZE

   key = b'x' * SM4_BLOCK_SIZE
   iv = b'y' * SM4_CBC_IV_SIZE
   enc = EasySm4CBC(key, iv, True)
   cipher = enc.Update(b'plain') + enc.Finish()

   # SM4-CTR 密文与明文等长
   iv_ctr = b'z' * SM4_CTR_IV_SIZE
   ctr = EasySm4CTR(key, iv_ctr)
   out = ctr.Update(b'data') + ctr.Finish()
   ```

6. **ZUC 与随机数**
   ```python
   from easy_gmssl import EasyZuc, EasyRandomData, RandomMode
   from easy_gmssl.gmssl import ZUC_KEY_SIZE, ZUC_IV_SIZE

   key = EasyRandomData().GetRandomData(ZUC_KEY_SIZE)
   iv = EasyRandomData().GetRandomData(ZUC_IV_SIZE)
   zuc = EasyZuc(key, iv)
   cipher = zuc.Update(b'plain') + zuc.Finish()
   ```

7. **SM9 标识密码（加密与签名）**
   ```python
   from easy_gmssl import EasySM9EncMasterKey, EasySM9EncKey, EasySM9SignMasterKey, EasySM9SignKey, EasySM9VerifyKey

   # SM9 加密：KGC 生成主密钥，提取用户私钥，加密方用公钥加密，接收方用私钥解密
   enc_master = EasySM9EncMasterKey()
   enc_master.GenerateMasterKey()
   user_key = enc_master.ExtractKey('alice@example.com')
   cipher = enc_master.Encrypt(b'hello', 'alice@example.com')
   plain = user_key.Decrypt(cipher)

   # SM9 签名：KGC 生成主密钥，提取用户签名私钥，验签方用主密钥公钥验签
   sign_master = EasySM9SignMasterKey()
   sign_master.GenerateMasterKey()
   sign_key = sign_master.ExtractKey('bob@example.com')
   sig = sign_key.Sign(b'data')
   verify_key = EasySM9VerifyKey('bob@example.com', 'sm9_sign_public.pem')
   ok = verify_key.Verify(b'data', sig)
   ```

8. **SM2 证书（X.509 解析与验证）**
   ```python
   from easy_gmssl import EasySm2Certificate
   from easy_gmssl.gmssl import SM2_DEFAULT_ID

   cert = EasySm2Certificate(pem_file='cert.pem')
   print('Serial:', cert.GetSerialNumber().hex())
   print('Subject:', cert.GetSubject())
   print('Validity:', cert.GetValidity().not_before, '-', cert.GetValidity().not_after)
   ok = cert.VerifyByCaCertificate(ca_cert, SM2_DEFAULT_ID)
   ok2 = cert.VerifyDigestWithSubjectKey(digest, signature)
   ```

## 九、API 接口一览

| 模块 | 类/函数 | 说明 |
|------|---------|------|
| SM2 | `EasySm2Key` | 密钥管理、PEM 导入导出 |
| SM2 | `EasySm2EncryptionKey` | 加解密（多种密文格式） |
| SM2 | `EasySM2SignKey` / `EasySM2VerifyKey` | 签名验签 |
| SM2 | `EasySm2Certificate` | X.509 证书解析与 CA 验证 |
| SM3 | `EasySM3Digest` | 哈希（含 `Hash()` 一次性） |
| SM3 | `EasySM3Hmac` | HMAC |
| SM3 | `EasySM3Kdf` | SM3 密钥派生 |
| SM3 | `EasySM3Pbkdf2` | PBKDF2-HMAC-SM3（`DeriveKey()`） |
| SM4 | `EasySm4CBC` / `EasySm4CTR` / `EasySm4GCM` | 对称加密 |
| SM9 | `EasySM9EncMasterKey` / `EasySM9EncKey` | 标识密码加密 |
| SM9 | `EasySM9SignMasterKey` / `EasySM9SignKey` / `EasySM9VerifyKey` | 标识密码签名 |
| 其他 | `EasyZuc` | 祖冲之序列密码 |
| 其他 | `EasyRandomData` | 随机数生成 |

更多示例见 `easy_gmssl/demo_easy_gmssl/` 目录。

## 十、注意事项

1. 在使用 SM2 密钥加解密、签名验签等功能时，请务必根据实际需求谨慎选择合适的模式，不同模式在数据格式、兼容性等方面存在差异。
2. 对于读取的公钥、私钥十六进制明文，要妥善保管，防止泄露，因为这是加密体系的核心机密信息。
3. 虽然SDK尽力优化了接口，但国密算法涉及密码学专业知识，在开发高安全性应用时，建议开发者深入了解相关算法原理，确保应用的安全性。