🆕 #1706 微信支付增加特约商户进件相关接口

* 实现特约商户进件相关接口
This commit is contained in:
叶枫
2020-08-07 17:39:38 +08:00
committed by GitHub
parent e7f2378f49
commit edf8e18c5b
22 changed files with 1755 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
package com.github.binarywang.wxpay.v3;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 敏感信息字段
* @author zhouyognshen
**/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SpecEncrypt {
}

View File

@@ -0,0 +1,99 @@
package com.github.binarywang.wxpay.v3.util;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.v3.SpecEncrypt;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Base64;
/**
* 微信支付敏感信息加密
* 文档见: https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/min-gan-xin-xi-jia-mi
*
* @author zhouyongshen
**/
public class RsaCryptoUtil {
static String JAVA_LANG_STRING = "java.lang.String";
public static void encryptFields(Object encryptObject, X509Certificate certificate) throws WxPayException {
try {
encryptField(encryptObject, certificate);
} catch (IllegalAccessException | IllegalBlockSizeException e) {
throw new WxPayException("敏感信息加密失败", e);
} catch (Exception e2) {
throw new WxPayException("敏感信息加密失败", e2);
}
}
private static void encryptField(Object encryptObject, X509Certificate certificate) throws IllegalAccessException, IllegalBlockSizeException {
Class<?> infoClass = encryptObject.getClass();
Field[] infoFieldArray = infoClass.getDeclaredFields();
for (Field field : infoFieldArray) {
if (field.isAnnotationPresent(SpecEncrypt.class)) {
//字段使用了@SpecEncrypt进行标识
if (field.getType().getTypeName().equals(JAVA_LANG_STRING)) {
field.setAccessible(true);
Object oldValue = field.get(encryptObject);
if (oldValue != null) {
String oldStr = (String) oldValue;
if (!oldStr.trim().equals("'")) {
field.set(encryptObject, encryptOAEP(oldStr, certificate));
}
}
} else {
field.setAccessible(true);
Object obj = field.get(encryptObject);
if (obj != null) {
encryptField(field.get(encryptObject), certificate);
}
}
}
}
}
public static String encryptOAEP(String message, X509Certificate certificate)
throws IllegalBlockSizeException {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
byte[] data = message.getBytes(StandardCharsets.UTF_8);
byte[] ciphertext = cipher.doFinal(data);
return Base64.getEncoder().encodeToString(ciphertext);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("无效的证书", e);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
}
}
public static String decryptOAEP(String ciphertext, PrivateKey privateKey)
throws BadPaddingException {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] data = Base64.getDecoder().decode(ciphertext);
return new String(cipher.doFinal(data), StandardCharsets.UTF_8);
} catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("无效的私钥", e);
} catch (BadPaddingException | IllegalBlockSizeException e) {
throw new BadPaddingException("解密失败");
}
}
}