主题
SM4 输出加密
创建授权时传入 output_encryption: "SM4",可以让平台把发给你的 JSON 内容整体加密, 再装进一个固定结构里返回 —— 这个装着密文的固定结构就是下文的「SM4-GCM 信封」。
影响范围
| 报文 | 是否加密 |
|---|---|
| 回调通知 Body | ✅ |
| 订单查询 / 产品查询成功响应 | ✅ |
| V1 数据接口成功响应(绑定订单) | ✅ |
| 创建授权响应、税务表单目录 | ❌ |
| 税务大型记录块 | ✅ 使用独立 tax-large-sm4.v1 结构,须验证 AAD,见税务分页 |
| V2 发票 JSON 接口成功响应 | ✅ |
| 错误响应(4xx / 5xx,业务码失败) | ❌ 保持明文 |
| PDF 文件、授权协议、HTML 页面 | ❌ |
| Worker 原始表格文件 | ❌ |
| 发票压缩分片 | ❌ |
错误始终明文
错误响应不加密,是为了让客户在密钥配置出错时仍能定位参数与鉴权问题。
信封结构
json
{
"encrypted": true,
"algorithm": "SM4-GCM",
"version": "tax-rpa.sm4-gcm.v1",
"encoding": "BASE64",
"keyDerivation": "SHA256_CALLBACK_SECRET_FIRST_16_BYTES",
"iv": "Base64 编码的 12 字节随机 IV",
"ciphertext": "Base64 编码的 JSON 密文",
"tag": "Base64 编码的 16 字节认证标签"
}密钥派生
text
key = SHA-256(callback_secret 的 UTF-8 字节)[0:16]固定取 SHA-256 结果的前 16 字节作为 SM4 密钥。
明文是 UTF-8 JSON,序列化时使用紧凑分隔符并按对象键排序 —— 这一点只影响平台侧的确定性输出,客户端解密后正常解析即可。
解密
先验证签名,再解密
回调场景必须先对收到的原始密文信封完成 X-RPA-Signature 签名验证, 再执行 SM4-GCM 解密。顺序颠倒等于对来路不明的数据做解密运算。
解密时应先校验 GCM Tag,再解析 JSON。
Python 解密示例
python
import base64
import hashlib
import json
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
def decrypt_envelope(envelope: dict, callback_secret: str) -> dict:
key = hashlib.sha256(callback_secret.encode("utf-8")).digest()[:16]
decryptor = Cipher(
algorithms.SM4(key),
modes.GCM(
base64.b64decode(envelope["iv"]),
base64.b64decode(envelope["tag"]),
),
).decryptor()
plain = decryptor.update(base64.b64decode(envelope["ciphertext"]))
plain += decryptor.finalize() # Tag 校验失败会在这里抛异常
return json.loads(plain.decode("utf-8"))统一入口
建议在 HTTP 客户端里包一层,业务代码不感知加密开关:
python
def unwrap(body: dict, callback_secret: str) -> dict:
if isinstance(body, dict) and body.get("encrypted") is True:
return decrypt_envelope(body, callback_secret)
return body依赖
必须验证运行环境同时支持 SM4 与 GCM 认证模式。只有 SM4-ECB / SM4-CBC 的库不能解密本接口。上方 Python 代码与平台实现使用同一 cryptography 接口;发行版还须实际支持 algorithms.SM4 和 modes.GCM 的组合。
Node.js 可先用 crypto.getCiphers().includes('sm4-gcm') 检查原生能力;不能仅凭 OpenSSL 主版本推定支持。本站 Bruno 集合自带经测试的 SM4-GCM 实现,可用于联调。
下载公开解密测试向量,以其中的演示密钥解密并核对明文,再修改 Tag 验证认证失败。该文件仅用于协议测试,演示密钥和 IV 不用于真实订单。
联调时先验证算法可用性
接入前先用一段已知的 IV / 密文 / Tag 在目标语言里跑通解密, 再切换订单的 output_encryption。否则很容易把「依赖不支持 SM4」 误判成「平台返回了错误数据」。
何时启用
| 情况 | 建议 |
|---|---|
| 传输全程已走 HTTPS(TLS),且回调接收端在自己内网 | NONE 即可 |
| 回调要经过第三方网关,或日志系统会把报文写进磁盘 | SM4 |
| 合规要求业务数据在应用层加密 | SM4 |
启用与否是每个订单的选择,写在创建授权的请求体里,并且参与 重复请求的比对 —— 同一订单号不能中途改变。