sm4加密/解密-postman
1、SmEncryptUtil 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) {
// 修正:appAKA 改为 appSecret
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) {
// 修正:appAKA 改为 appSecret
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) {
// 修正:appAKA 改为 appSecret
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 + '\'' +
'}';
}
}
}
2、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 {
// 统一修改为指定的appSecret密钥
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");
// 调用核心解密方法(使用修改后的默认appSecret)
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);
// 先解密(使用修改后的默认appSecret)
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) {
// 先解密(使用修改后的默认appSecret)
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;
}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1191202.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!