CheckUtil.java
4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package com.aigeo.util.pay;
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* 项目名称: 微信支付回调解密
* 版权所有: 深圳市科飞时速网络技术有限公司(0755-88843776)
* 程序版本: V3.0
* 技术支持: info@21gmail.com
* 单元名称: 支付接口
* 开始时间: 2025/08/04 15:13
* 最后修改: 2025/08/04 15:13
* 开发人员: 温志锋
* 备 注: 如需修改请联系开发人员
*/
public class CheckUtil {
/**
* 验签
* @param wechatPublicKeyPath 公钥文件路径
* @param timestamp 时间戳
* @param nonce 验签的随机字符串
* @param body 请求体
* @param signature 签名值
* @return 验签成功
*/
public static boolean verifySignature(String wechatPublicKeyPath, String timestamp, String nonce, String body, String signature){
try{
// 1. 构建验签串
String signMessage = buildSignMessage(timestamp, nonce, body);
// 2. 解码Base64签名
byte[] signatureBytes = Base64.getDecoder().decode(signature);
// 3. 加载微信支付公钥
PublicKey publicKey = loadPublicKey(wechatPublicKeyPath);
// 4. 执行验签
Signature signer = Signature.getInstance("SHA256withRSA");
signer.initVerify(publicKey);
signer.update(signMessage.getBytes(StandardCharsets.UTF_8));
return signer.verify(signatureBytes);
}catch(Exception e){
e.printStackTrace();
System.out.println("---------验签异常---------"+e);
return false;
}
}
/**
* 解密方法
* @param ciphertext 数据密文
* @param associatedData 附加数据
* @param nonce 随机串
* @param vkey v3key
* @return 解密数据
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static String decryptData(String ciphertext, String associatedData, String nonce,String vkey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] keyBytes = vkey.getBytes(StandardCharsets.UTF_8);
SecretKey key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE, key, spec);
if (associatedData != null) {
cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));
}
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
return new String(decrypted, StandardCharsets.UTF_8);
}
/**
* 构建验签串
* 格式: timestamp + "\n" + nonce + "\n" + body + "\n"
*/
private static String buildSignMessage(String timestamp, String nonce, String body) {
// 处理空body情况(如204响应)
if (body == null) {
body = "";
}
return timestamp + "\n" + nonce + "\n" + body + "\n";
}
/**
* 从PEM格式字符串加载公钥
*/
private static PublicKey loadPublicKey(String filePath) throws GeneralSecurityException {
try {
String pemContent = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
//1. 移除PEM头尾标记和空白字符
String publicKeyPEM = pemContent
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s", "");
System.out.println("----公钥:"+publicKeyPEM);
// 2. Base64解码
byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
// 3. 创建KeyFactory
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 4. 生成公钥
return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
//byte[] certBytes = Files.readAllBytes(Paths.get(filePath));
//CertificateFactory cf = CertificateFactory.getInstance("X.509");
//X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certBytes));
//return cert.getPublicKey();
} catch (Exception e) {
e.printStackTrace();
throw new GeneralSecurityException("加载微信支付公钥失败", e);
}
}
}