SM2/SM4 怎么使用?(附代码与问答)
目录导读
- 国密算法背景与必要性
- SM2 非对称加密:原理与典型用法
- SM2 密钥生成
- SM2 加密/解密流程
- SM2 签名/验签示例
- SM4 对称加密:原理与典型用法
- SM4 加密模式选择(ECB/CBC/GCM)
- SM4 加解密代码实战
- SM2 + SM4 混合加密体系(推荐方案)
- 为什么需要混合加密?
- 混合加密完整流程与代码片段
- 常见问题与深度问答(不低于3组)
- 总结与最佳实践建议
国密算法背景与必要性
SM2(椭圆曲线公钥密码算法)与 SM4(分组对称密码算法)是我国国家密码管理局发布的商用密码标准,广泛应用于政务、金融、物联网等需要合规密码技术的领域,自2020年起,中国关键信息基础设施必须采用国密算法,因此掌握 SM2/SM4 怎么使用 成为开发者的必备技能。

核心区别:
- SM2(公钥体系):用于数字签名、密钥交换、加密(性能低,适合小数据)。
- SM4(对称体系):用于大量数据加密(性能高,需安全分发密钥)。
SM2 非对称加密:原理与典型用法
1 SM2 密钥生成
SM2 基于椭圆曲线(推荐曲线参数为 sm2p256v1),使用 Python 的 gmssl 库(或 Java 的 BouncyCastle)生成密钥对:
from gmssl import sm2 # 生成私钥(十六进制字符串)与公钥 private_key = '...' # 实际应由库生成 public_key = '...' # 推荐直接使用库函数: sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key)
注意: 私钥长度固定为 32 字节,公钥为 64 字节(未压缩形式)。
2 SM2 加密与解密
SM2 加密时自动加入随机数,确保每次密文不同。
data = b"Hello National Secret" enc_data = sm2_crypt.encrypt(data) dec_data = sm2_crypt.decrypt(enc_data) print(dec_data.decode()) # 输出:Hello National Secret
3 SM2 签名与验签
sign = sm2_crypt.sign(data, random_hex='...') # 随机数应严格安全 assert sm2_crypt.verify(sign, data) # 验签通过
SM4 对称加密:原理与典型用法
1 加密模式选择
SM4 标准分组大小为 128 位,推荐以下模式:
| 模式 | 用途 | 说明 |
|---|---|---|
| ECB | 不推荐 | 相同明文输出相同密文,泄露模式 |
| CBC | 通用 | 需要初始向量(IV),并行解密 |
| GCM | 推荐 | 认证加密(AAD),自带完整性校验 |
2 SM4-CBC 示例(Python)
from gmssl import sm4 key = b'0123456789abcdeffedcba9876543210' # 16字节密钥 iv = b'0000000000000000' # 16字节初始向量 crypt_sm4 = sm4.CryptSM4(mode=sm4.SM4_ENCRYPT) crypt_sm4.set_key(key, iv) enc_data = crypt_sm4.crypt(b"Secret Data") crypt_sm4_dec = sm4.CryptSM4(mode=sm4.SM4_DECRYPT) crypt_sm4_dec.set_key(key, iv) dec_data = crypt_sm4_dec.crypt(enc_data)
注意: 实际生产务必使用 GCM 模式或 CBC+HMAC 防止篡改。
SM2 + SM4 混合加密体系
1 为什么要混合加密?
- 性能问题: SM2 加密 100KB 数据耗时约 500ms,不可接受。
- 密钥分发: SM4 密钥需安全传输,SM2 恰好解决此问题。
方案:
- 发送方:生成随机 SM4 会话密钥(16字节),用 SM2 公钥加密该会话密钥。
- 发送方:用 SM4 密钥加密实际消息(大数据)。
- 接收方:用 SM2 私钥解密得到会话密钥,再用该密钥解密消息。
2 混合加密代码片段
# 发送方 session_key = os.urandom(16) enc_session_key = sm2_crypt.encrypt(session_key) # SM2 加密会话密钥 cipher_sm4 = sm4.CryptSM4(mode=sm4.SM4_ENCRYPT) cipher_sm4.set_key(session_key, iv) ciphertext = cipher_sm4.crypt(plaintext) # SM4 加密大数据 # 传输 enc_session_key + ciphertext + iv # 接收方 session_key = sm2_crypt.decrypt(enc_session_key) # SM2 解密会话密钥 cipher_sm4_dec = sm4.CryptSM4(mode=sm4.SM4_DECRYPT) cipher_sm4_dec.set_key(session_key, iv) plaintext = cipher_sm4_dec.crypt(ciphertext)
常见问题与深度问答
Q1:SM2 和 SM4 能否替换 RSA 与 AES?
A: 可以,且国密合规,但注意:
- SM2 性能优于 RSA 2048,密钥更短(256位 vs 2048位)。
- SM4 与 AES 安全性同级别(AES-128 对应 SM4-128),但 SM4 硬件加速尚未普及。
- 迁移成本: 银行核心系统已完成替换,物联网场景建议优先选用。
Q2:SM4 的 GCM 模式为什么推荐?
A: GCM 同时提供加密与完整性校验(类似 AES-GCM),避免 CBC 模式下“密文替换/填充预言攻击”。
使用示例(需扩展 gmssl 或改用 pysmx 库):
# 伪代码示意 tag = sm4_gcm_encrypt(key, iv, aad, plaintext) # tag 用于验签 # 解密时验证 tag 是否一致,否则返回失败
Q3:SM2 签名时为什么要提供随机数?
A: SM2 签名算法基于 ECDSA,随机数 k 必须唯一、不可预测。
若随机数重复或已知,攻击者可推导出私钥(如索尼 PS3 签名泄露事件)。
最佳实践: 使用 secrets.randbelow() 或硬件真随机数生成器(TRNG)。
Q4:如何保证 SM4 密钥的安全存储?
A:
- 生产环境密钥使用硬件安全模块(HSM)或密钥管理系统(KMS)。
- 代码中不硬编码密钥,通过环境变量或配置中心(如 etcd)注入。
- SM4 会话密钥仅存于内存,使用后立即
memset清零(Python 可用ctypes手动清理)。
总结与最佳实践建议
- 合规第一: 政务云、金融系统必须使用国密,且通过 GM/T 测试。
- 混合加密必然: 小数据用 SM2,大数据用 SM4,二者结合。
- 模式选择: SM4 优先选 GCM(带认证),拒绝 ECB。
- 库备选方案: Python 选
gmssl(功能全但性能一般)或pysmx(C扩展,快百倍);Java 用BouncyCastle国密插件。 - 调试技巧: 使用在线国密工具(如
gmssl.cn)验证加解密结果一致性。
行动清单:
- [ ] 生成 SM2 密钥对,完成加密解密测试。
- [ ] 实现 SM4-GCM 加密并验证完整性。
- [ ] 搭建混合加密 demo,传输 10KB 数据验证性能。
掌握 SM2/SM4 不仅是技术升级,更是国家网络安全战略的基石,立即动手,让你的应用从“能用”走向“合规、安全”。