From fbdc8d8b308ddf7c3dae50ac6bfc292b4c0fad8c Mon Sep 17 00:00:00 2001 From: cheney Date: Fri, 22 Jul 2022 17:01:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/~$交易所数据库加密 java 接口新增.docx | Bin 0 -> 162 bytes doc/黄金交易所数据库加密 java 接口新增.docx | Bin 26237 -> 26712 bytes .../黄金交易所数据库加密 java 接口新增.docx | Bin 26237 -> 0 bytes pom.xml | 94 +++-- .../java/com/sunyard/sge/database/Consts.java | 13 + .../sunyard/sge/database/LongDataReturn.java | 18 +- .../java/com/sunyard/sge/database/SydApi.java | 18 +- .../sunyard/sge/database/SydApi4Database.java | 374 ++++++++++++++---- .../sunyard/sge/database/SydApiBuilder.java | 65 +++ .../sunyard/sge/database/SydApiConfig.java | 17 + .../sunyard/sge/database/SydConfigApi.java | 24 -- .../sge/database/pool/HsmLinkInfo.java | 69 ++++ .../sunyard/sge/database/pool/SydApiPool.java | 51 +++ .../java/com/sunyard/sge/log/LogFactory.java | 115 ++++++ .../com/sunyard/sge/pool/ObjectInPool.java | 24 ++ .../java/com/sunyard/sge/pool/PoolConfig.java | 26 ++ .../sge/pool/ThreadBasedConnectPool.java | 128 ++++++ src/test/java/sample/Sample.java | 328 ++++++++++++++- src/test/java/test/FuncTest.java | 32 ++ src/test/java/test/LogTest.java | 15 + .../java/test/{Pref.java => PrefTest.java} | 14 +- 21 files changed, 1272 insertions(+), 153 deletions(-) create mode 100644 doc/~$交易所数据库加密 java 接口新增.docx delete mode 100644 pack/doc/黄金交易所数据库加密 java 接口新增.docx create mode 100644 src/main/java/com/sunyard/sge/database/SydApiBuilder.java create mode 100644 src/main/java/com/sunyard/sge/database/SydApiConfig.java delete mode 100644 src/main/java/com/sunyard/sge/database/SydConfigApi.java create mode 100644 src/main/java/com/sunyard/sge/database/pool/HsmLinkInfo.java create mode 100644 src/main/java/com/sunyard/sge/database/pool/SydApiPool.java create mode 100644 src/main/java/com/sunyard/sge/log/LogFactory.java create mode 100644 src/main/java/com/sunyard/sge/pool/ObjectInPool.java create mode 100644 src/main/java/com/sunyard/sge/pool/PoolConfig.java create mode 100644 src/main/java/com/sunyard/sge/pool/ThreadBasedConnectPool.java create mode 100644 src/test/java/test/FuncTest.java create mode 100644 src/test/java/test/LogTest.java rename src/test/java/test/{Pref.java => PrefTest.java} (91%) diff --git a/doc/~$交易所数据库加密 java 接口新增.docx b/doc/~$交易所数据库加密 java 接口新增.docx new file mode 100644 index 0000000000000000000000000000000000000000..7c44ef39ef81cde95c3e311d3bf8ea6eeba24710 GIT binary patch literal 162 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 delta 16088 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 diff --git a/pack/doc/黄金交易所数据库加密 java 接口新增.docx b/pack/doc/黄金交易所数据库加密 java 接口新增.docx deleted file mode 100644 index d7c563d6a8ccd55d7c58b6765762778124ca9f1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26237 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 - 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() {