|
@@ -0,0 +1,334 @@
|
|
|
|
|
+package com.ydtech.modules.order.utils;
|
|
|
|
|
+
|
|
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
+import com.ydtech.exception.SystemException;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.springframework.util.Base64Utils;
|
|
|
|
|
+
|
|
|
|
|
+import javax.crypto.Cipher;
|
|
|
|
|
+import java.io.ByteArrayOutputStream;
|
|
|
|
|
+import java.security.*;
|
|
|
|
|
+import java.security.spec.PKCS8EncodedKeySpec;
|
|
|
|
|
+import java.security.spec.X509EncodedKeySpec;
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 签名工具
|
|
|
|
|
+ */
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+public class SignatureUtils {
|
|
|
|
|
+
|
|
|
|
|
+ private SignatureUtils(){
|
|
|
|
|
+ throw new IllegalStateException("Utility class");
|
|
|
|
|
+ }
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 加密算法RSA
|
|
|
|
|
+ */
|
|
|
|
|
+ public static final String KEY_ALGORITHM = "RSA";
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 签名算法
|
|
|
|
|
+ */
|
|
|
|
|
+ public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * RSA最大加密明文大小
|
|
|
|
|
+ */
|
|
|
|
|
+ private static final int MAX_ENCRYPT_BLOCK = 117;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * RSA最大解密密文大小
|
|
|
|
|
+ */
|
|
|
|
|
+ private static final int MAX_DECRYPT_BLOCK = 128;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 验签并解密
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 对于<b>银保信</b>,publicKey是指合作方的公钥,privateKey是指银保信的私钥<br>
|
|
|
|
|
+ * 对于<b>合作方</b>,publicKey是指银保信的公钥,privateKey是指合作方的私钥<br>
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param request 原始报文(JSON字符串)
|
|
|
|
|
+ * @param publicKey 公钥
|
|
|
|
|
+ * @param privateKey 私钥
|
|
|
|
|
+ * @param isCheckSign 是否验签
|
|
|
|
|
+ * @param isDecrypt 是否解密
|
|
|
|
|
+ * @return 解密后的明文,验签失败则异常抛出
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String checkSignAndDecrypt(String request, String sign, String publicKey, String privateKey, boolean isCheckSign,
|
|
|
|
|
+ boolean isDecrypt) {
|
|
|
|
|
+ boolean verifyResult = false;
|
|
|
|
|
+ JSONObject requestJSONObject = JSONObject.parseObject(request);
|
|
|
|
|
+ String bizContent = requestJSONObject.getString("bizContent");// 获取的业务数据密文
|
|
|
|
|
+ String signContent = getSignContent(requestJSONObject);// 所有key排序后放入LingkedMap后map.toString()
|
|
|
|
|
+ if (isCheckSign) {
|
|
|
|
|
+ verifyResult = verify(signContent, sign, publicKey);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!isCheckSign) {
|
|
|
|
|
+ verifyResult = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isDecrypt && verifyResult) {
|
|
|
|
|
+ return decryptByPrivateKey(bizContent, privateKey);
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static String checkSignAndDecryptNew(String request, String sign, String publicKey, String privateKey, boolean isCheckSign,
|
|
|
|
|
+ boolean isDecrypt) throws Exception {
|
|
|
|
|
+ boolean verifyResult = false;
|
|
|
|
|
+ JSONObject requestJSONObject = JSONObject.parseObject(request);
|
|
|
|
|
+ String bizContent = requestJSONObject.getString("bizContent");// 获取的业务数据密文
|
|
|
|
|
+ String insurerCode = requestJSONObject.getString("insurerCode");
|
|
|
|
|
+ String sysSourceCode = requestJSONObject.getString("sysSourceCode");
|
|
|
|
|
+ String signContent = getSignContent(requestJSONObject);// 所有key排序后放入LingkedMap后map.toString()
|
|
|
|
|
+ if (isCheckSign) {
|
|
|
|
|
+ verifyResult = verify(signContent, sign, publicKey);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!isCheckSign) {
|
|
|
|
|
+ verifyResult = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isDecrypt && verifyResult) {
|
|
|
|
|
+ String json = decryptByPrivateKey(bizContent, privateKey);
|
|
|
|
|
+ String oldChar = "\\{";
|
|
|
|
|
+ String newChar = "{\"sysSourceCode\": \"" + sysSourceCode + "\",\"insurerCode\": \"" + insurerCode + "\",";
|
|
|
|
|
+ return json.replaceFirst(oldChar, newChar);
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 加密并签名
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 对于<b>银保信</b>,publicKey是指合作方的公钥,privateKey是指银保信的私钥<br>
|
|
|
|
|
+ * 对于<b>合作方</b>,publicKey是指银保信的公钥,privateKey是指合作方的私钥<br>
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param publicKey 公钥
|
|
|
|
|
+ * @param requestContent 报文原文
|
|
|
|
|
+ * @param isCheckSign 是否签名
|
|
|
|
|
+ * @param isEncrypt 是否加密
|
|
|
|
|
+ * @return 加密加签后的返回报文
|
|
|
|
|
+ * @throws Exception
|
|
|
|
|
+ */
|
|
|
|
|
+ public static Map<String, String> encryptAndSign(String privateKey, String publicKey, String requestContent, boolean isCheckSign,
|
|
|
|
|
+ boolean isEncrypt) throws Exception {
|
|
|
|
|
+ JSONObject requestJSONObject = JSONObject.parseObject(requestContent);
|
|
|
|
|
+ String bizContent = requestJSONObject.getString("bizContent");
|
|
|
|
|
+ Map<String, String> map = new HashMap<String, String>();
|
|
|
|
|
+ if (isEncrypt) {
|
|
|
|
|
+ //加密
|
|
|
|
|
+ String encryptBizContent = encryptByPublicKey(bizContent, publicKey);//对业务数据进行加密
|
|
|
|
|
+ requestJSONObject.put("bizContent", encryptBizContent);//将加密后的数据替换原有的明文
|
|
|
|
|
+ map.put("content", requestJSONObject.toJSONString());
|
|
|
|
|
+ if (isCheckSign) {
|
|
|
|
|
+ //加签
|
|
|
|
|
+ String signContent = getSignContent(requestJSONObject);// 所有key排序后放入LingkedMap后map.toString()
|
|
|
|
|
+ String sign = sign(signContent, privateKey);
|
|
|
|
|
+ map.put("signature", sign);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (isCheckSign) {// 只加签、不加密
|
|
|
|
|
+ String signContent = getSignContent(requestJSONObject);// 所有key排序后放入LingkedMap后map.toString()
|
|
|
|
|
+ String sign = sign(signContent, privateKey);
|
|
|
|
|
+ map.put("signature", sign);
|
|
|
|
|
+ }
|
|
|
|
|
+ return map;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 封装待验签的内容
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param sortedParam
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String getSignContent(Map<String, Object> sortedParam) {
|
|
|
|
|
+ LinkedHashMap map = new LinkedHashMap();
|
|
|
|
|
+ List<String> keys = new ArrayList<String>(sortedParam.keySet());
|
|
|
|
|
+ Collections.sort(keys);
|
|
|
|
|
+ for (int i = 0; i < keys.size(); i++) {
|
|
|
|
|
+ String key = keys.get(i);
|
|
|
|
|
+ String value = sortedParam.get(key).toString();
|
|
|
|
|
+ map.put(key, value);
|
|
|
|
|
+ }
|
|
|
|
|
+ return map.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 验签
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param request
|
|
|
|
|
+ * @param sign
|
|
|
|
|
+ * @param
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public static boolean verify(String request, String sign, String publicKey) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ return SignatureUtils.verify(request.getBytes(), publicKey, sign);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("验签异常,inputParams: {} and publicKey: {} and sign: {} and errorMessage: {}", request, publicKey, sign,
|
|
|
|
|
+ e.getMessage(), e);
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 校验数字签名
|
|
|
|
|
+ * </p>
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param data 已加密数据
|
|
|
|
|
+ * @param publicKey 公钥(BASE64编码)
|
|
|
|
|
+ * @param sign 数字签名
|
|
|
|
|
+ * @return
|
|
|
|
|
+ * @throws Exception
|
|
|
|
|
+ */
|
|
|
|
|
+ public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
|
|
|
|
|
+ byte[] keyBytes = Base64Utils.decode(publicKey.getBytes());
|
|
|
|
|
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
|
|
|
|
|
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
|
|
|
|
+ PublicKey publicK = keyFactory.generatePublic(keySpec);
|
|
|
|
|
+ Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
|
|
|
|
|
+ signature.initVerify(publicK);
|
|
|
|
|
+ signature.update(data);
|
|
|
|
|
+ return signature.verify(Base64Utils.decode(sign.getBytes()));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 私钥对数据进行解密
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param bizContent
|
|
|
|
|
+ * @param privateKey
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String decryptByPrivateKey(String bizContent, String privateKey) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ return new String(SignatureUtils.decryptByPrivateKey(Base64Utils.decode(bizContent.getBytes()), privateKey));
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("私钥解密异常,inputParams: {} and privateKey: {} and errorMessage: {}", bizContent, privateKey, e.getMessage(), e);
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * <P>
|
|
|
|
|
+ * 私钥解密
|
|
|
|
|
+ * </p>
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param encryptedData 已加密数据
|
|
|
|
|
+ * @param privateKey 私钥(BASE64编码)
|
|
|
|
|
+ * @return
|
|
|
|
|
+ * @throws Exception
|
|
|
|
|
+ */
|
|
|
|
|
+ public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
|
|
|
|
|
+ byte[] keyBytes = Base64Utils.decode(privateKey.getBytes());
|
|
|
|
|
+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
|
|
|
|
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
|
|
|
|
+ Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
|
|
|
|
|
+ Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
|
|
|
|
+ cipher.init(Cipher.DECRYPT_MODE, privateK);
|
|
|
|
|
+ int inputLen = encryptedData.length;
|
|
|
|
|
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
|
|
+ int offSet = 0;
|
|
|
|
|
+ byte[] cache;
|
|
|
|
|
+ int i = 0;
|
|
|
|
|
+ // 对数据分段解密
|
|
|
|
|
+ while (inputLen - offSet > 0) {
|
|
|
|
|
+ if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
|
|
|
|
|
+ cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
|
|
|
|
|
+ }
|
|
|
|
|
+ out.write(cache, 0, cache.length);
|
|
|
|
|
+ i++;
|
|
|
|
|
+ offSet = i * MAX_DECRYPT_BLOCK;
|
|
|
|
|
+ }
|
|
|
|
|
+ byte[] decryptedData = out.toByteArray();
|
|
|
|
|
+ out.close();
|
|
|
|
|
+ return decryptedData;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 公钥加密
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param request
|
|
|
|
|
+ * @param publicKey
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String encryptByPublicKey(String request, String publicKey) throws Exception {
|
|
|
|
|
+ return new String(Base64Utils.encode(SignatureUtils.encryptByPublicKey(request.getBytes(), publicKey)));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 公钥加密
|
|
|
|
|
+ * </p>
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param data 源数据
|
|
|
|
|
+ * @param publicKey 公钥(BASE64编码)
|
|
|
|
|
+ * @return
|
|
|
|
|
+ * @throws Exception
|
|
|
|
|
+ */
|
|
|
|
|
+ public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
|
|
|
|
|
+ byte[] keyBytes = Base64Utils.decode(publicKey.getBytes());
|
|
|
|
|
+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
|
|
|
|
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
|
|
|
|
+ Key publicK = keyFactory.generatePublic(x509KeySpec);
|
|
|
|
|
+ // 对数据加密
|
|
|
|
|
+ Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
|
|
|
|
+ cipher.init(Cipher.ENCRYPT_MODE, publicK);
|
|
|
|
|
+ int inputLen = data.length;
|
|
|
|
|
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
|
|
+ int offSet = 0;
|
|
|
|
|
+ byte[] cache;
|
|
|
|
|
+ int i = 0;
|
|
|
|
|
+ // 对数据分段加密
|
|
|
|
|
+ while (inputLen - offSet > 0) {
|
|
|
|
|
+ if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
|
|
|
|
|
+ cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ cache = cipher.doFinal(data, offSet, inputLen - offSet);
|
|
|
|
|
+ }
|
|
|
|
|
+ out.write(cache, 0, cache.length);
|
|
|
|
|
+ i++;
|
|
|
|
|
+ offSet = i * MAX_ENCRYPT_BLOCK;
|
|
|
|
|
+ }
|
|
|
|
|
+ byte[] encryptedData = out.toByteArray();
|
|
|
|
|
+ out.close();
|
|
|
|
|
+ return encryptedData;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 加签
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param
|
|
|
|
|
+ * @param privateKey
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String sign(String request, String privateKey) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ return SignatureUtils.sign(request.getBytes(), privateKey);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("加签异常,inputParams: {} and privateKey: {} and errorMessage: {}", request, privateKey, e.getMessage(), e);
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 用私钥对信息生成数字签名
|
|
|
|
|
+ * </p>
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param data 已加密数据
|
|
|
|
|
+ * @param privateKey 私钥(BASE64编码)
|
|
|
|
|
+ * @return
|
|
|
|
|
+ * @throws Exception
|
|
|
|
|
+ */
|
|
|
|
|
+ public static String sign(byte[] data, String privateKey) throws Exception {
|
|
|
|
|
+ byte[] keyBytes = Base64Utils.decode(privateKey.getBytes());
|
|
|
|
|
+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
|
|
|
|
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
|
|
|
|
+ PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
|
|
|
|
|
+ Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
|
|
|
|
|
+ signature.initSign(privateK);
|
|
|
|
|
+ signature.update(data);
|
|
|
|
|
+ return new String(Base64Utils.encode(signature.sign()));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|