diff --git a/doc/~$交易所数据库加密 java 接口新增.docx b/doc/~$交易所数据库加密 java 接口新增.docx new file mode 100644 index 0000000..7c44ef3 Binary files /dev/null and b/doc/~$交易所数据库加密 java 接口新增.docx differ diff --git a/doc/黄金交易所数据库加密 java 接口新增.docx b/doc/黄金交易所数据库加密 java 接口新增.docx index d7c563d..106219f 100644 Binary files a/doc/黄金交易所数据库加密 java 接口新增.docx and b/doc/黄金交易所数据库加密 java 接口新增.docx differ diff --git a/pack/doc/黄金交易所数据库加密 java 接口新增.docx b/pack/doc/黄金交易所数据库加密 java 接口新增.docx deleted file mode 100644 index d7c563d..0000000 Binary files a/pack/doc/黄金交易所数据库加密 java 接口新增.docx and /dev/null differ diff --git a/pom.xml b/pom.xml index c6988c9..b206c3e 100644 --- a/pom.xml +++ b/pom.xml @@ -1,48 +1,70 @@ - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - com.sunyard.sge.database - sydapi-database - 1.0 + com.sunyard.sge.database + sydapi-database + 1.0 - sydapi-database + sydapi-database - - UTF-8 - 1.7 - 1.7 - + + UTF-8 + 1.8 + 1.8 + 2.17.0 + - - - junit - junit - 4.11 - test - + + + junit + junit + 4.11 + test + - - com.sunyard - sydapi4j - 1.0.20220712 - + + com.sunyard + sydapi4j + 1.0.20220712 + - + + org.apache.logging.log4j + log4j-api + ${log.version} + + + org.apache.logging.log4j + log4j-core + ${log.version} + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log.version} + + + org.apache.logging.log4j + log4j-jcl + ${log.version} + - + - - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - 8 - - - - + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + diff --git a/src/main/java/com/sunyard/sge/database/Consts.java b/src/main/java/com/sunyard/sge/database/Consts.java index 4a45873..7df5eae 100644 --- a/src/main/java/com/sunyard/sge/database/Consts.java +++ b/src/main/java/com/sunyard/sge/database/Consts.java @@ -3,4 +3,17 @@ package com.sunyard.sge.database; public class Consts { public static final int ECB_DEC = 0; public static final int ECB_ENC = 1; + + + // 唯一包 + public static final int PkgNumAll = 0; + + // 首包 + public static final int PkgNumHead = 1; + + // 中间包 + public static final int PkgNumMiddle = 2; + + // 结束包 + public static final int PkgNumTail = 3; } diff --git a/src/main/java/com/sunyard/sge/database/LongDataReturn.java b/src/main/java/com/sunyard/sge/database/LongDataReturn.java index be4ddf2..3874484 100644 --- a/src/main/java/com/sunyard/sge/database/LongDataReturn.java +++ b/src/main/java/com/sunyard/sge/database/LongDataReturn.java @@ -1,4 +1,20 @@ package com.sunyard.sge.database; -public class LongDataReturn { +public class LongDataReturn { + + private T1 procData; + private T2 data; + + public LongDataReturn(T1 procData, T2 data) { + this.procData = procData; + this.data = data; + } + + public T1 getProcData() { + return procData; + } + + public T2 getData() { + return data; + } } diff --git a/src/main/java/com/sunyard/sge/database/SydApi.java b/src/main/java/com/sunyard/sge/database/SydApi.java index 408b7a5..19d23cd 100644 --- a/src/main/java/com/sunyard/sge/database/SydApi.java +++ b/src/main/java/com/sunyard/sge/database/SydApi.java @@ -7,8 +7,23 @@ import java.util.List; */ public interface SydApi { - void warmUpMode(boolean use); + /** + * 设置全局日志相应的配置 + * + *@param pcLogPath: 输入。日志存储路径 + *@param iLogLevel: 输入。日志级别设置 + * 0:不记录日志, + * 1:记录网络层错误日志, + * 2:记录接口错误日志及网络层错误日志, + * 3:记录正确日志及错误日志 + * + * @return 无 + **/ + static void SYD_SetLogConfig( + String pcLogPath, + int iLogLevel) { + } /** * 建立到指定地址和端口号的签名服务器的 TCP/IP 连接,返回 API 操作对象 SydApi。 @@ -20,6 +35,7 @@ public interface SydApi { * @param iDealTimeOut 交易接口超时设定,单位毫秒(不超过10ms)。 * @return SydApi 的对象,只要有设备可用则返回。 */ + @Deprecated SydApi SYD_Connect_Ex( String[] pcIpList, int[] iPortList, diff --git a/src/main/java/com/sunyard/sge/database/SydApi4Database.java b/src/main/java/com/sunyard/sge/database/SydApi4Database.java index 6e77ddb..99f36b1 100644 --- a/src/main/java/com/sunyard/sge/database/SydApi4Database.java +++ b/src/main/java/com/sunyard/sge/database/SydApi4Database.java @@ -1,6 +1,7 @@ package com.sunyard.sge.database; import com.sunyard.SydApiException; +import com.sunyard.proto.Util; import com.sunyard.util.SYMUtil; import racal.sunyard.main.SydApi4j; @@ -8,136 +9,355 @@ import java.util.List; /** * 上海黄金交易所 - 数据库加密方案 - * */ -public class SydApi4Database implements SydApi -{ +public class SydApi4Database implements SydApi { -// public static void SYD_SetLogConfig ( -// String pcLogPath, -// int iLogLevel) { -// } - - private SydApi4j api4j = null; - - @Override - public void warmUpMode(boolean use) { - this.api4j.warmUpMode( use ); - } + private SydApi4j[] hsms = null; @Override public SydApi SYD_Connect_Ex(String[] pcIpList, int[] iPortList, int iConnectTimeOut, int iDealTimeOut) { - - - if ( null == pcIpList && - null == iPortList && - pcIpList.length != iPortList.length ) { - throw new IllegalArgumentException("入参错误"); - } - if ( null != api4j ) { - this.SYD_Disconnect_Ex(); - } - - api4j = (SydApi4j) new SydApi4j().connect( pcIpList[0], iPortList[0], null, iConnectTimeOut, iDealTimeOut); - + SydApi4j api = (SydApi4j) new SydApi4j().connect(pcIpList[0], iPortList[0], null, iConnectTimeOut); + hsms = new SydApi4j[]{ api }; return this; } @Override public void SYD_Disconnect_Ex() { - if ( null != this.api4j ) { - try { - this.api4j.disconnect(); - }catch ( Exception e ){ - } - } - this.api4j = null; + // 配合链接池,不再需要释放。 +// if ( null != api ) { +// try { +// api.disconnect(); +// }catch ( Exception e ){ +// } +// } +// api = null; } @Override public String SYD_SM3_Hash_ShortData(byte[] pcData) { - return null; + if (null == this.hsms || this.hsms.length < 1) { + throw new SydApiException(-1); + } + + SydApiException le = null; + for (SydApi4j api : this.hsms) { + try { + byte[] hash = api.SYD_SM3_LongData(pcData, null, 0); + return Util.bytes2HexString(hash); + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } + } + throw le; } @Override public LongDataReturn SYD_SM3_Hash_LongData(byte[] pcData, int iPkgNum, String pcProcData) { - return null; + if (null == this.hsms || this.hsms.length < 1) { + throw new SydApiException(-1); + } + + byte[] procData = null; + if (2 == iPkgNum || 3 == iPkgNum) { + procData = Util.hexString2Bytes(pcProcData); + } + SydApiException le = null; + for (SydApi4j api : this.hsms) { + try { + byte[] hash = api.SYD_SM3_LongData(pcData, procData, iPkgNum); + + if (0 == iPkgNum || 3 == iPkgNum) { + return new LongDataReturn(null, Util.bytes2HexString(hash)); + } else { + return new LongDataReturn(Util.bytes2HexString(hash), null); + } + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } + } + throw le; } @Override public byte[] SYD_SM4_ShortData(int iKeyIndex, byte[] pcData, int iFlag) { - if ( null == this.api4j ) { + if (null == this.hsms || this.hsms.length < 1) { + throw new SydApiException(-1); + } + + String keyIndex = String.format("%08d", iKeyIndex); + SydApiException le = null; + for (SydApi4j api : this.hsms) { + try { + + if (Consts.ECB_ENC == iFlag) { + return api.SYMEncryptData( + com.sunyard.SydApi.NALG_SM4, + "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", keyIndex), + 1, + pcData); + } else { + return api.SYMDecryptData( + com.sunyard.SydApi.NALG_SM4, + "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", keyIndex), + 1, + pcData); + } + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } + } + throw le; + } + + @Override + public List SYD_SM4_BatchData(int[] iKeyIndex, List pcData, int iFlag) { + if (null == this.hsms || this.hsms.length < 1) { + throw new SydApiException(-1); + } + + String[] keys = new String[iKeyIndex.length]; + for (int i = 0; i < iKeyIndex.length; i++) { + keys[i] = "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", String.format("%08d", iKeyIndex[i])); + } + + SydApiException le = null; + for (SydApi4j api : this.hsms) { + try { + if (Consts.ECB_ENC == iFlag) { + return api.SYMEncryptDecryptBatchData(8, 1, null, keys, 1, pcData); + } else { + return api.SYMEncryptDecryptBatchData(9, 1, null, keys, 1, pcData); + } + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } + } + throw le; + } + + @Override + public byte[] SYD_SM4_LongData(int iKeyIndex, byte[] pcData, int iPkgNum, int iFlag) { + if (null == this.hsms || this.hsms.length < 1) { throw new SydApiException(-1); } String keyIndex = String.format("%08d", iKeyIndex); - if ( Consts.ECB_ENC == iFlag ) { - return this.api4j.SYMEncryptData( - com.sunyard.SydApi.NALG_SM4, - "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", keyIndex), - 1, - pcData ); - } else { - return this.api4j.SYMDecryptData( - com.sunyard.SydApi.NALG_SM4, - "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", keyIndex), - 1, - pcData ); - } - } + SydApiException le = null; + for (SydApi4j api : this.hsms) { + try { + if (Consts.ECB_ENC == iFlag) { + return api.SYD_SM4_LongData( + 8, + 1, null, + "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", keyIndex), + 1, + pcData, iPkgNum); + } else { + return api.SYD_SM4_LongData( + 9, + 1, null, + "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", keyIndex), + 1, + pcData, iPkgNum); + } - @Override - public List SYD_SM4_BatchData(int[] iKeyIndex, List pcData, int iFlag) { - if ( null == this.api4j ) { - throw new SydApiException(-1); + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } } - - String[] keys = new String[ iKeyIndex.length ]; - for ( int i = 0 ; i < iKeyIndex.length ; i++ ) { - keys[i] = "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", String.format("%08d", iKeyIndex[i] )); - } - - if ( Consts.ECB_ENC == iFlag ) { - return this.api4j.SYMEncryptDecryptBatchData(8, keys, 1, pcData); - } else { - return this.api4j.SYMEncryptDecryptBatchData(9, keys, 1, pcData); - } - } - - @Override - public byte[] SYD_SM4_LongData(int iKeyIndex, byte[] pcData, int iPkgNum, int iFlag) { - return new byte[0]; + throw le; } @Override public String[] SYD_SM4Mac_BatchData(int[] iKeyIndex, List pcData) { - return new String[0]; + if (null == this.hsms || this.hsms.length < 1) { + throw new SydApiException(-1); + } + + String[] keys = new String[iKeyIndex.length]; + for (int i = 0; i < iKeyIndex.length; i++) { + keys[i] = "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", String.format("%08d", iKeyIndex[i])); + } + SydApiException le = null; + for (SydApi4j api : this.hsms) { + try { + List list = api.SYMEncryptDecryptBatchData(8, 2, null, keys, 1, pcData); + String[] ret = new String[list.size()]; + for (int i = 0; i < list.size(); i++) { + byte[] mac = new byte[16]; + byte[] buff = list.get(i); + System.arraycopy(buff, buff.length - 16, mac, 0, 16); + ret[i] = Util.bytes2HexString(buff); + } + return ret; + + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } + } + throw le; } @Override public boolean[] SYD_SM4Mac_BatchData(int[] iKeyIndex, List pcData, String[] pcMac) { - return new boolean[0]; + if (null == this.hsms || this.hsms.length < 1) { + throw new SydApiException(-1); + } + + String[] keys = new String[iKeyIndex.length]; + for (int i = 0; i < iKeyIndex.length; i++) { + keys[i] = "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", String.format("%08d", iKeyIndex[i])); + } + SydApiException le = null; + for (SydApi4j api : this.hsms) { + try { + + List list = api.SYMEncryptDecryptBatchData(8, 2, null, keys, 1, pcData); + boolean[] ret = new boolean[list.size()]; + for (int i = 0; i < list.size(); i++) { + byte[] mac = new byte[16]; + byte[] buff = list.get(i); + System.arraycopy(buff, buff.length - 16, mac, 0, 16); + ret[i] = pcMac[i].equals(Util.bytes2HexString(buff)); + } + + return ret; + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } + } + throw le; } @Override public LongDataReturn SYD_SM4Mac_LongData(int iKeyIndex, byte[] pcData, int iPkgNum, String pcProcData) { - return null; + if (null == this.hsms || this.hsms.length < 1) { + throw new SydApiException(-1); + } + + String keyIndex = String.format("%08d", iKeyIndex); + + byte[] iv = null; + + // 仅一包 和 第一包 忽略 pcProcData 参数 + if (Consts.PkgNumAll != iPkgNum && Consts.PkgNumHead != iPkgNum) { + iv = pcProcData.getBytes(); + } + + SydApiException le = null; + for (SydApi4j api : this.hsms) { + try { + byte[] ret = api.SYD_SM4_LongData( + 8, + 2, iv, + "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", keyIndex), + 1, + pcData, iPkgNum); + + byte[] mac = new byte[16]; + System.arraycopy(ret, ret.length - 16, mac, 0, 16); + + // 仅一包 和 尾包 返回最终结果 + if (Consts.PkgNumAll == iPkgNum || Consts.PkgNumTail == iPkgNum) { + return new LongDataReturn<>(null, Util.bytes2HexString(mac)); + } else { + // 返回中间值 + return new LongDataReturn<>(Util.bytes2HexString(mac), null); + } + + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } + } + throw le; } @Override public LongDataReturn SYD_SM4Mac_LongData(int iKeyIndex, byte[] pcData, int iPkgNum, String pcProcData, String pcMac) { - return null; + + LongDataReturn ret = SYD_SM4Mac_LongData(iKeyIndex, pcData, iPkgNum, pcProcData); + + // 仅一包 和 尾包 返回最终结果 + if (Consts.PkgNumAll == iPkgNum || Consts.PkgNumTail == iPkgNum) { + return new LongDataReturn<>(null, pcMac.equals(ret.getData())); + } else { + // 返回中间值 + return new LongDataReturn<>(ret.getProcData(), false); + } } @Override public String SYD_SM4Mac_ShortData(int iKeyIndex, byte[] pcData) { - return null; + + if (null == this.hsms || this.hsms.length < 1) { + throw new SydApiException(-1); + } + + String keyIndex = "SK" + SYMUtil.genPrivateKeyMark("000000", "00A", String.format("%08d", iKeyIndex)); + + SydApiException le = null; + for (SydApi4j api : this.hsms) { + try { + + return api.SYD_SM4Mac_ShortData(keyIndex, pcData); + + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } + } + throw le; } @Override public boolean SYD_SM4Mac_ShortData(int iKeyIndex, byte[] pcData, String pcMac) { - return false; + if (null == this.hsms || this.hsms.length < 1) { + throw new SydApiException(-1); + } + + if (null == pcMac) { + throw new IllegalArgumentException(); + } + + String mac = this.SYD_SM4Mac_ShortData(iKeyIndex, pcData); + + return pcMac.equals(mac); } } diff --git a/src/main/java/com/sunyard/sge/database/SydApiBuilder.java b/src/main/java/com/sunyard/sge/database/SydApiBuilder.java new file mode 100644 index 0000000..b626259 --- /dev/null +++ b/src/main/java/com/sunyard/sge/database/SydApiBuilder.java @@ -0,0 +1,65 @@ +package com.sunyard.sge.database; + +import com.sunyard.sge.database.pool.HsmLinkInfo; +import com.sunyard.sge.database.pool.SydApiPool; +import com.sunyard.sge.log.LogFactory; +import org.slf4j.Logger; + + +public class SydApiBuilder { + + private SydApiPool pool; + + public SydApiBuilder( + String[] pcIpList, + int[] iPortList, + int iConnectTimeOut, + int iDealTimeOut + ) { + Logger log = LogFactory.getLogger(); + log.debug("创建链接"); + + HsmLinkInfo[] linkInfo = HsmLinkInfo.mutiHsmLinkInfo(pcIpList, iPortList, iConnectTimeOut, iDealTimeOut); + this.pool = new SydApiPool(linkInfo); + + warmUp( pcIpList, iPortList, iConnectTimeOut, iDealTimeOut ); + } + + public SydApi build() { + return pool.get(); + } + + + private void warmUp(String[] pcIpList, + int[] iPortList, + int iConnectTimeOut, + int iDealTimeOut){ + SydApi api = null; + try { + api = new SydApi4Database(); + api.SYD_Connect_Ex( pcIpList, iPortList, iConnectTimeOut, iDealTimeOut ); + + try { + + api.SYD_SM3_Hash_ShortData( new byte[8] ); + + }catch ( Exception e) { + // 忽略 + } + + try { + + api.SYD_SM4_ShortData( 0 , new byte[16], Consts.ECB_ENC ); + + }catch ( Exception e) { + // 忽略 + } + } catch ( Exception e ){ + // 忽略预热失败 + } finally { + if ( null != api ) { + api.SYD_Disconnect_Ex(); + } + } + } +} diff --git a/src/main/java/com/sunyard/sge/database/SydApiConfig.java b/src/main/java/com/sunyard/sge/database/SydApiConfig.java new file mode 100644 index 0000000..eea5aaf --- /dev/null +++ b/src/main/java/com/sunyard/sge/database/SydApiConfig.java @@ -0,0 +1,17 @@ +package com.sunyard.sge.database; +/** + * 日志配置接口 + * */ +public class SydApiConfig { + + // 数据包长度 + private final int MaxDataLenEachPack = 4064; + + // 批量数据包,单包数据长度 + // 加密 + private final int MaxDataLenEachBatchPackEn = 1024; + // 解密 + private final int MaxDataLenEachBatchPackDe = 1040; + + +} diff --git a/src/main/java/com/sunyard/sge/database/SydConfigApi.java b/src/main/java/com/sunyard/sge/database/SydConfigApi.java deleted file mode 100644 index 02cbd7e..0000000 --- a/src/main/java/com/sunyard/sge/database/SydConfigApi.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.sunyard.sge.database; -/** - * - * 日志配置接口 - * */ -public interface SydConfigApi { - - /** - * 设置日志相应的配置 - * - *@param pcLogPath: 输入。日志存储路径 - *@param iLogPathLen: 输入。日志路径长度。 - *@param iLogLevel: 输入。日志级别设置 0:不记录日志,1:记录网络层错误日志,2:记录接口错误日志及网络层错误日志,3:记录正确日志及错误日志 - * - * @return null - * */ - - static void SYD_SetLogConfig( - String pcLogPath, - int iLogPathLen, - int iLogLevel) { - - } -} diff --git a/src/main/java/com/sunyard/sge/database/pool/HsmLinkInfo.java b/src/main/java/com/sunyard/sge/database/pool/HsmLinkInfo.java new file mode 100644 index 0000000..4d35796 --- /dev/null +++ b/src/main/java/com/sunyard/sge/database/pool/HsmLinkInfo.java @@ -0,0 +1,69 @@ +package com.sunyard.sge.database.pool; + + +import com.sunyard.sge.log.LogFactory; +import org.slf4j.Logger; + +/** + * 到加密机的链接信息 + */ +public class HsmLinkInfo { + + private String pcIp; + private int iPort; + private int iConnectTimeOut; + private int iDealTimeOut; + + + public HsmLinkInfo(String pcIp, int iPort, int iConnectTimeOut, int iDealTimeOut) { + this.pcIp = pcIp; + this.iPort = iPort; + this.iConnectTimeOut = iConnectTimeOut; + this.iDealTimeOut = iDealTimeOut; + } + + public static HsmLinkInfo[] mutiHsmLinkInfo(String[] pcIpList, int[] iPortList, int iConnectTimeOut, int iAllDealTimeOut) { + Logger log = LogFactory.getLogger(); + log.debug("链接参数整理"); + + if (null == pcIpList && + null == iPortList && + pcIpList.length != iPortList.length) { + log.error("加密机配置 ip 和 port 数量错误"); + throw new IllegalArgumentException("入参错误"); + } + + if ( iAllDealTimeOut < pcIpList.length) { + log.error("加密机配置交易时间过短"); + throw new IllegalArgumentException("入参错误"); + } + + // 交易时间进行处理 + int iDealTimeOut = iAllDealTimeOut / pcIpList.length; + + + HsmLinkInfo[]hsms = new HsmLinkInfo[ pcIpList.length ]; + for ( int i = 0 ; i < pcIpList.length ; i++ ) { + hsms[ i ] = new HsmLinkInfo( pcIpList[i], iPortList[i], iConnectTimeOut, iDealTimeOut ); + } + + return hsms; + } + + + public String getPcIp() { + return pcIp; + } + + public int getiPort() { + return iPort; + } + + public int getiConnectTimeOut() { + return iConnectTimeOut; + } + + public int getiDealTimeOut() { + return iDealTimeOut; + } +} diff --git a/src/main/java/com/sunyard/sge/database/pool/SydApiPool.java b/src/main/java/com/sunyard/sge/database/pool/SydApiPool.java new file mode 100644 index 0000000..e211822 --- /dev/null +++ b/src/main/java/com/sunyard/sge/database/pool/SydApiPool.java @@ -0,0 +1,51 @@ +package com.sunyard.sge.database.pool; + +import com.sunyard.sge.database.SydApi; +import com.sunyard.sge.pool.ThreadBasedConnectPool; +import racal.sunyard.main.SydApi4j; + +public class SydApiPool extends ThreadBasedConnectPool { + + private HsmLinkInfo[] linkInfos; + + public SydApiPool(HsmLinkInfo[] linkInfos) { + super(); + this.linkInfos = linkInfos; + } + + // 继承 初始化 + protected SydApi initialValue() { + + // 所有加密机一次性链接 + SydApi4j[] apis = new SydApi4j[ linkInfos.length ]; + + // 只有所有都不好,才报错。 + boolean connected = false; + + for ( int i = 0; i < apis.length; i ++ ) { + HsmLinkInfo info = linkInfos[i]; + try { + apis[ i ] = (SydApi4j) new SydApi4j().connect(info.getPcIp(), info.getiPort(), + null, + info.getiConnectTimeOut(), + info.getiDealTimeOut() + ); + connected = true; + } catch ( Exception e ) { + // 忽略单个错误 + } + } + + return null; + } + + // 保活接口 + protected boolean check(SydApi o) { + return null != o; + } + + // 释放 + protected void free(SydApi o) { + } + +} diff --git a/src/main/java/com/sunyard/sge/log/LogFactory.java b/src/main/java/com/sunyard/sge/log/LogFactory.java new file mode 100644 index 0000000..b4de299 --- /dev/null +++ b/src/main/java/com/sunyard/sge/log/LogFactory.java @@ -0,0 +1,115 @@ +package com.sunyard.sge.log; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.FileAppender; +import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy; +import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy; +import org.apache.logging.log4j.core.config.AppenderRef; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 金交所定制日志 + */ +public class LogFactory { + + // 金交所定制日志 + public static final String logName = "sge-hsm-sydapi-log"; + + // 日志级别 + public static final int LogLevelOFF = 0; + public static final int LogLevelError = 1; + public static final int LogLevelInfo = 2; + public static final int LogLevelDebug = 3; + public static int iLogLevel = LogLevelDebug; + + // Levels + public static final Level[] levels = new Level[]{ Level.OFF, Level.ERROR, Level.INFO, Level.DEBUG }; + + // 日志目录 + public static String pcLogPath = "./sydapi-logs/"; + + // 日期格式 + private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + + private LogFactory() { + } + + public static void start() { + // 上下文 + final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + final Configuration config = ctx.getConfiguration(); + + // 创建一个展示的样式 + Layout layout = PatternLayout.createLayout( + "[%level{DEBUG=3, INFO=2, ERROR=1, OFF=0}: %d{ISO8601} <%thread>] %message%n%throwable%n", + null, + config, null, null, true, false, null, null); + + + TriggeringPolicy tp = SizeBasedTriggeringPolicy.createPolicy("10MB"); + +// Appender appender = RollingFileAppender.createAppender(String.format("logs/test/syncshows-job-%s.log", jobID), +// "/logs/test/" + jobID + "/syncshows-job-" + jobID + ".log.gz", +// "true", jobID, null, null, null, tp, null, layout, null, +// null, null, null, config); + + // 日志打印方式——输出为文件    + Appender appender = FileAppender.createAppender( + String.format( pcLogPath + getToday() + ".log"), + "true", "false", + logName, null, "true", "true", null, layout, null, null, null, config); + + appender.start(); + config.addAppender(appender); + AppenderRef ref = AppenderRef.createAppenderRef( logName, levels[ iLogLevel ], null); + AppenderRef[] refs = new AppenderRef[]{ref}; + LoggerConfig loggerConfig = LoggerConfig.createLogger("false", levels[ iLogLevel ], logName, + "true", refs, null, config, null); + loggerConfig.addAppender(appender, levels[ iLogLevel ], null); + config.addLogger( logName, loggerConfig); + ctx.updateLoggers(); + } + + + public static void stop() { + final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + final Configuration config = ctx.getConfiguration(); + config.getAppender( logName ).stop(); + config.getLoggerConfig(logName).removeAppender( logName); + config.removeLogger(logName); + ctx.updateLoggers(); + } + + + public static String getToday(){ + return format.format( new Date()); + } + + /** + * 创建 Logger + * @return Logger + */ + public static Logger createLogger() { + start(); + return LoggerFactory.getLogger( logName ); + } + + /** + * 获取 Logger + * @return Logger + */ + public static Logger getLogger() { + return LoggerFactory.getLogger( logName ); + } +} diff --git a/src/main/java/com/sunyard/sge/pool/ObjectInPool.java b/src/main/java/com/sunyard/sge/pool/ObjectInPool.java new file mode 100644 index 0000000..2834686 --- /dev/null +++ b/src/main/java/com/sunyard/sge/pool/ObjectInPool.java @@ -0,0 +1,24 @@ +package com.sunyard.sge.pool; + +public class ObjectInPool { + + private T object; + private long lasUseAt = System.currentTimeMillis(); + + public ObjectInPool(T object) { + this.object = object; + } + + public T getObjectForCheck() { + return object; + } + + public T getObject() { + this.lasUseAt = System.currentTimeMillis(); + return object; + } + + public long getLasUseAt() { + return lasUseAt; + } +} diff --git a/src/main/java/com/sunyard/sge/pool/PoolConfig.java b/src/main/java/com/sunyard/sge/pool/PoolConfig.java new file mode 100644 index 0000000..d0725bd --- /dev/null +++ b/src/main/java/com/sunyard/sge/pool/PoolConfig.java @@ -0,0 +1,26 @@ +package com.sunyard.sge.pool; + +public class PoolConfig { + + // 最大空闲时间 + private long maxIdle = 5 * 3600 * 1000; // 5 分钟 + + // 最大无用时间 + private long maxUseless = 30 * 3600 * 1000; // 30 分钟 + + public long getMaxIdle() { + return maxIdle; + } + + public void setMaxIdle(long maxIdle) { + this.maxIdle = maxIdle; + } + + public long getMaxUseless() { + return maxUseless; + } + + public void setMaxUseless(long maxUseless) { + this.maxUseless = maxUseless; + } +} diff --git a/src/main/java/com/sunyard/sge/pool/ThreadBasedConnectPool.java b/src/main/java/com/sunyard/sge/pool/ThreadBasedConnectPool.java new file mode 100644 index 0000000..51953b1 --- /dev/null +++ b/src/main/java/com/sunyard/sge/pool/ThreadBasedConnectPool.java @@ -0,0 +1,128 @@ +package com.sunyard.sge.pool; + +import com.sunyard.sge.log.LogFactory; +import org.slf4j.Logger; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class ThreadBasedConnectPool { + + // ThreadLocal + private final Map> map = new HashMap<>(); + + // 守护 + private final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(1); + + // 配置 + private PoolConfig config; + + public ThreadBasedConnectPool(PoolConfig config) { + this.config = config; + threadPool.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + Logger log = LogFactory.getLogger(); + log.debug("连接池检测进程开始执行"); + log.debug("共有链接 {} 个", map.size()); + + // 检测和回收逻辑 + Iterator>> it = map.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry> entry = it.next(); + ObjectInPool oip = entry.getValue(); + + if (System.currentTimeMillis() - oip.getLasUseAt() < config.getMaxIdle()) { + // 空闲时间不足,免检。 + continue; + } + + if (System.currentTimeMillis() - oip.getLasUseAt() > config.getMaxUseless()) { + // 长时间未使用,回收链接 + log.debug("回收一个链接"); + + it.remove(); + + try { + free(oip.getObject()); + } catch (Exception e) { + } + continue; + } + + boolean checkRet = false; + try { + checkRet = check(entry.getValue().getObject()); + } catch (Exception e) { + checkRet = false; + } + + if (checkRet) { + log.debug("一个链接检查未通过"); + // 检查未通过 + it.remove(); + + try { + free(oip.getObject()); + } catch (Exception e) { + } + continue; + } + } + + log.debug("连接池检测进程执行结束"); + } + }, config.getMaxIdle(), config.getMaxIdle(), TimeUnit.MILLISECONDS); + } + + public ThreadBasedConnectPool() { + this(new PoolConfig()); + } + + // 继承 初始化 + protected T initialValue() { + return null; + } + + + // 保活接口 + protected boolean check(T o) { + return null != o; + } + + // 释放 + protected void free(T o) { + } + + + // 获取 + public T get() { + ObjectInPool o = map.get(Thread.currentThread()); + if (null != o) { + return o.getObject(); + } + + return setInitialValue(); + } + + // 设置 + public void set(T o) { + map.put(Thread.currentThread(), new ObjectInPool<>(o)); + } + + // 清除 + public void remove() { + map.remove(Thread.currentThread()); + } + + + private T setInitialValue() { + T value = initialValue(); + map.put(Thread.currentThread(), new ObjectInPool<>(value)); + return value; + } +} diff --git a/src/test/java/sample/Sample.java b/src/test/java/sample/Sample.java index e9885b6..61cd58a 100644 --- a/src/test/java/sample/Sample.java +++ b/src/test/java/sample/Sample.java @@ -1,11 +1,11 @@ package sample; import com.sunyard.proto.Util; +import com.sunyard.sge.database.*; import com.sunyard.sge.database.Consts; -import com.sunyard.sge.database.SydApi; -import com.sunyard.sge.database.SydApi4Database; import org.junit.Assert; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -13,7 +13,7 @@ public class Sample { public static void main(String[] args) { - // System.setProperty("com.sunyard.sydapi4j.debug", "true"); + System.setProperty("com.sunyard.sydapi4j.debug", "true"); SydApi api = new SydApi4Database(); try { @@ -25,12 +25,29 @@ public class Sample ); - // 短数据 - shortData( api ); + // 短数据加密解密 + shortEndeData( api ); + // 批量加密解密 + batchEndeData( api ); - // 批量 - batchData( api ); + // 长数据加密解密 + longDataEnde( api ); + + // 短数据 MAC + shortMAC( api ); + + // 批量 MAC + batchMACData( api ); + + // 长数据 MAC + longMAC( api ); + + // 短数据 SM3 + shortSM3( api ); + + // 长数据 SM3 + longSM3( api ); } finally { @@ -40,7 +57,300 @@ public class Sample } } - public static void shortData(SydApi api){ + public static void longDataEnde(SydApi api){ + + // 密钥索引 + int keyIdx = 0; + // 测试数据 + byte[] data = new byte[16 * 3 + 8]; + // 每包大小 + int pack = 16; + + // 测试数据 > 每包大小需要分包 + + // 密文数据 + ByteBuffer enDataBuff = ByteBuffer.allocate( data.length + 16 ); + + // 分包加密 + { + int n = data.length / pack; + int remainder = data.length % pack; + if ( remainder > 0 ) { + n += 1; + } else { + remainder = pack; + } + + for ( int i = 0 ; i < n ; i ++ ) { + byte[] buff = new byte[ pack ]; + + // 首包 + if ( 0 == i ) { + System.arraycopy( data, i * pack, buff, 0, pack ); + byte[] recv = api.SYD_SM4_LongData( keyIdx , buff, Consts.PkgNumHead, Consts.ECB_ENC); + enDataBuff.put( recv ); + continue; + } + + // 尾包 + if ( i == (n-1) ){ + buff = new byte[ remainder ]; + System.arraycopy( data, i * pack, buff, 0, remainder ); + byte[] recv = api.SYD_SM4_LongData( keyIdx , buff, Consts.PkgNumTail, Consts.ECB_ENC); + enDataBuff.put( recv ); + continue; + } + + // 中间包 + System.arraycopy( data, i * pack, buff, 0, pack ); + byte[] recv = api.SYD_SM4_LongData( keyIdx , buff, Consts.PkgNumMiddle, Consts.ECB_ENC); + enDataBuff.put( recv ); + + } + + } + + byte[] enData = new byte[ enDataBuff.position() ]; + System.arraycopy( enDataBuff.array(), 0, enData, 0, enData.length ); + System.out.println( "EnData HEX=" + Util.bytes2HexString( enData )); + + + // 分包解密 + // 密文数据 + ByteBuffer deDataBuff = ByteBuffer.allocate( data.length + 16 ); + { + int n = enData.length / pack; + int remainder = enData.length % pack; + if ( remainder > 0 ) { + n += 1; + } else { + remainder = pack; + } + + for ( int i = 0 ; i < n ; i ++ ) { + byte[] buff = new byte[ pack ]; + + // 首包 + if ( 0 == i ) { + System.arraycopy( enData, i * pack, buff, 0, pack ); + byte[] recv = api.SYD_SM4_LongData( keyIdx , buff, Consts.PkgNumHead, Consts.ECB_DEC); + deDataBuff.put( recv ); + continue; + } + + // 尾包 + if ( i == (n-1) ){ + buff = new byte[ remainder ]; + System.arraycopy( enData, i * pack, buff, 0, remainder ); + byte[] recv = api.SYD_SM4_LongData( keyIdx , buff, Consts.PkgNumTail, Consts.ECB_DEC); + deDataBuff.put( recv ); + continue; + } + + // 中间包 + System.arraycopy( enData, i * pack, buff, 0, pack ); + byte[] recv = api.SYD_SM4_LongData( keyIdx , buff, Consts.PkgNumMiddle, Consts.ECB_DEC); + deDataBuff.put( recv ); + + } + } + + byte[] deData = new byte[ deDataBuff.position() ]; + System.arraycopy( deDataBuff.array(), 0, deData, 0, deData.length ); + System.out.println( "DeData HEX=" + Util.bytes2HexString( deData )); + + // 断言解密后和原文相同 + Assert.assertArrayEquals( deData, data ); + } + + + public static void longMAC(SydApi api){ + + // 密钥索引 + int keyIdx = 0; + // 测试数据 + byte[] data = new byte[16 * 3 + 8]; + // 每包大小 + int pack = 16; + + // 测试数据 > 每包大小需要分包 + + LongDataReturn recv = null; + // 分包 MAC + { + int n = data.length / pack; + int remainder = data.length % pack; + if ( remainder > 0 ) { + n += 1; + } else { + remainder = pack; + } + + for ( int i = 0 ; i < n ; i ++ ) { + byte[] buff = new byte[ pack ]; + + // 首包 + if ( 0 == i ) { + System.arraycopy( data, i * pack, buff, 0, pack ); + recv = api.SYD_SM4Mac_LongData( keyIdx , buff, Consts.PkgNumHead, null); + continue; + } + + // 尾包 + if ( i == (n-1) ){ + // 尾包大小可能不同 + buff = new byte[ remainder ]; + System.arraycopy( data, i * pack, buff, 0, remainder ); + recv = api.SYD_SM4Mac_LongData( keyIdx , buff, Consts.PkgNumTail, recv.getProcData() ); + continue; + } + + // 中间包 + System.arraycopy( data, i * pack, buff, 0, pack ); + recv = api.SYD_SM4Mac_LongData( keyIdx , buff, Consts.PkgNumMiddle, recv.getProcData() ); + } + } + + String mac = recv.getData(); + System.out.println( "MAC=" + mac); + + + // 分包校验 MAC + LongDataReturn check = null; + ByteBuffer deDataBuff = ByteBuffer.allocate( data.length + 16 ); + { + int n = data.length / pack; + int remainder = data.length % pack; + if ( remainder > 0 ) { + n += 1; + } else { + remainder = pack; + } + + for ( int i = 0 ; i < n ; i ++ ) { + byte[] buff = new byte[ pack ]; + + // 首包 + if ( 0 == i ) { + System.arraycopy( data, i * pack, buff, 0, pack ); + check = api.SYD_SM4Mac_LongData( keyIdx , buff, Consts.PkgNumHead, null, mac); + continue; + } + + // 尾包 + if ( i == (n-1) ){ + // 尾包大小可能不同 + buff = new byte[ remainder ]; + System.arraycopy( data, i * pack, buff, 0, remainder ); + check = api.SYD_SM4Mac_LongData( keyIdx , buff, Consts.PkgNumTail, check.getProcData() , mac); + continue; + } + + // 中间包 + System.arraycopy( data, i * pack, buff, 0, pack ); + check = api.SYD_SM4Mac_LongData( keyIdx , buff, Consts.PkgNumMiddle, check.getProcData() , mac); + + } + } + + // 断言 MAC 校验通过 + Assert.assertTrue( check.getData() ); + } + + public static void shortSM3(SydApi api){ + // 测试数据 + byte[] data = new byte[16]; + String macData = api.SYD_SM3_Hash_ShortData( data ); + System.out.println( "SM3=" + macData ); + Assert.assertEquals( macData , "106E34A2B8C7BB13156CFDD0D91379DCC47543DCF9787C68AE5EB582620AE6E8"); + } + + + public static void longSM3(SydApi api){ + + // 密钥索引 + int keyIdx = 0; + // 测试数据 + byte[] data = new byte[16 * 3 + 8]; + // 每包大小 + int pack = 16; + + // 测试数据 > 每包大小需要分包 + + LongDataReturn recv = null; + // 分包 MAC + { + int n = data.length / pack; + int remainder = data.length % pack; + if ( remainder > 0 ) { + n += 1; + } else { + remainder = pack; + } + + for ( int i = 0 ; i < n ; i ++ ) { + byte[] buff = new byte[ pack ]; + + // 首包 + if ( 0 == i ) { + System.arraycopy( data, i * pack, buff, 0, pack ); + recv = api.SYD_SM3_Hash_LongData( buff, Consts.PkgNumHead, null); + continue; + } + + // 尾包 + if ( i == (n-1) ){ + // 尾包大小可能不同 + buff = new byte[ remainder ]; + System.arraycopy( data, i * pack, buff, 0, remainder ); + recv = api.SYD_SM3_Hash_LongData( buff, Consts.PkgNumTail, recv.getProcData() ); + continue; + } + + // 中间包 + System.arraycopy( data, i * pack, buff, 0, pack ); + recv = api.SYD_SM3_Hash_LongData( buff, Consts.PkgNumMiddle, recv.getProcData() ); + } + } + + String mac = recv.getData(); + System.out.println( "SM3=" + mac); + + // 断言 + Assert.assertEquals( mac, "87B81AF2B2B22CBDF268E211D012D604892D3C948FF298D61D6C942EEE847F86"); + } + + public static void shortMAC(SydApi api){ + // 密钥索引 + int keyIdx = 0; + // 测试数据 + byte[] data = new byte[16]; + String macData = api.SYD_SM4Mac_ShortData( keyIdx , data ); + System.out.println( "MAC=" + macData ); + boolean ret = api.SYD_SM4Mac_ShortData( keyIdx , data, macData ); + Assert.assertTrue( ret ); + } + + public static void batchMACData(SydApi api){ + // 密钥索引 + int[] keyIdx = new int[]{ 0, 1, 2 }; + // 测试数据 + List data = new ArrayList<>(); + data.add( new byte[8] ); + data.add( new byte[16] ); + data.add( new byte[1024] ); + + String[] macs = api.SYD_SM4Mac_BatchData( keyIdx , data); + boolean[] checks = api.SYD_SM4Mac_BatchData( keyIdx , data, macs ); + + for ( int i = 0 ; i < data.size() ; i++ ) { + System.out.println( "MAC["+ i +"]=" + macs[i] ); + Assert.assertTrue( checks[i] ); + } + } + + + public static void shortEndeData(SydApi api){ // 密钥索引 int keyIdx = 0; // 测试数据 @@ -51,7 +361,7 @@ public class Sample Assert.assertArrayEquals( orgData, data ); } - public static void batchData(SydApi api){ + public static void batchEndeData(SydApi api){ // 密钥索引 int[] keyIdx = new int[]{ 0, 1, 2 }; // 测试数据 diff --git a/src/test/java/test/FuncTest.java b/src/test/java/test/FuncTest.java new file mode 100644 index 0000000..7160607 --- /dev/null +++ b/src/test/java/test/FuncTest.java @@ -0,0 +1,32 @@ +package test; + +import com.sunyard.sge.database.SydApi; +import com.sunyard.sge.database.SydApiBuilder; +import org.junit.Before; +import org.junit.Test; + +/** + * 功能确认 + */ +public class FuncTest { + + private SydApi api; + + @Before + public void init(){ + SydApiBuilder builder = new SydApiBuilder( + new String[]{ "192.168.0.200" }, + new int[]{ 8889 }, + 10, + 15 + ); + + api = builder.build(); + } + + + @Test + public void sm3(){ + } + +} diff --git a/src/test/java/test/LogTest.java b/src/test/java/test/LogTest.java new file mode 100644 index 0000000..b0edd79 --- /dev/null +++ b/src/test/java/test/LogTest.java @@ -0,0 +1,15 @@ +package test; + +import com.sunyard.sge.log.LogFactory; +import org.slf4j.Logger; + +public class LogTest { + public static void main(String[] args) { + + Logger log = LogFactory.createLogger(); + log.error("error"); + log.info("info"); + log.debug("debug"); + + } +} diff --git a/src/test/java/test/Pref.java b/src/test/java/test/PrefTest.java similarity index 91% rename from src/test/java/test/Pref.java rename to src/test/java/test/PrefTest.java index 7a0856b..a714e24 100644 --- a/src/test/java/test/Pref.java +++ b/src/test/java/test/PrefTest.java @@ -9,7 +9,7 @@ import org.junit.Assert; import java.util.ArrayList; import java.util.List; -public class Pref +public class PrefTest { public static void main(String[] args) throws InterruptedException { @@ -30,14 +30,18 @@ public class Pref // 预热 final int max = 1; for (int i = 0; i < max; i ++) { - shortData( api ); +// shortData( api ); // batchData( api ); + try { + api.SYD_SM4_ShortData( 0 , new byte[16], Consts.ECB_ENC ); +// api.SYD_SM4_ShortData( 0 , new byte[16], Consts.ECB_DEC ); + } catch ( Exception e ){ + + } + } - - - Thread t = new Thread(new Runnable() { @Override public void run() {