| | |
| | | package com.dsh.activity.util.wx; |
| | | |
| | | import javax.crypto.Cipher; |
| | | import javax.crypto.NoSuchPaddingException; |
| | | import javax.crypto.spec.GCMParameterSpec; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.security.GeneralSecurityException; |
| | | import java.security.InvalidAlgorithmParameterException; |
| | | import java.security.InvalidKeyException; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.util.Base64; |
| | | |
| | | /** |
| | | * 微信支付V3 AES解密工具类 (AEAD_AES_256_GCM) |
| | | */ |
| | | public class WxPayAesUtil { |
| | | |
| | | private static final String ALGORITHM = "AES/GCM/NoPadding"; |
| | | private static final int TAG_LENGTH_BIT = 128; // GCM认证标签长度,固定为128位 |
| | | private static final int NONCE_LENGTH_BYTE = 12; // GCM随机串长度,固定为12字节 |
| | | private static final String TRANSFORMATION = "AES/GCM/NoPadding"; // 算法/模式/填充 |
| | | |
| | | /** |
| | | * 解密微信支付回调通知中的加密信息 |
| | | * |
| | | * @param apiV3Key APIv3密钥 (来自 WxV3PayConfig) |
| | | * @param associatedData 附加数据 (resource.associated_data) |
| | | * @param nonce 随机串 (resource.nonce) |
| | | * @param ciphertext 密文 (resource.ciphertext),Base64编码 |
| | | * @return 解密后的明文字符串 |
| | | * @throws GeneralSecurityException 解密失败时抛出异常 |
| | | */ |
| | | public static String decrypt(String apiV3Key, String associatedData, String nonce, String ciphertext) |
| | | throws GeneralSecurityException { |
| | | try { |
| | | SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES"); |
| | | GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce.getBytes(StandardCharsets.UTF_8)); |
| | | |
| | | Cipher cipher = Cipher.getInstance(TRANSFORMATION); |
| | | cipher.init(Cipher.DECRYPT_MODE, key, spec); |
| | | cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8)); // 设置附加认证数据 |
| | | |
| | | byte[] decodedCiphertext = Base64.getDecoder().decode(ciphertext); |
| | | byte[] decryptedBytes = cipher.doFinal(decodedCiphertext); |
| | | |
| | | return new String(decryptedBytes, StandardCharsets.UTF_8); |
| | | } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { |
| | | throw new IllegalStateException("当前JDK环境不支持AEAD_AES_256_GCM", e); |
| | | } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { |
| | | throw new IllegalArgumentException("无效的密钥或GCM参数", e); |
| | | } catch (Exception e) { |
| | | // 包括 BadPaddingException 等解密失败的情况 |
| | | throw new GeneralSecurityException("AES/GCM 解密失败", e); |
| | | } |
| | | } |
| | | } |
| | | //package com.dsh.activity.util.wx; |
| | | // |
| | | //import javax.crypto.Cipher; |
| | | //import javax.crypto.NoSuchPaddingException; |
| | | //import javax.crypto.spec.GCMParameterSpec; |
| | | //import javax.crypto.spec.SecretKeySpec; |
| | | //import java.nio.charset.StandardCharsets; |
| | | //import java.security.GeneralSecurityException; |
| | | //import java.security.InvalidAlgorithmParameterException; |
| | | //import java.security.InvalidKeyException; |
| | | //import java.security.NoSuchAlgorithmException; |
| | | //import java.util.Base64; |
| | | // |
| | | ///** |
| | | // * 微信支付V3 AES解密工具类 (AEAD_AES_256_GCM) |
| | | // */ |
| | | //public class WxPayAesUtil { |
| | | // |
| | | // private static final String ALGORITHM = "AES/GCM/NoPadding"; |
| | | // private static final int TAG_LENGTH_BIT = 128; // GCM认证标签长度,固定为128位 |
| | | // private static final int NONCE_LENGTH_BYTE = 12; // GCM随机串长度,固定为12字节 |
| | | // private static final String TRANSFORMATION = "AES/GCM/NoPadding"; // 算法/模式/填充 |
| | | // |
| | | // /** |
| | | // * 解密微信支付回调通知中的加密信息 |
| | | // * |
| | | // * @param apiV3Key APIv3密钥 (来自 WxV3PayConfig) |
| | | // * @param associatedData 附加数据 (resource.associated_data) |
| | | // * @param nonce 随机串 (resource.nonce) |
| | | // * @param ciphertext 密文 (resource.ciphertext),Base64编码 |
| | | // * @return 解密后的明文字符串 |
| | | // * @throws GeneralSecurityException 解密失败时抛出异常 |
| | | // */ |
| | | // public static String decrypt(String apiV3Key, String associatedData, String nonce, String ciphertext) |
| | | // throws GeneralSecurityException { |
| | | // try { |
| | | // SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES"); |
| | | // GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce.getBytes(StandardCharsets.UTF_8)); |
| | | // |
| | | // Cipher cipher = Cipher.getInstance(TRANSFORMATION); |
| | | // cipher.init(Cipher.DECRYPT_MODE, key, spec); |
| | | // cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8)); // 设置附加认证数据 |
| | | // |
| | | // byte[] decodedCiphertext = Base64.getDecoder().decode(ciphertext); |
| | | // byte[] decryptedBytes = cipher.doFinal(decodedCiphertext); |
| | | // |
| | | // return new String(decryptedBytes, StandardCharsets.UTF_8); |
| | | // } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { |
| | | // throw new IllegalStateException("当前JDK环境不支持AEAD_AES_256_GCM", e); |
| | | // } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { |
| | | // throw new IllegalArgumentException("无效的密钥或GCM参数", e); |
| | | // } catch (Exception e) { |
| | | // // 包括 BadPaddingException 等解密失败的情况 |
| | | // throw new GeneralSecurityException("AES/GCM 解密失败", e); |
| | | // } |
| | | // } |
| | | //} |