|
@@ -1,20 +1,12 @@
|
|
|
package org.jeecg.common.zhutils;
|
|
package org.jeecg.common.zhutils;
|
|
|
|
|
|
|
|
-import com.alibaba.fastjson.JSONArray;
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
|
|
|
|
|
|
-import javax.crypto.Cipher;
|
|
|
|
|
-import javax.crypto.spec.SecretKeySpec;
|
|
|
|
|
import java.net.URLEncoder;
|
|
import java.net.URLEncoder;
|
|
|
-import java.security.PrivateKey;
|
|
|
|
|
-import java.security.PublicKey;
|
|
|
|
|
-import java.security.Signature;
|
|
|
|
|
-import java.time.LocalDateTime;
|
|
|
|
|
-import java.time.ZoneId;
|
|
|
|
|
-import java.time.format.DateTimeFormatter;
|
|
|
|
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
|
|
+import java.security.Security;
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
|
-import java.util.Iterator;
|
|
|
|
|
-import java.util.TreeSet;
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* @Author: zwq
|
|
* @Author: zwq
|
|
@@ -22,6 +14,8 @@ import java.util.TreeSet;
|
|
|
* @Date: 2021/05/27 9:34
|
|
* @Date: 2021/05/27 9:34
|
|
|
*/
|
|
*/
|
|
|
public class PayRequest {
|
|
public class PayRequest {
|
|
|
|
|
+ // 采用国密算法
|
|
|
|
|
+ private static final String ALG_SM = "SM";
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 支付请求统一方法
|
|
* 支付请求统一方法
|
|
@@ -31,63 +25,79 @@ public class PayRequest {
|
|
|
* @return
|
|
* @return
|
|
|
*/
|
|
*/
|
|
|
public static String doRequest(JSONObject obj_body, String funcode, String userid, String payurl,
|
|
public static String doRequest(JSONObject obj_body, String funcode, String userid, String payurl,
|
|
|
- PublicKey publicKey, PrivateKey prvKey, String aesKey) throws Exception {
|
|
|
|
|
|
|
+ String publicKey, String prvKey, String aesKey) throws Exception {
|
|
|
|
|
+ // 引入BC库
|
|
|
|
|
+ Security.addProvider(new BouncyCastleProvider());
|
|
|
|
|
+
|
|
|
JSONObject jObject = new JSONObject();
|
|
JSONObject jObject = new JSONObject();
|
|
|
JSONObject request = new JSONObject();
|
|
JSONObject request = new JSONObject();
|
|
|
// head
|
|
// head
|
|
|
JSONObject head = new JSONObject();
|
|
JSONObject head = new JSONObject();
|
|
|
head.put("funcode", funcode);
|
|
head.put("funcode", funcode);
|
|
|
head.put("userid", userid);
|
|
head.put("userid", userid);
|
|
|
- //免前置接入方式时该字段必输,前17位必须满足日期格式yyyyMMddHHmmssSSS(年月日时分秒毫秒)后面的自己定义,长度18-51位
|
|
|
|
|
- LocalDateTime now = LocalDateTime.now(ZoneId.of("+8"));
|
|
|
|
|
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
|
|
|
|
|
- String reqid = formatter.format(now);
|
|
|
|
|
- //组合随机数(12位),请求id=日期+随机数
|
|
|
|
|
|
|
+ // 免前置接入方式时该字段必输,前17位必须满足日期格式yyyyMMddHHmmssSSS(年月日时分秒毫秒)后面的自己定义,长度18-51位
|
|
|
|
|
+ String reqid = DCHelper.getTime();
|
|
|
|
|
+ // 组合随机数(12位),请求id=日期+随机数
|
|
|
reqid = reqid + RandomRequest.getRandom(12);
|
|
reqid = reqid + RandomRequest.getRandom(12);
|
|
|
head.put("reqid", reqid);
|
|
head.put("reqid", reqid);
|
|
|
- //data
|
|
|
|
|
|
|
+ // data
|
|
|
request.put("head", head);
|
|
request.put("head", head);
|
|
|
request.put("body", obj_body);
|
|
request.put("body", obj_body);
|
|
|
jObject.put("request", request);
|
|
jObject.put("request", request);
|
|
|
- //签名
|
|
|
|
|
|
|
+ // 签名
|
|
|
JSONObject sign = new JSONObject();
|
|
JSONObject sign = new JSONObject();
|
|
|
sign.put("sigdat", "__signature_sigdat__");
|
|
sign.put("sigdat", "__signature_sigdat__");
|
|
|
- sign.put("sigtim", GetTime());
|
|
|
|
|
|
|
+ sign.put("sigtim", DCHelper.getTime());
|
|
|
jObject.put("signature", sign);
|
|
jObject.put("signature", sign);
|
|
|
- String source = serialJsonOrdered(jObject);
|
|
|
|
|
- System.out.println("source===" + source);
|
|
|
|
|
- String data = signRsa2048(source.getBytes(), prvKey);
|
|
|
|
|
- sign.put("sigdat", data);
|
|
|
|
|
|
|
+ String source = DCHelper.serialJsonOrdered(jObject);
|
|
|
|
|
+ System.out.println("签名原文: " + source);
|
|
|
|
|
+ byte[] signature1 = DCCryptor.CMBSM2SignWithSM3(getID_IV(userid), Base64.decode(prvKey), source.getBytes(
|
|
|
|
|
+ StandardCharsets.UTF_8));
|
|
|
|
|
+ String sigdat1 = new String(Base64.encode(signature1));
|
|
|
|
|
+ System.out.println("签名结果: " + sigdat1);
|
|
|
|
|
+ sign.put("sigdat", sigdat1);
|
|
|
jObject.put("signature", sign);
|
|
jObject.put("signature", sign);
|
|
|
|
|
|
|
|
- // AES加密
|
|
|
|
|
- String AesPlainxt = serialJsonOrdered(jObject);
|
|
|
|
|
- System.out.println("加密前req: " + AesPlainxt);
|
|
|
|
|
- String req = encryptAES256Str(AesPlainxt, aesKey.getBytes());
|
|
|
|
|
|
|
+ // SM4-CBC加密
|
|
|
|
|
+ String plaintxt = jObject.toString();
|
|
|
|
|
+ System.out.println("加密前req: " + plaintxt);
|
|
|
|
|
+ byte[] enInput = DCCryptor.CMBSM4EncryptWithCBC(aesKey.getBytes(), getID_IV(userid), plaintxt.getBytes(
|
|
|
|
|
+ StandardCharsets.UTF_8));
|
|
|
|
|
+ String req = new String(Base64.encode(enInput));
|
|
|
System.out.println("加密后req: " + req);
|
|
System.out.println("加密后req: " + req);
|
|
|
|
|
|
|
|
// 发送请求
|
|
// 发送请求
|
|
|
HashMap<String, String> map = new HashMap<>();
|
|
HashMap<String, String> map = new HashMap<>();
|
|
|
map.put("UID", userid);
|
|
map.put("UID", userid);
|
|
|
|
|
+ map.put("ALG", ALG_SM);
|
|
|
map.put("DATA", URLEncoder.encode(req, "utf-8"));
|
|
map.put("DATA", URLEncoder.encode(req, "utf-8"));
|
|
|
|
|
+ map.put("FUNCODE", funcode);
|
|
|
System.out.println(map.toString());
|
|
System.out.println(map.toString());
|
|
|
String formResult = PayUtils.doPostForm(payurl, map);
|
|
String formResult = PayUtils.doPostForm(payurl, map);
|
|
|
System.out.println("请求结果: " + formResult);
|
|
System.out.println("请求结果: " + formResult);
|
|
|
|
|
+ try {
|
|
|
|
|
+ Base64.decode(formResult);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ System.err.println("访问返回错误.");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
//请求报文通过校验,不再抛异常
|
|
//请求报文通过校验,不再抛异常
|
|
|
if (!formResult.startsWith(PayConst.CDCServer)) {
|
|
if (!formResult.startsWith(PayConst.CDCServer)) {
|
|
|
- // 解密请求结果
|
|
|
|
|
- String resPlain = decryptAES256(formResult, aesKey.getBytes(), true);
|
|
|
|
|
|
|
+ // 解密请求
|
|
|
|
|
+ String resPlain = new String(DCCryptor.CMBSM4DecryptWithCBC(aesKey.getBytes(), getID_IV(userid), Base64.decode(formResult)),
|
|
|
|
|
+ StandardCharsets.UTF_8);
|
|
|
System.out.println("res decrypt: " + resPlain);
|
|
System.out.println("res decrypt: " + resPlain);
|
|
|
|
|
+ // 验签
|
|
|
JSONObject object2 = JSONObject.parseObject(resPlain);
|
|
JSONObject object2 = JSONObject.parseObject(resPlain);
|
|
|
JSONObject object3 = object2.getJSONObject("signature");
|
|
JSONObject object3 = object2.getJSONObject("signature");
|
|
|
String resSign = object3.getString("sigdat");
|
|
String resSign = object3.getString("sigdat");
|
|
|
object3.put("sigdat", "__signature_sigdat__");
|
|
object3.put("sigdat", "__signature_sigdat__");
|
|
|
object2.put("signature", object3);
|
|
object2.put("signature", object3);
|
|
|
- String resSignSource = serialJsonOrdered(object2);
|
|
|
|
|
|
|
+ String resSignSource = DCHelper.serialJsonOrdered(object2);
|
|
|
System.out.println("验签原文: " + resSignSource);
|
|
System.out.println("验签原文: " + resSignSource);
|
|
|
System.out.println("验签签名值: " + resSign);
|
|
System.out.println("验签签名值: " + resSign);
|
|
|
- Boolean verify = signRsa2048Verify(resSignSource.getBytes(), Base64.decode(resSign), publicKey);
|
|
|
|
|
|
|
+ Boolean verify = DCCryptor.CMBSM2VerifyWithSM3(getID_IV(userid), Base64.decode(publicKey), resSignSource.getBytes(
|
|
|
|
|
+ StandardCharsets.UTF_8), Base64.decode(resSign));
|
|
|
System.out.println("验签结果: " + verify);
|
|
System.out.println("验签结果: " + verify);
|
|
|
if (verify) {
|
|
if (verify) {
|
|
|
return resSignSource;
|
|
return resSignSource;
|
|
@@ -97,188 +107,13 @@ public class PayRequest {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 加密
|
|
|
|
|
- *
|
|
|
|
|
- * @param content
|
|
|
|
|
- * @param bytePassword
|
|
|
|
|
- * @return
|
|
|
|
|
- */
|
|
|
|
|
- public static String encryptAES256Str(String content, byte[] bytePassword) {
|
|
|
|
|
- return Base64.encode(encryptAES256(content, bytePassword));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public static byte[] encryptAES256(String content, byte[] bytePassword) {
|
|
|
|
|
- try {
|
|
|
|
|
- Cipher cipherInstance = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
|
|
|
|
|
- SecretKeySpec key = new SecretKeySpec(bytePassword, "AES");
|
|
|
|
|
- cipherInstance.init(Cipher.ENCRYPT_MODE, key);
|
|
|
|
|
- byte[] byteContent = content.getBytes();
|
|
|
|
|
- byte[] cryptograph = cipherInstance.doFinal(byteContent);
|
|
|
|
|
- return cryptograph;
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println(e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
- return bytePassword;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 解密
|
|
|
|
|
- *
|
|
|
|
|
- * @param content
|
|
|
|
|
- * @param bytePassword
|
|
|
|
|
- * @param logError
|
|
|
|
|
- * @return
|
|
|
|
|
- */
|
|
|
|
|
- public static String decryptAES256(String content, byte[] bytePassword, boolean logError) {
|
|
|
|
|
- if (content == null || content.length() == 0) {
|
|
|
|
|
- System.out.println("解密失败1");
|
|
|
|
|
- }
|
|
|
|
|
- byte[] bContent = null;
|
|
|
|
|
- try {
|
|
|
|
|
- bContent = Base64.decode(content);
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println("解密失败2");
|
|
|
|
|
- e.printStackTrace();
|
|
|
|
|
- }
|
|
|
|
|
- try {
|
|
|
|
|
- Cipher cipherInstance = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
|
|
|
|
|
- SecretKeySpec key = new SecretKeySpec(bytePassword, "AES");
|
|
|
|
|
- cipherInstance.init(Cipher.DECRYPT_MODE, key);
|
|
|
|
|
- byte[] crypted = cipherInstance.doFinal(bContent);
|
|
|
|
|
- return new String(crypted, "utf-8");
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println("解密失败3" + e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
- return content;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * RSA 2048 签名
|
|
|
|
|
- *
|
|
|
|
|
- * @param baSource
|
|
|
|
|
- * @param prvKey
|
|
|
|
|
- * @return
|
|
|
|
|
- * @throws Exception
|
|
|
|
|
- */
|
|
|
|
|
- public static String signRsa2048(byte[] baSource, PrivateKey prvKey) throws Exception {
|
|
|
|
|
- try {
|
|
|
|
|
- Signature signature = Signature.getInstance("SHA256WithRSA");
|
|
|
|
|
- signature.initSign(prvKey);
|
|
|
|
|
- signature.update(baSource);
|
|
|
|
|
- return Base64.encode(signature.sign());
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println("签名失败" + e.getMessage());
|
|
|
|
|
- throw new Exception("签名失败" + e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * RSA 2048 验签
|
|
|
|
|
- *
|
|
|
|
|
- * @param baSource
|
|
|
|
|
- * @param baSignature
|
|
|
|
|
- * @param pubKey
|
|
|
|
|
- * @return
|
|
|
|
|
- * @throws Exception
|
|
|
|
|
- */
|
|
|
|
|
- public static boolean signRsa2048Verify(byte[] baSource, byte[] baSignature, PublicKey pubKey) throws Exception {
|
|
|
|
|
- try {
|
|
|
|
|
- Signature signature = Signature.getInstance("SHA256WithRSA");
|
|
|
|
|
- signature.initVerify(pubKey);
|
|
|
|
|
- signature.update(baSource);
|
|
|
|
|
- return signature.verify(baSignature);
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println("验签失败 " + e.getMessage());
|
|
|
|
|
- throw new Exception("验签失败 " + e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 当前时间
|
|
|
|
|
- *
|
|
|
|
|
- * @return
|
|
|
|
|
- */
|
|
|
|
|
- public static String GetTime() {
|
|
|
|
|
- LocalDateTime now = LocalDateTime.now(ZoneId.of("+8"));
|
|
|
|
|
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
|
|
|
|
- return formatter.format(now);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 序列化json
|
|
|
|
|
|
|
+ * 获取id字节
|
|
|
*
|
|
*
|
|
|
- * @param json
|
|
|
|
|
|
|
+ * @param uid
|
|
|
* @return
|
|
* @return
|
|
|
*/
|
|
*/
|
|
|
- public static String serialJsonOrdered(JSONObject json) {
|
|
|
|
|
- StringBuilder appender = new StringBuilder();
|
|
|
|
|
- appender.append("{");
|
|
|
|
|
- Iterator<String> keys = new TreeSet<>(json.keySet()).iterator();
|
|
|
|
|
- boolean isFirstEle = true;
|
|
|
|
|
- while (keys.hasNext()) {
|
|
|
|
|
- if (!isFirstEle) {
|
|
|
|
|
- appender.append(",");
|
|
|
|
|
- }
|
|
|
|
|
- String key = keys.next();
|
|
|
|
|
- Object val = json.get(key);
|
|
|
|
|
- if (val instanceof JSONObject) {
|
|
|
|
|
- appender.append("\"").append(key).append("\":");
|
|
|
|
|
- appender.append(serialJsonOrdered((JSONObject) val));
|
|
|
|
|
- } else if (val instanceof JSONArray) {
|
|
|
|
|
- JSONArray jarray = (JSONArray) val;
|
|
|
|
|
- appender.append("\"").append(key).append("\":[");
|
|
|
|
|
- boolean isFirstArrEle = true;
|
|
|
|
|
- for (int i = 0; i < jarray.size(); i++) {
|
|
|
|
|
- if (!isFirstArrEle) {
|
|
|
|
|
- appender.append(",");
|
|
|
|
|
- }
|
|
|
|
|
- Object obj = jarray.get(i);
|
|
|
|
|
- if (obj instanceof JSONObject) {
|
|
|
|
|
- appender.append(serialJsonOrdered((JSONObject) obj));
|
|
|
|
|
- } else {
|
|
|
|
|
- appender.append("\"" + replaceSlash(obj.toString()) + "\"");
|
|
|
|
|
- }
|
|
|
|
|
- isFirstArrEle = false;
|
|
|
|
|
- }
|
|
|
|
|
- appender.append("]");
|
|
|
|
|
- } else {
|
|
|
|
|
- String value = "";
|
|
|
|
|
- if (val instanceof String) {
|
|
|
|
|
- value = "\"" + replaceSlash(val.toString()) + "\"";
|
|
|
|
|
- } else {
|
|
|
|
|
- value = replaceSlash(val.toString());
|
|
|
|
|
- }
|
|
|
|
|
- appender.append("\"").append(key).append("\":").append(value);
|
|
|
|
|
- }
|
|
|
|
|
- isFirstEle = false;
|
|
|
|
|
- }
|
|
|
|
|
- appender.append("}");
|
|
|
|
|
- return appender.toString();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private static String replaceSlash(String val1) {
|
|
|
|
|
-
|
|
|
|
|
- StringBuilder buffer = new StringBuilder();
|
|
|
|
|
- char[] arr = val1.toCharArray();
|
|
|
|
|
- for (char c : arr) {
|
|
|
|
|
- if (c == '\\') {
|
|
|
|
|
- buffer.append(c).append(c);
|
|
|
|
|
- } else if (c == '\"') {
|
|
|
|
|
- buffer.append('\\').append(c);
|
|
|
|
|
- } else if (c == '\r') {
|
|
|
|
|
- buffer.append("\\r");
|
|
|
|
|
- } else if (c == '\n') {
|
|
|
|
|
- buffer.append("\\n");
|
|
|
|
|
- } else if (c == '\b') {
|
|
|
|
|
- buffer.append("\\b");
|
|
|
|
|
- } else if (c == '\t') {
|
|
|
|
|
- buffer.append("\\t");
|
|
|
|
|
- } else if (c == '\f') {
|
|
|
|
|
- buffer.append("\\f");
|
|
|
|
|
- } else {
|
|
|
|
|
- buffer.append(c);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return buffer.toString();
|
|
|
|
|
|
|
+ private static byte[] getID_IV(String uid) {
|
|
|
|
|
+ String userid = uid + "0000000000000000";
|
|
|
|
|
+ return userid.substring(0, 16).getBytes();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|