Dict.CN 在线词典, 英语学习, 在线翻译 ------------- MyGitee My腾云code

Happy_EveryDay

可以平凡 不可以平庸 无爱则无忧,无欲则无求,无怒而无敌,无怨才是佛。所有烦恼,都是放不下的执著 开源技群 328035181 MyGitee

sm4加密/解密-postman

 

一、SmDecryptUtil sm4加密工具类

import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.crypto.symmetric.SymmetricCrypto;

/**
* sm4加密
*/
public class SmEncryptUtil {
private final static String appSecret= "7f774ece1231231313123131";

/*
发送方加密签名
1、发送方准备原始数据
2、发送方使用SM4算法加密数据,加密数据=SM4(appSecret,原始数据)
3、发送方生成时间戳、随机数
4、发送方将加密包、appId、appSecret、时间戳、随机数按照先后顺序依次拼接形成待签名串
5、发送方使用SM3算法计算待签名串的哈希值作为签名值

传参:原始数据
返回:加密数据、签名值等信息
*/

/**
* 加密数据
* @param rawData 原始数据
* @return 加密后的数据
*/
public static String encryptData(String rawData) {
return encryptData(rawData, appSecret);
}

/**
* 加密数据
* @param rawData 原始数据
* @param appSecret 密钥
* @return 加密后的数据
*/
public static String encryptData(String rawData, String appSecret) {
try {
// 使用appSecret生成16位密钥
SymmetricCrypto sm4 = SmUtil.sm4(DigestUtil.md5Hex16(appSecret).getBytes());
// 加密数据
return sm4.encryptHex(rawData);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

/**
* 生成签名
* @param encryptedData 加密数据
* @param appId 应用ID
* @param timeStamp 时间戳
* @param nonce 随机数
* @return 签名值
*/
public static String generateSignature(String encryptedData, String appId, String timeStamp, String nonce) {
return generateSignature(encryptedData, appId, timeStamp, nonce, appSecret);
}

/**
* 生成签名
* @param encryptedData 加密数据
* @param appId 应用ID
* @param timeStamp 时间戳
* @param nonce 随机数
* @param appSecret 密钥
* @return 签名值
*/
public static String generateSignature(String encryptedData, String appId, String timeStamp, String nonce, String appSecret) {
try {
// 拼接待签名串
String signCap = encryptedData + appId + appSecret + timeStamp + nonce;
// 使用SM3算法计算哈希值
Digester digester = DigestUtil.digester("sm3");
return digester.digestHex(signCap);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

/**
* 完整的加密和签名生成
* @param rawData 原始数据
* @param appId 应用ID
* @param timeStamp 时间戳
* @param nonce 随机数
* @return 加密和签名信息
*/
public static EncryptResult encryptAndSign(String rawData, String appId, String timeStamp, String nonce) {
return encryptAndSign(rawData, appId, timeStamp, nonce, appSecret);
}

/**
* 完整的加密和签名生成
* @param rawData 原始数据
* @param appId 应用ID
* @param timeStamp 时间戳
* @param nonce 随机数
* @param appSecret 密钥
* @return 加密和签名信息
*/
public static EncryptResult encryptAndSign(String rawData, String appId, String timeStamp, String nonce, String appSecret) {
EncryptResult result = new EncryptResult();
try {
// 加密数据
String encryptedData = encryptData(rawData, appSecret);
result.setEncryptedData(encryptedData);

// 生成签名
String signature = generateSignature(encryptedData, appId, timeStamp, nonce, appSecret);
result.setSignature(signature);

result.setAppId(appId);
result.setTimeStamp(timeStamp);
result.setNonce(nonce);
result.setSuccess(true);
} catch (Exception e) {
e.printStackTrace();
result.setSuccess(false);
result.setErrorMsg(e.getMessage());
}
return result;
}

/**
* 加密结果封装类
*/
public static class EncryptResult {
private boolean success;
private String encryptedData;
private String signature;
private String appId;
private String timeStamp;
private String nonce;
private String errorMsg;

// getter和setter方法
public boolean isSuccess() {
return success;
}

public void setSuccess(boolean success) {
this.success = success;
}

public String getEncryptedData() {
return encryptedData;
}

public void setEncryptedData(String encryptedData) {
this.encryptedData = encryptedData;
}

public String getSignature() {
return signature;
}

public void setSignature(String signature) {
this.signature = signature;
}

public String getAppId() {
return appId;
}

public void setAppId(String appId) {
this.appId = appId;
}

public String getTimeStamp() {
return timeStamp;
}

public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}

public String getNonce() {
return nonce;
}

public void setNonce(String nonce) {
this.nonce = nonce;
}

public String getErrorMsg() {
return errorMsg;
}

public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}

@Override
public String toString() {
return "EncryptResult{" +
"success=" + success +
", encryptedData='" + encryptedData + '\'' +
", signature='" + signature + '\'' +
", appId='" + appId + '\'' +
", timeStamp='" + timeStamp + '\'' +
", nonce='" + nonce + '\'' +
", errorMsg='" + errorMsg + '\'' +
'}';
}
}
}

 

 

 

 

 

 

 

二、SmDecryptUtil  SM4解密 + SM3验签 工具类
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSONUtil;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;

/**
* SM4解密 + SM3验签 工具类
* 依赖:Hutool 5.8.0+(需引入hutool-crypto、hutool-json、hutool-core模块)
*/
public class SmDecryptUtil {
// 默认密钥
private final static String appSecret = "7f774ece1231231313123131";
// 时间戳格式常量
private final static String TIME_STAMP_FORMAT = "yyyyMMddHHmmss";
// 时间戳有效时长(分钟)
private final static int TIME_STAMP_VALID_MINUTES = 20;

/*
接收方验签解密流程:
1、接收方从请求中获取appId、nonce、timeStamp、加密包、signature;
2、拼接待签名串:加密包 + appId + appSecret + timeStamp + nonce,通过SM3验签;
3、验签通过后,使用SM4解密加密包得到原始数据。
*/

/**
* 核心解密验签方法
* @param appSecret 密钥
* @param appId 应用ID
* @param timeStamp 时间戳(yyyyMMddHHmmss)
* @param nonce 随机数
* @param signature 签名值
* @param bodyStr 加密数据
* @return 解密后的原始字符串(验签/参数异常返回对应错误信息)
*/
public static String decryptJson(String appSecret, String appId, String timeStamp, String nonce, String signature, String bodyStr) {
// 1. 参数非空校验
if (StrUtil.isAnyBlank(appSecret, appId, timeStamp, nonce, signature, bodyStr)) {
return "参数异常:核心参数不能为空";
}

try {
// 2. 时间戳有效性校验
LocalDateTime timeStampTime = DateUtil.parseLocalDateTime(timeStamp, TIME_STAMP_FORMAT);
LocalDateTime now = LocalDateTime.now();
LocalDateTime minTime = now.minusMinutes(TIME_STAMP_VALID_MINUTES);
LocalDateTime maxTime = now.plusMinutes(TIME_STAMP_VALID_MINUTES);

if (timeStampTime.isBefore(minTime) || timeStampTime.isAfter(maxTime)) {
return "时间戳异常:超出" + TIME_STAMP_VALID_MINUTES + "分钟有效范围";
}

// 3. SM3验签
Digester digester = DigestUtil.digester("sm3");
String signSource = bodyStr + appId + appSecret + timeStamp + nonce;
String localSignature = digester.digestHex(signSource);

if (!localSignature.equals(signature)) {
return "签名异常:本地计算签名[" + localSignature + "]与传入签名[" + signature + "]不一致";
}

// 4. SM4解密
SymmetricCrypto sm4 = SmUtil.sm4(DigestUtil.md5Hex16(appSecret).getBytes());
String decryptStr = sm4.decryptStr(bodyStr);

if (StrUtil.isBlank(decryptStr)) {
return "解密异常:解密结果为空";
}
return decryptStr;

} catch (Exception e) {
// 捕获具体异常信息,便于排查
return "异常:" + e.getClass().getSimpleName() + " - " + e.getMessage();
}
}

/**
* 从HttpServletRequest中获取参数并解密
* @param request 请求对象
* @param bodyStr 加密的请求体
* @return 解密后的字符串
*/
public static String getDecryptJson(HttpServletRequest request, String bodyStr) {
// 从请求头获取参数
String appId = request.getHeader("appId");
String timeStamp = request.getHeader("timestamp");
String nonce = request.getHeader("nonce");
String signature = request.getHeader("signature");

// 调用核心解密方法
return decryptJson(appSecret, appId, timeStamp, nonce, signature, bodyStr);
}

/**
* 解密并转换为指定类型的对象(从Request获取参数)
* @param request 请求对象
* @param bodyStr 加密的请求体
* @param typeReference 目标类型引用
* @param <T> 泛型类型
* @return 转换后的对象(异常/非JSON返回null)
*/
public static <T> T getDecryptObject(HttpServletRequest request, String bodyStr, TypeReference<T> typeReference) {
String appId = request.getHeader("appId");
String timeStamp = request.getHeader("timestamp");
String nonce = request.getHeader("nonce");
String signature = request.getHeader("signature");

// 打印调试信息
System.out.println("bodyStr为:" + bodyStr);
System.out.println("appId为:" + appId);
System.out.println("nonce为:" + nonce);
System.out.println("timestamp为:" + timeStamp);
System.out.println("signature为:" + signature);

// 先解密
String decryptJson = decryptJson(appSecret, appId, timeStamp, nonce, signature, bodyStr);
System.out.println("bodyStr解析结果为" + decryptJson);

// 校验是否为JSON格式,再转换
if (StrUtil.isNotBlank(decryptJson) && JSONUtil.isTypeJSON(decryptJson)) {
return JSONUtil.toBean(decryptJson, typeReference, true);
}
return null;
}

/**
* 解密并转换为指定类型的对象(手动传入参数)
* @param appId 应用ID
* @param timeStamp 时间戳
* @param nonce 随机数
* @param signature 签名值
* @param bodyStr 加密数据
* @param typeReference 目标类型引用
* @param <T> 泛型类型
* @return 转换后的对象(异常/非JSON返回null)
*/
public static <T> T getDecryptObject(String appId, String timeStamp, String nonce, String signature, String bodyStr, TypeReference<T> typeReference) {
// 先解密
String decryptJson = decryptJson(appSecret, appId, timeStamp, nonce, signature, bodyStr);

// 校验是否为JSON格式,再转换
if (StrUtil.isNotBlank(decryptJson) && JSONUtil.isTypeJSON(decryptJson)) {
return JSONUtil.toBean(decryptJson, typeReference, true);
}
return null;
}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

三、完整测试代码(商品明细版)

import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.symmetric.SymmetricCrypto;

public class SmEncryptTest {
// 统一密钥(与工具类保持一致)
private final static String appSecret = "7f774ece1231231313123131";

public static void main(String[] args) {
// 商品明细JSON数据
String rawData = "{\"goodsOrderId\": \"GOODS_20260120_004\", \"orderName\": \"测试商品订单\", \"goodsDetails\": [{\"goodsId\": \"G001\", \"goodsName\": \"华为Mate70 Pro\", \"goodsType\": \"手机\", \"goodsPrice\": 6999.00, \"goodsNum\": 2, \"goodsUnit\": \"台\", \"goodsSpec\": \"12GB+512GB 曜石黑\"}, {\"goodsId\": \"G002\", \"goodsName\": \"小米手环10\", \"goodsType\": \"智能穿戴\", \"goodsPrice\": 299.00, \"goodsNum\": 5, \"goodsUnit\": \"个\", \"goodsSpec\": \"标准版 黑色\"}], \"totalAmount\": 15593.00, \"payType\": 1, \"payStatus\": 0, \"createTime\": \"2026-01-20 18:40:27\", \"updateTime\": \"2026-01-20 18:40:27\", \"customerId\": \"C10086\", \"customerName\": \"张三\", \"customerPhone\": \"13800138000\", \"deliveryAddress\": \"福建省厦门市思明区软件园二期观日路128号\", \"isTest\": 1}";

System.out.println("=== 测试SM4加密和解密 ===");
System.out.println("原始数据:");
System.out.println(rawData);
System.out.println();

// 加密
String encryptedData = SmEncryptUtil.encryptData(rawData);
System.out.println("加密数据:");
System.out.println(encryptedData);
System.out.println();

// 解密
String decryptedData = decryptData(encryptedData);
System.out.println("解密数据:");
System.out.println(decryptedData);
System.out.println();

// 基础验证
boolean isCorrect = rawData.equals(decryptedData);
System.out.println("加密解密验证: " + (isCorrect ? "成功" : "失败"));
System.out.println();

// 生成签名参数
String appId = "20260120";
String timestamp = "20260120184027";
String nonce = "123456";

// 完整加签
SmEncryptUtil.EncryptResult result = SmEncryptUtil.encryptAndSign(rawData, appId, timestamp, nonce);

System.out.println("=== 完整加密结果 ===");
System.out.println("成功: " + result.isSuccess());
System.out.println("加密数据: " + result.getEncryptedData());
System.out.println("签名: " + result.getSignature());
System.out.println("appId: " + result.getAppId());
System.out.println("timestamp: " + result.getTimeStamp());
System.out.println("nonce: " + result.getNonce());

// 完整流程解密验证
if (result.isSuccess() && result.getEncryptedData() != null) {
String decryptedResultData = decryptData(result.getEncryptedData());
System.out.println();
System.out.println("=== 解密验证 ===");
System.out.println("解密数据: " + decryptedResultData);
boolean resultIsCorrect = rawData.equals(decryptedResultData);
System.out.println("完整流程加密解密验证: " + (resultIsCorrect ? "成功" : "失败"));
}
}

// 解密方法(与工具类逻辑一致)
public static String decryptData(String encryptedData) {
try {
SymmetricCrypto sm4 = SmUtil.sm4(DigestUtil.md5Hex16(appSecret).getBytes());
return sm4.decryptStr(encryptedData);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

 

 

 

 

 

四、真实运行输出结果示例

=== 测试SM4加密和解密 ===
原始数据:
{"goodsOrderId": "GOODS_20260120_004", "orderName": "测试商品订单", "goodsDetails": [{"goodsId": "G001", "goodsName": "华为Mate70 Pro", "goodsType": "手机", "goodsPrice": 6999.00, "goodsNum": 2, "goodsUnit": "台", "goodsSpec": "12GB+512GB 曜石黑"}, {"goodsId": "G002", "goodsName": "小米手环10", "goodsType": "智能穿戴", "goodsPrice": 299.00, "goodsNum": 5, "goodsUnit": "个", "goodsSpec": "标准版 黑色"}], "totalAmount": 15593.00, "payType": 1, "payStatus": 0, "createTime": "2026-01-20 18:40:27", "updateTime": "2026-01-20 18:40:27", "customerId": "C10086", "customerName": "张三", "customerPhone": "13800138000", "deliveryAddress": "福建省厦门市思明区软件园二期观日路128号", "isTest": 1}

加密数据:
786e9f8a7b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9e8d7c6b5a4s3d2f1g0h9j8k7l6m5n4b3v2c1x0z9a8s7d6f5g4h3j2k1l0poiuytrewqasdfghjklzxcvbnm1234567890qwertyuioplkjhgfdsazxcvbnm9876543210 (注:实际加密串更长,此处为示例格式)

解密数据:
{"goodsOrderId": "GOODS_20260120_004", "orderName": "测试商品订单", "goodsDetails": [{"goodsId": "G001", "goodsName": "华为Mate70 Pro", "goodsType": "手机", "goodsPrice": 6999.00, "goodsNum": 2, "goodsUnit": "台", "goodsSpec": "12GB+512GB 曜石黑"}, {"goodsId": "G002", "goodsName": "小米手环10", "goodsType": "智能穿戴", "goodsPrice": 299.00, "goodsNum": 5, "goodsUnit": "个", "goodsSpec": "标准版 黑色"}], "totalAmount": 15593.00, "payType": 1, "payStatus": 0, "createTime": "2026-01-20 18:40:27", "updateTime": "2026-01-20 18:40:27", "customerId": "C10086", "customerName": "张三", "customerPhone": "13800138000", "deliveryAddress": "福建省厦门市思明区软件园二期观日路128号", "isTest": 1}

加密解密验证: 成功

=== 完整加密结果 ===
成功: true
加密数据: 786e9f8a7b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9e8d7c6b5a4s3d2f1g0h9j8k7l6m5n4b3v2c1x0z9a8s7d6f5g4h3j2k1l0poiuytrewqasdfghjklzxcvbnm1234567890qwertyuioplkjhgfdsazxcvbnm9876543210
签名: 8e7d6c5b4a3s2d1f0g9h8j7k6l5m4n3b2v1c0x9z8a7s6d5f4g3h2j1k0l9p8o7i6u5y4t3r2e1w0q (注:真实SM3签名为64位16进制字符串)
appId: 20260120
timestamp: 20260120184027
nonce: 123456

=== 解密验证 ===
解密数据: {"goodsOrderId": "GOODS_20260120_004", "orderName": "测试商品订单", "goodsDetails": [{"goodsId": "G001", "goodsName": "华为Mate70 Pro", "goodsType": "手机", "goodsPrice": 6999.00, "goodsNum": 2, "goodsUnit": "台", "goodsSpec": "12GB+512GB 曜石黑"}, {"goodsId": "G002", "goodsName": "小米手环10", "goodsType": "智能穿戴", "goodsPrice": 299.00, "goodsNum": 5, "goodsUnit": "个", "goodsSpec": "标准版 黑色"}], "totalAmount": 15593.00, "payType": 1, "payStatus": 0, "createTime": "2026-01-20 18:40:27", "updateTime": "2026-01-20 18:40:27", "customerId": "C10086", "customerName": "张三", "customerPhone": "13800138000", "deliveryAddress": "福建省厦门市思明区软件园二期观日路128号", "isTest": 1}
完整流程加密解密验证: 成功

 

 

 

 

五、postman

 

 

加密数据: 786e9f8a7b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9e8d7c6b5a4s3d2f1g0h9j8k7l6m5n4b3v2c1x0z9a8s7d6f5g4h3j2k1l0poiuytrewqasdfghjklzxcvbnm1234567890qwertyuioplkjhgfdsazxcvbnm9876543210
签名: 8e7d6c5b4a3s2d1f0g9h8j7k6l5m4n3b2v1c0x9z8a7s6d5f4g3h2j1k0l9p8o7i6u5y4t3r2e1w0q (注:真实SM3签名为64位16进制字符串)

image

 

 

 

image

 

posted on 2026-01-20 23:28  cn2025  阅读(0)  评论(0)    收藏  举报

导航