增加AES加密方式,兼容旧版加密

beta
kk 2 years ago
parent 673faa474e
commit 053eafab6f
  1. 101
      jianshui-common/src/main/java/com/jianshui/common/utils/encrypt/AisinoInvoiceDecryptUtil.java
  2. 109
      jianshui-common/src/main/java/com/jianshui/common/utils/encrypt/AisinoInvoiceEncryptUtil.java
  3. 2
      jianshui-invoice/src/main/java/com/jianshui/invoice/service/impl/adapter/request/AisinoInvoiceRequestAdapterImpl.java
  4. 10
      jianshui-invoice/src/main/java/com/jianshui/invoice/service/impl/api/AisinoConsoleInvoiceApiZhongQiServiceImpl.java
  5. 6
      jianshui-invoice/src/main/java/com/jianshui/invoice/task/InvoiceBackTask.java
  6. 10
      jianshui-invoice/src/main/java/com/jianshui/invoice/utils/InvoiceTest.java

@ -8,11 +8,15 @@ import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
/**
* 功能描述
@ -20,6 +24,12 @@ import java.security.MessageDigest;
*/
public class AisinoInvoiceDecryptUtil {
private static final String ALGORITHM = "AES/GCM/NoPadding";
private static final int KEY_SIZE = 128; // 密钥长度为128位
private static final int IV_LENGTH = 12; // 初始化向量长度为12字节(96位)
private static final int TAG_LENGTH = 16; // GCM模式的认证标签长度为16字节
/**
* 解密api里order请求同时兼容老版本order里面包了identity的版本
*
@ -99,6 +109,93 @@ public class AisinoInvoiceDecryptUtil {
return new BASE64Encoder().encode(temp);
}
/**
* @author kk
* @date 2023/11/21 14:45
* @param: [xmlStr, mKey]
* @return: 新增AES加密方式兼容旧版
*/
public static String decrypt(String xmlStr, String mKey) throws Exception {
// base64解码
BASE64Decoder decoder = new BASE64Decoder();
byte[] encBuf = null;
try {
if (xmlStr != null) {
xmlStr = xmlStr.replaceAll(" ", "+");//解决URL里加号变空格
}
encBuf = decoder.decodeBuffer(xmlStr);
} catch (IOException e) {
e.printStackTrace();
}
// 取密钥和偏转向量
byte[] key = new byte[8];
byte[] iv = new byte[8];
getKeyIV(mKey, key, iv);
SecretKeySpec deskey = new SecretKeySpec(key, "DES");
IvParameterSpec ivParam = new IvParameterSpec(iv);
// 使用DES算法解密
byte[] temp = null;
try {
temp = DES_CBC_Decrypt(encBuf, deskey, ivParam);
// 进行解密后的md5Hash校验
byte[] md5Hash = null;
try {
md5Hash = MD5Hash(temp, 16, temp.length - 16);
} catch (Exception e) {
e.printStackTrace();
}
// 进行解密校检
for (int i = 0; i < md5Hash.length; i++) {
if (md5Hash[i] != temp[i]) {
// System.out.println(md5Hash[i] + "MD5校验错误。" + temp[i]);
throw new Exception("MD5校验错误。");
}
}
// 返回解密后的数组,其中前16位MD5Hash码要除去。
return new String(temp, 16, temp.length - 16, "utf-8");
} catch (Exception e) {
temp = AES_CBC_Decrypt(hexToBytes(xmlStr), mKey.getBytes(), ivParam);
return new String(temp);
}
}
// 新版AES解密方法
private static byte[] AES_CBC_Decrypt(byte[] data, byte[] key, IvParameterSpec ivSpec) throws Exception {
byte[] iv = key;
System.arraycopy(data, 0, iv, 0, IV_LENGTH);
byte[] encryptedData = new byte[data.length - IV_LENGTH];
System.arraycopy(data, IV_LENGTH, encryptedData, 0, encryptedData.length);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv);
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
return cipher.doFinal(encryptedData);
}
/** 还原方法*/
public static byte[] hexToBytes(String hexString) {
int len = hexString.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ Character.digit(hexString.charAt(i+1), 16));
}
return data;
}
/**
* <li>
* 方法名称:encrypt</li> <li>
@ -114,7 +211,7 @@ public class AisinoInvoiceDecryptUtil {
* @return 解密后的字符串
* @throws Exception
*/
public static String decrypt(String xmlStr, String mKey) throws Exception {
/*public static String decrypt(String xmlStr, String mKey) throws Exception {
// base64解码
BASE64Decoder decoder = new BASE64Decoder();
byte[] encBuf = null;
@ -161,7 +258,7 @@ public class AisinoInvoiceDecryptUtil {
// 返回解密后的数组,其中前16位MD5Hash码要除去。
return new String(temp, 16, temp.length - 16, "utf-8");
}
}*/
/**
* <li>

@ -1,14 +1,20 @@
package com.jianshui.common.utils.encrypt;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.SecureUtil;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
/**
* 功能描述
@ -16,6 +22,12 @@ import java.security.MessageDigest;
*/
public class AisinoInvoiceEncryptUtil {
private static final String ALGORITHM = "AES/GCM/NoPadding";
private static final int KEY_SIZE = 128; // 密钥长度为128位
private static final int IV_LENGTH = 12; // 初始化向量长度为12字节(96位)
private static final int TAG_LENGTH = 16; // GCM模式的认证标签长度为16字节
/**
* <li>
* 方法名称:encrypt</li> <li>
@ -95,6 +107,73 @@ public class AisinoInvoiceEncryptUtil {
return cipherByte;
}
/** AES 加密接口*/
public static byte[] AES_Encrypt(byte[] sourceBuf,
byte[] keys, IvParameterSpec ivParam) throws Exception {
byte[] iv = keys;
Cipher cipher = Cipher.getInstance(ALGORITHM);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv);
SecretKeySpec keySpec = new SecretKeySpec(keys, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);
byte[] ciphertext = cipher.doFinal(sourceBuf);
// 将初始化向量和密文拼接在一起
byte[] result = new byte[IV_LENGTH + ciphertext.length];
System.arraycopy(iv, 0, result, 0, IV_LENGTH);
System.arraycopy(ciphertext, 0, result, IV_LENGTH, ciphertext.length);
return result;
}
/** 转为十六进制字符串*/
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
/** AES加密方法*/
public static String encryptAES(String xmlStr, String mkey) {
byte[] encrypt = {};
try {
// 取需要加密内容的utf-8编码。
if (xmlStr != null) {
encrypt = xmlStr.getBytes("utf-8");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 取MD5Hash码,并组合加密数组
byte[] md5Hasn = null;
try {
md5Hasn = MD5Hash(encrypt, 0, encrypt.length);
} catch (Exception e) {
e.printStackTrace();
}
// 组合消息体
byte[] totalByte = addMD5(md5Hasn, encrypt);
// 取密钥和偏转向量
byte[] iv = new byte[16];
IvParameterSpec ivParam = new IvParameterSpec(iv);
// 使用DES算法使用加密消息体
byte[] temp = null;
try {
temp = AES_Encrypt(totalByte, mkey.getBytes(), ivParam);
} catch (Exception e) {
e.printStackTrace();
}
// 使用Base64加密后返回
return bytesToHex(temp);
}
/**
* <li>
@ -152,6 +231,7 @@ public class AisinoInvoiceEncryptUtil {
return resutlByte;
}
/**
* <li>
* 方法名称:getKeyIV</li> <li>
@ -188,9 +268,32 @@ public class AisinoInvoiceEncryptUtil {
public static void main(String[] args) throws Exception {
// 生成一个随机的AES密钥
SecretKey secretKey = SecureUtil.generateKey("AES");
// 转换为16进制字符串
String keyHex = HexUtil.encodeHexStr(secretKey.getEncoded());
System.out.println("AES密钥:");
System.out.println(keyHex);
String str = "test";
String key = "LTEO+oOgWMsuQAOUglqXuQ=="; // 2233
str = encrypt(str, key);
System.out.println(str);
// String key = "LTEO+oOgWMsuQAOUglqXuQ=="; // 2233
String key = "c5fdd10b2abd23b6c1c077935da40fca"; // 2233
// str = encrypt(str, key);
// System.out.println(str);
System.out.println(encryptAES(str,key));
}
}

@ -330,7 +330,7 @@ public class AisinoInvoiceRequestAdapterImpl implements IInvoiceRequestService {
// 平台解密
try {
// TODO: 2023/9/20wozheb
// TODO: 2023/9/20
order = AisinoInvoiceDecryptUtil.decrypt(order, JKey);
} catch (Exception e) {
e.printStackTrace();

@ -509,23 +509,23 @@ public class AisinoConsoleInvoiceApiZhongQiServiceImpl implements IInvoiceApiSer
if ("0000".equals(status)) {
invoiceBack.setStatus("1");
invoiceBack.setBackMsg(message.substring(0,200));
invoiceBack.setBackMsg(message != null ? message.substring(0, Math.min(message.length(), 200)) : "");
invoiceBack.setUpdateTime(new Date());
invoiceBackMapper.updateInvoiceBack(invoiceBack);
} else if ("9999".equals(status)) {
invoiceBack.setStatus("3");
invoiceBack.setBackMsg(message.substring(0,200));
invoiceBack.setBackMsg(message != null ? message.substring(0, Math.min(message.length(), 200)) : "");
invoiceBack.setUpdateTime(new Date());
invoiceBackMapper.updateInvoiceBack(invoiceBack);
} else {
invoiceBack.setStatus("2");
invoiceBack.setUpdateTime(new Date());
invoiceBack.setBackMsg(status + message.substring(0,200));
invoiceBack.setBackMsg(status + message != null ? message.substring(0, Math.min(message.length(), 200)) : "");
invoiceBackMapper.updateInvoiceBack(invoiceBack);
}
}
} catch (Exception e) {
log.info("【控制台】发票回调接口,发送数据异常,id={}", id);
log.info("【控制台】发票回调接口,发送数据异常,id={},e={}", id,e);
invoiceBack.setStatus("2");
invoiceBack.setBackMsg("发送数据异常!");
invoiceBackMapper.updateInvoiceBack(invoiceBack);
@ -533,6 +533,8 @@ public class AisinoConsoleInvoiceApiZhongQiServiceImpl implements IInvoiceApiSer
}
@Override
public HXResponse mailDelivery(InvoiceMailDeliveryDTO mailDeliveryDTO, Companyservice companyservice) {
return null;

@ -129,17 +129,17 @@ public class InvoiceBackTask
if("0000".equals(status)){
invoiceBack.setStatus("1");
invoiceBack.setBackMsg(message.substring(0,200));
invoiceBack.setBackMsg(message != null ? message.substring(0, Math.min(message.length(), 200)) : "");
invoiceBack.setUpdateTime(new Date());
invoiceBackMapper.updateInvoiceBack(invoiceBack);
}else if("9999".equals(status)){
invoiceBack.setStatus("3");
invoiceBack.setBackMsg(message.substring(0,200));
invoiceBack.setBackMsg(message != null ? message.substring(0, Math.min(message.length(), 200)) : "");
invoiceBack.setUpdateTime(new Date());
invoiceBackMapper.updateInvoiceBack(invoiceBack);
}else {
invoiceBack.setStatus("3");
invoiceBack.setBackMsg(status+message.substring(0,200));
invoiceBack.setBackMsg(status+message != null ? message.substring(0, Math.min(message.length(), 200)) : "");
invoiceBack.setUpdateTime(new Date());
invoiceBackMapper.updateInvoiceBack(invoiceBack);
}

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save