奥兹米奇orzmic
837.95M · 2025-09-13
本文记录了某接口调用过程中,如何基于 SM2 签名 与 SM4 加密 完成数据请求的流程。为安全起见,涉及的密钥参数已做脱敏处理。
private static String url = "http://xx.xx.xx.xx:8083/epc/api";
private static String appSecret = "****";
private static String appId = "****";
private static String publicKey = "****";
private static String privateKey = "****";
private static String path = "/fixmedins/hospRxDetlQuery";
signstr
signData
、encData
、extra
appSecret
到最后的 key
字段示例入参:
{
"certno": "612*****316",
"drCode": "D610****06954",
"fixmedinsCode": "H610****0077",
"fixmedinsName": "某某医院",
"hiRxno": "610700022**********45233982978",
"mdtrtId": "1274753890",
"patnName": "张三",
"pharCertType": "01",
"pharCertno": "21233121",
"pharChkTime": "2025-08-27 17:57:59",
"pharCode": "111",
"pharDeptCode": "A50.04",
"pharDeptName": "儿一科",
"pharName": "李四",
"pharProfttlCodg": "1",
"pharProfttlName": "执业药师",
"prscDrName": "王五",
"psnCertType": "01",
"rxTraceCode": "612*****261"
}
拼接后的 signstr
:
appId=****&data={...}&encType=SM4&signType=SM2×tamp=1757326792488&version=1.0.0&key=****
原始私钥(Base64 编码)需先转化为十六进制格式:
CommonUtil.byteArrayToHex(this.decoder.decode(privateKey));
示例转换结果(脱敏):
69ECB3F1F419A015******************************B4DDE79CB3D8899542
GMObjectIdentifiers.sm2sign_with_sm3
示例签名结果:
j7hAVMocO14BPOli/bKxe6Md4d********************************yuPjhKnTLMZOMKI3kJngKfIUolg==
data
仅取业务字段部分(如处方信息等 JSON)。
{
"pharDeptName": "儿一科",
"pharCertType": "01",
"psnCertType": "01",
"pharName": "李四",
"hiRxno": "610*****978",
"pharCertno": "21233121",
"pharCode": "111",
"pharDeptCode": "A50.04",
"drCode": "D610724006954",
"pharProfttlName": "执业药师",
"certno": "612****316",
"fixmedinsCode": "H61****077",
"patnName": "张三",
"prscDrName": "王五",
"rxTraceCode": "612897******48261",
"pharChkTime": "2025-08-27 17:57:59",
"pharProfttlCodg": "1",
"fixmedinsName": "某某医院",
"mdtrtId": "127*****90"
}
SM4Util.encryptEcb(CommonUtil.stringToHexString(appID.substring(0, 16)), secret)
.substring(0, 16)
.toUpperCase()
.getBytes();
SM4/ECB/PKCS7Padding
Cipher cipher = generateEcbCipher(...);
示例加密结果(脱敏) :
f4064a4d7e1291ea1aef4fc8436a4a22...
...39ef651c08fb50eec96f23b184d2506
最终请求中:
data
字段需删除encData
(即 SM4 加密结果)signData
(SM2 签名结果)所有参数放入 TreeMap
后再发起请求。
data
字段仅参与签名,不直接传输;传输的是 encData
。sequenceDiagram
participant Client as 客户端
participant SM2 as SM2签名模块
participant SM4 as SM4加密模块
participant Server as 服务端接口
Client->>Client: 构建业务参数(JSON)
Client->>Client: 剔除 signData/encData/extra
Client->>Client: 参数排序 + 拼接 appSecret = signstr
Client->>SM2: 使用私钥对 signstr 执行 SM2 签名
SM2-->>Client: 返回 signData(Base64)
Client->>SM4: 使用 appId/secret 生成 SM4 key
Client->>SM4: 对 data(JSON) 执行 SM4/ECB/PKCS7Padding 加密
SM4-->>Client: 返回 encData(Hex)
Client->>Client: TreeMap 组装请求参数
Note right of Client: 删除原 data,保留<br/>appId、timestamp、signData、encData 等
Client->>Server: 发送请求(url+path)
Server-->>Client: 返回处理结果(JSON)
graph TD
A[开始] --> B[构建业务参数 JSON]
B --> C[剔除 signData / encData / extra 字段]
C --> D[参数排序]
D --> E[拼接 appSecret 得到 signstr]
E --> F1[SM2 签名]
F1 --> F2[生成 signData Base64]
D --> H[提取 data JSON]
H --> I[生成 SM4 Key 使用 appId 和 secret]
I --> J[SM4 加密 ECB PKCS7Padding]
J --> K[生成 encData Hex]
F2 --> L[TreeMap 组装参数]
K --> L
L --> M[删除 data 保留 signData 和 encData]
M --> N[发送请求 url+path]
N --> O[服务端接收并校验]
O --> P[返回结果 JSON]
P --> Q[结束]