Java微信支付回调验签并解密

微信支付是一种流行的移动支付方式,许多应用程序都集成了微信支付功能。在接收到微信支付回调通知时,我们需要对回调的数据进行验签和解密,以确保数据的安全性和完整性。本文将详细介绍如何使用Java对微信支付回调进行验签和解密,并提供代码示例。

1. 验签

验签是指通过对数据进行加密和解密,确认数据的发送方是可信的。在微信支付回调中,微信服务器会将回调的数据使用私钥进行加密,我们需要使用相应的公钥进行解密并验证签名。

1.1 获取公钥

在微信支付商户平台中,我们可以获取到微信支付的公钥。将公钥保存在本地文件中,用于后续的解密和验签操作。

1.2 解密和验签代码示例

下面是一个示例代码,演示了如何使用Java对微信支付回调进行解密和验签的过程。

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;

public class WechatPayCallbackVerifier {
    
    public static boolean verifyCallback(String encryptedData, String signature, String publicKeyPath) {
        try {
            byte[] encryptedBytes = Base64.decodeBase64(encryptedData);
            byte[] signatureBytes = Base64.decodeBase64(signature);
            
            PublicKey publicKey = getPublicKey(publicKeyPath);
            
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initVerify(publicKey);
            sign.update(encryptedBytes);
            
            return sign.verify(signatureBytes);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    private static PublicKey getPublicKey(String publicKeyPath) throws Exception {
        byte[] keyBytes = Files.readAllBytes(Paths.get(publicKeyPath));
        
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        
        return kf.generatePublic(spec);
    }
    
    public static String decryptData(String encryptedData, String privateKeyPath) {
        try {
            byte[] encryptedBytes = Base64.decodeBase64(encryptedData);
            
            PrivateKey privateKey = getPrivateKey(privateKeyPath);
            
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            
            return new String(decryptedBytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    private static PrivateKey getPrivateKey(String privateKeyPath) throws Exception {
        byte[] keyBytes = Files.readAllBytes(Paths.get(privateKeyPath));
        
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        
        return kf.generatePrivate(spec);
    }
}

上述代码中,verifyCallback方法接受三个参数:encryptedData是回调数据的密文,signature是回调数据的签名,publicKeyPath是公钥文件的路径。方法中使用公钥对密文进行解密,并使用签名验证解密后的数据的完整性。

decryptData方法接受两个参数:encryptedData是回调数据的密文,privateKeyPath是私钥文件的路径。方法中使用私钥对密文进行解密,并返回解密后的明文。

2. 解密

在验签通过后,我们需要对密文进行解密,以获取到回调的明文数据。微信支付回调中的明文数据是经过AES加密后的,我们需要使用相应的AES密钥进行解密。

2.1 获取AES密钥

在微信支付回调中,我们可以获取到AES密钥的密文。将密文保存在本地文件中,用于后续的解密操作。

2.2 解密代码示例

下面是一个示例代码,演示了如何使用Java对微信支付回调进行解密的过程。

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class WechatPayCallbackDecryptor {
    
    public static String decryptData(String encryptedData, String keyPath, String iv) {
        try {
            byte[] encryptedBytes = Base64.decodeBase64(encryptedData);
            byte[] keyBytes = Base64.decodeBase64(getKey(keyPath));