diff --git a/DProto/6A.xml b/DProto/6A.xml index 03d19e4..cc0dec8 100644 --- a/DProto/6A.xml +++ b/DProto/6A.xml @@ -220,7 +220,7 @@ } function dataLen() { - return $packet.data.orgData.length + return $packet.data.orgData.length() } diff --git a/doc/密码机JAVA接口说明文档V1.01 .pdf b/doc/密码机JAVA接口说明文档V1.01 .pdf new file mode 100644 index 0000000..498d1a1 Binary files /dev/null and b/doc/密码机JAVA接口说明文档V1.01 .pdf differ diff --git a/kit.json b/kit.json index b840b6d..0b59874 100644 --- a/kit.json +++ b/kit.json @@ -72,8 +72,8 @@ }, { "func": "cp", - "from": "./说明.txt", - "to": "%out_path%/说明.txt" + "from": "./˵.txt", + "to": "%out_path%/˵.txt" }, { "func": "zip", diff --git a/public.cmd b/public.cmd new file mode 100644 index 0000000..cfb0d92 --- /dev/null +++ b/public.cmd @@ -0,0 +1,7 @@ +:: 自动打包为发布格式 +:: 准备文件夹 +:: rd /s/q ./public +:: md ./public + +:: 获取版本 +node public.script/index.js \ No newline at end of file diff --git a/release.cmd b/release.cmd new file mode 100644 index 0000000..4ab9f3d --- /dev/null +++ b/release.cmd @@ -0,0 +1,3 @@ +7z a ./target/sydapi4j.jar racal.sunyard.main.version +7z a ./target/sydapi4j-sources.jar racal.sunyard.main.version +7z a ./target/sydapi4j-jar-with-dependencies.jar racal.sunyard.main.version \ No newline at end of file diff --git a/src/main/java/com/sunyard/SydApi.java b/src/main/java/com/sunyard/SydApi.java index 7acace7..257a955 100644 --- a/src/main/java/com/sunyard/SydApi.java +++ b/src/main/java/com/sunyard/SydApi.java @@ -113,4 +113,8 @@ public interface SydApi extends RetWrap getStatus(); byte[] directBytes(byte[] data); + + public Object getBindObject(); + + public void setBindObject(Object bindObject); } diff --git a/src/main/java/com/sunyard/inf/SydCertApi.java b/src/main/java/com/sunyard/inf/SydCertApi.java index dc2cacc..613d906 100644 --- a/src/main/java/com/sunyard/inf/SydCertApi.java +++ b/src/main/java/com/sunyard/inf/SydCertApi.java @@ -125,6 +125,15 @@ public interface SydCertApi { RetWrap importCert(byte[] certData, byte[] organizationId, CertUsage... us); RetWrap importCert(byte[] certData, byte[] organizationId); + + /** + * 从加密设备中删除指定 DN 的公钥证书 + * @param dn:传入的证书 + * + * @return + */ + boolean deleteCert(String dn); + /** * 从加密设备中删除指定 DN 的公钥证书 * @param dn:传入的证书 diff --git a/src/main/java/com/sunyard/inf/cryption/SydASYMApi.java b/src/main/java/com/sunyard/inf/cryption/SydASYMApi.java new file mode 100644 index 0000000..6ab1be9 --- /dev/null +++ b/src/main/java/com/sunyard/inf/cryption/SydASYMApi.java @@ -0,0 +1,135 @@ +package com.sunyard.inf.cryption; + +public interface SydASYMApi { + /** + * 非对称加解密接口 + */ + /** + * 用指定的 SM2 公钥对指定的密文数据进行加密。 + * + * @param publicKey 公钥钥串,DER 编码,HEX 格式。 + * @param pOrgData 加密的数据。 + * @return 加密的数据 base64 编码。 + */ + String SM2Encrypt( + byte[] publicKey, + byte[] pOrgData + ); + + /** + * 用指定的 SM2 公钥对指定的密文数据进行加密。 + * + * @param publicKey 公钥钥串,DER 编码,HEX 格式。 + * @param pOrgData 加密的数据。 + * @return 加密的数据 der 编码。 + */ + byte[] SYD_SM2_Encrypt(byte[] publicKey, byte[] pOrgData); + + + /** + * 用指定的 SM2 公钥对指定的密文数据进行加密。 + * 输出的sm2密文结构为C1C2C3格式 + * @param publicKey 公钥钥串,DER 编码,HEX 格式。 + * @param pOrgData 加密的数据。 + * @return 加密的数据 base64 编码。 + */ + String SM2EncryptOrder(byte[] publicKey, byte[] pOrgData); + + + /** + * 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。 + * + * @param userId 使用者的 ID,最大长度为 16 位数字,右对齐。 + * @param pEnData 加密的数据,base64 编码。 + * @return 明文数据。 + */ + byte[] SM2DecryptC(String userId, String pEnData); + + /** + * 使用外部私钥解密 + * @param sk LMK下加密的私钥 + * @param enData 密文数据(base64 编码) + * @return 解密结果 + */ + byte[] SM2Decrypt(byte[] sk, String enData); + + /** + * 使用外部私钥解密 + * @param sk LMK下加密的私钥 + * @param enData 密文数据(DER 编码) + * @return 解密结果 + */ + byte[] SYD_SM2_Decrypt(byte[] sk, byte[] enData); + + /** + * 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。 + * 输入的sm2密文结构为C1C2C3格式 + * @param userId 使用者的 ID,最大长度为 16 位数字,右对齐。 + * @param enData 加密的数据,base64 编码。 + * @param keyType 密钥类型,0:签名证书, 1:加密证书。 + * @return 明文数据。 + */ + byte[] SM2DecryptOrder(String userId, String enData, int keyType); + + /** + * 用指定的 RSA 私钥对指定的密文数据进行加密。 + * + * @param publicKey 私钥串,DER 编码,HEX 格式。 + * @param pOrgData 加密的数据。 + * @return 加密的数据 base64 编码。 + */ + String RSAEncrypt( + String publicKey, + byte[] pOrgData + ); + + /** + * 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。 + * + * @param userId 使用者的 ID,最大长度为 16 位数字,右对齐。 + * @param pEnData 加密的数据,base64 编码。 + * @return 明文数据。 + */ + byte[] RSADecryptC( + String userId, + String pEnData + ) throws Exception; + + + /** + * 使用外部私钥解密 + * @param sk + * @param enData + * @return + */ + public byte[] RSADecrypt(String sk, String enData) throws Exception; + + + /** + * 非对称公钥加密 + * @param alg 算法标识,0 = RSA 1 = SM2 + * @param pk 公钥的 DER 编码 + * @param data 数据 + * @return 公钥加密的密文的 DER 编码(对于 RSA 算法,数据类型为 BIT). + */ + public byte[] encryptByPk(int alg, String pk, byte[] data); + + /** + * 非对称私钥解密 + * @param alg 算法标识:0 = RSA 1 = SM2 + * @param sk 私钥值,LMK下加密的私钥 + * @param data 密文数据(DER 编码) + * @return 公钥加密的密文的 DER 编码(对于 RSA 算法,数据类型为 BIT) + */ + public byte[] decryptBySk(int alg, String sk, byte[] data); + + + /** + * 非对称私钥解密 + * @param alg 算法标识:0 = RSA 1 = SM2 + * @param userId 16位机构号 + * @param data 密文数据(DER 编码) + * @return 公钥加密的密文的 DER 编码(对于 RSA 算法,数据类型为 BIT). + */ + public byte[] decryptBySkC(int alg, String userId, byte[] data); + } diff --git a/src/main/java/com/sunyard/inf/cryption/SydHashApi.java b/src/main/java/com/sunyard/inf/cryption/SydHashApi.java new file mode 100644 index 0000000..5418403 --- /dev/null +++ b/src/main/java/com/sunyard/inf/cryption/SydHashApi.java @@ -0,0 +1,71 @@ +package com.sunyard.inf.cryption; + +/** + * Hash 算法接口 + */ +public interface SydHashApi { + + /** + * 计算SM3散列值 + * @param sn 证书序号 + * @param userId 用户ID + * @param msg 原始数据,二进制的消息块 + * @return + */ +// byte[] SM3HashSNaId(String sn, String userId, byte[] msg); + + /** + * 输入对指定的原始数据和公钥,通过 SM3 算法计算数据的散列值。 + * @param publicKey 公钥的 DER 编码(可以为空) + * @param msg 原始数据,二进制的消息块 + * @param block 消息块标志 + * @param mac 上一轮 mac 值,当 mac 不是 null,长度不为 0,则直接从第二包开始。 + * @return HASH 值,32 个 Bytes. + */ + byte[] SM3Hash(String publicKey, byte[] msg, int block, byte[] mac); + + /** + * 计算SM3散列值 + * @param publicKey 公钥的 DER 编码 (03420004 开头) + * @param userId 用户ID + * @param msg 原始数据,二进制的消息块 + * @return + */ + byte[] SM3Hash(String publicKey, String userId, byte[] msg); + + /** + * 输入对指定的原始数据和公钥,通过 SM3 算法计算数据的散列值。 + * + * @param publicKey 公钥(可以为空) + * @param msg 原始数据 + * @return HASH 值,32 个 Bytes. + */ + byte[] SM3Hash(String publicKey, byte[] msg); + + + /** + * 输入对指定的原始数据 (无公钥),通过 SM3 算法计算数据的散列值。 + * + * @param msg 原始数据 + * @return HASH 值,32 个 Bytes. + */ + byte[] SM3Hash(byte[] msg); + + + public byte[] MACCalc(int alg, int keyType, int fullmode, int maclen, String key, byte[] infoData); + + /** + * mac 计算 + * @param alg 0=DES 1=3DES 2=SM4 3=AES 4=IDEA 5=SM1 6=3DES-X9.19 + * @param keyType 0-TAK 1-ZAK + * @param fullMode 0-弱填充 1 强填充 + * @param AK 密钥 + * @param infoData <=1024 + * @param macLen 1=4Byte 2=8Byte 3=16Byte(仅在SM4/AES 下有效) + * @return mac 值 hex 格式 + */ + public String MACCalc(int alg, int keyType, String AK, int fullMode, byte[] infoData, int macLen); + public void MACCheck(int alg, int keyType, String AK, int fullMode, byte[] infoData, String mac); + + public String calcPBOCMAC(int mode, int keyType, String key, byte[] data, int block, byte[] iv); +} diff --git a/src/main/java/com/sunyard/inf/cryption/SydSYMApi.java b/src/main/java/com/sunyard/inf/cryption/SydSYMApi.java new file mode 100644 index 0000000..0821488 --- /dev/null +++ b/src/main/java/com/sunyard/inf/cryption/SydSYMApi.java @@ -0,0 +1,282 @@ +package com.sunyard.inf.cryption; + +import com.sunyard.RetWrap; + +import java.io.UnsupportedEncodingException; +/** + * 对称加解密接口 + */ +public interface SydSYMApi { + + /** + * E0 指令复合接口 + * @param isEn 指定加解密,true为加密,false为解密 + * @param nAlg 密钥模式,当isEn为true时,默认为SM4加密,0为DES加密,1为AES256 加密。当isEn为false时,默认为SM4解密,0为DES解密,1为AES256解密 + * @param seesionKey 密钥 + * @param roundmod 轮模式,密钥加密模式:1=ECB,2=CBC,3=CFB,4=OFB + * @param fullMode 填充模式:0为饥饿模式,1为贪婪模式 + * @param pInData 消息数据 + * @param iv IV + * @param block 消息块号 + * @return + * iv: IV 数据域 + * msg_all: 消息数据 + */ + RetWrap SYMEnDeData(Boolean isEn, int nAlg, String seesionKey, int roundmod, int fullMode, byte[] pInData, byte[] iv, int block); + + + + /** + * 用输入的会话密钥,对指定报文数据进行加密处理。填充模式为1 + * + * @param nAlg 算法标识., 0x00:3DES,0x01:SM4。 + * @param seesionKey 本地LMK 加密的会话密钥,HEX 格式 + * @param pINdata 要加密的报文明文。必须是 8 或16 的倍数。 + * @return 输出的报文密文, 长度为报文明文 + 16 + */ + byte[] SYMEncryptData(int nAlg, String seesionKey, byte[] pINdata); + + /** + * 对指定报文数据进行SM4加密 + * @param type 密钥类型。0: ZEK,1: TEK + * @param userId 生成密钥时的机构号。 + * @param index 密钥索引 + * @param data 待加密的数据 + * @return + */ + byte[] SYMSM4EncDataByIndex(int type, String userId, String index, byte[] data); + + /** + * 用输入的会话密钥,对指定报文数据进行加密处理。 + * + * @param nAlg 算法标识.,0x00:3DES,0x01:SM4。 + * @param seesionKey 本地LMK 加密的会话密钥,HEX 格式 + * @param fullmode 填充模式:0为饥饿模式,1为贪婪模式 + * @param pINdata 要加密的报文明文。必须是 8 或16 的倍数。 + * @return 输出的报文密文, 长度为报文明文 + 16 + */ + byte[] SYMEncryptData(int nAlg, String seesionKey, int fullmode, byte[] pINdata); + + + // List SYMEncryptDecryptBatchData(int nAlg, String[] seesionKey, int fullmode, List pINdata); + + /** + * 用输入的会话密钥,对指定报文数据进行加密处理。 + * + * @param nAlg 算法标识.,0x00:3DES,0x01:SM4。 + * @param seesionKey 本地LMK 加密的会话密钥,HEX 格式 + * @param pInData 要加密的报文明文。必须是 8 或16 的倍数。 + * @return 输出的报文密文, 长度为报文明文 + 16 + */ + byte[] SYMEncryptData_nofill(int nAlg, String seesionKey, byte[] pInData); + + + /** + * 用输入的会话密钥,对指定报文数据进行解密处理。填充模式为1 + * + * @param nAlg  算法标识.0x00:3DES,0x01:SM4。 + * @param seesionKey 本地LMK 加密的会话密钥,HEX 格式 + * @param pINdata 要解密的报文密文。长度必须是8 或16 的倍数。 + * @return 输出的报文明文。 + */ + byte[] SYMDecryptData(int nAlg, String seesionKey, byte[] pINdata); + + /** + * 用输入的会话密钥,对指定报文数据进行解密处理。 + * + * @param nAlg  算法标识.,0x00:3DES,0x01:SM4。 + * @param seesionKey 本地LMK 加密的会话密钥,HEX 格式 + * @param fullmode 填充模式:0为饥饿模式,1为贪婪模式 + * @param pINdata 要解密的报文密文。长度必须是8 或16 的倍数。 + * @return 输出的报文明文。 + */ + byte[] SYMDecryptData(int nAlg, String seesionKey, int fullmode, byte[] pINdata); + + /** + * 用输入的会话密钥,对指定报文数据进行解密处理。 + * + * @param nAlg  算法标识.,0x00:3DES,0x01:SM4。 + * @param seesionKey 本地LMK 加密的会话密钥,HEX 格式 + * @param pInData 要解密的报文密文。长度必须是8 或16 的倍数。 + * @return 输出的报文明文。 + */ + byte[] SYMDecryptData_nofill(int nAlg, String seesionKey, byte[] pInData); + + /** + * 加解密数据(E1) + * @param nAlg 密钥模式,默认为SM4解密,0:DES加密,1:AES256 解密 + * @param seesionKey 密钥 + * @param inputPath 输入消息数据的文件路径 + * @param outputPath 输出消息数据的文件路径 + * @return + */ + boolean SYMDecryptDataWithFile(int nAlg, String seesionKey, String inputPath, String outputPath) throws Exception; + + /** + * 使用SM4算法进行加密,其中加密模式为CBC, + * Ⅳ使用缺省值0X 00000000000000000000000000000000, + * 补位模式为 PKCS5 PADDING 。 + * @param keyType 密钥类型 0: ZEK,1: TEK + * @param key 密钥 + * @param inType 输入消息类型 0:二进制 1:扩展十六进制 + * @param outType 输出消息类型 0:二进制 1:扩展十六进制 + * @param inFilePath 需要加密的数据文件所在的路径 + * @param outFilePath 加密后的密文数据将要保存的文件路径 + * @return 加密是否成功。false为失败,true为成功 + */ + boolean SM4EncryptFileDataCBC(int keyType, String key, int inType, int outType, String inFilePath, String outFilePath); + + /** + * 使用SM4算法进行加密,其中加密模式为CBC, + * Ⅳ使用缺省值0X 00000000000000000000000000000000, + * 补位模式为 PKCS5 PADDING 。 + * @param keyType 密钥类型 0: ZEK,1: TEK + * @param key 密钥 + * @param inType 输入消息类型 0:二进制 1:扩展十六进制 + * @param outType 输出消息类型 0:二进制 1:扩展十六进制 + * @param msg 消息数据 + * @return 输出的报文密文 + */ + byte[] SM4EncryptDataCBC(int keyType, String key, int inType, int outType, byte[] msg); + + /** + * 使用SM4算法进行解密,其中加密模式为CBC, + * Ⅳ使用缺省值0X 00000000000000000000000000000000, + * 补位模式为 PKCS5 PADDING 。 + * @param keyType 密钥类型 0: ZEK,1: TEK + * @param key 密钥 + * @param inType 输入消息类型 0:二进制 1:扩展十六进制 + * @param outType 输出消息类型 0:二进制 1:扩展十六进制 + * @param inFilePath 加密后的密文数据将要保存的文件路径 + * @param outFilePath 解密后的数据文件所在的路径 + * @return 解密是否成功。false为失败,true为成功 + */ + boolean SM4DecryptFileDataCBC(int keyType, String key, int inType, int outType, String inFilePath, String outFilePath) throws UnsupportedEncodingException; + + /** + * 使用SM4算法进行解密,其中加密模式为CBC, + * Ⅳ使用缺省值0X 00000000000000000000000000000000, + * 补位模式为 PKCS5 PADDING 。 + * @param keyType 密钥类型 0: ZEK,1: TEK + * @param key 密钥 + * @param inType 输入消息类型 0:二进制 1:扩展十六进制 + * @param outType 输出消息类型 0:二进制 1:扩展十六进制 + * @param msg 加密后的消息数据 + * @return 输出的报文明文 + */ + byte[] SM4DecryptDataCBC(int keyType, String key, int inType, int outType, byte[] msg); + + /** + * 用输入的会话密钥,对指定报文数据进行加密处理。 + * + * @param nAlg  算法标识.,0x00:3DES,0x01:SM4。 + * @param seesionKey  本地LMK 加密的会话密钥,HEX 格式 + * @param pINdata  要加密的报文明文。必须是 8 或16 的倍数。 + * @return 输出的报文密文, 长度为报文明文 + 16 + */ + byte[] SYMEncryptDataCBC(int nAlg, String seesionKey, byte[] pINdata); + + /** + * 用输入的会话密钥,对指定报文数据进行加密处理。 + * + * @param nAlg  算法标识.,0x00:3DES,0x01:SM4。 + * @param seesionKey  本地LMK 加密的会话密钥,HEX 格式 + * @param fullmode  填充模式:0为饥饿模式,1为贪婪模式 + * @param pInData  要加密的报文明文。必须是 8 或16 的倍数。 + * @return 输出的报文密文, 长度为报文明文 + 16 + */ + byte[] SYMEncryptDataCBC(int nAlg, String seesionKey, int fullmode, byte[] pInData); + + /** + * 用输入的会话密钥,对指定报文数据进行解密处理。 + * + * @param nAlg  算法标识.,0x00:3DES,0x01:SM4。 + * @param seesionKey 本地LMK 加密的会话密钥,HEX 格式 + * @param pINdata 要解密的报文密文。长度必须是8 或16 的倍数。 + * @return 输出的报文明文。 + */ + byte[] SYMDecryptDataCBC(int nAlg, String seesionKey, byte[] pINdata); + /** + * 用输入的会话密钥,对指定报文数据进行解密处理。 + * + * @param nAlg  算法标识.,0x00:3DES,0x01:SM4。 + * @param seesionKey 本地LMK 加密的会话密钥,HEX 格式 + * @param fullmode 填充模式:0为饥饿模式,1为贪婪模式 + * @param pInData 要解密的报文密文。长度必须是8 或16 的倍数。 + * @return 输出的报文明文。 + */ + byte[] SYMDecryptDataCBC(int nAlg, String seesionKey, int fullmode, byte[] pInData); + + /** + * 用输入的会话密钥,对指定报文数据进行解密处理。 + * + * @param srcKey  源秘钥.十六进制字符串。 + * @param desKey  目的秘钥.十六进制字符串。 + * @param sca  源算法SCA.Int类型。 + * @param sPin  源PIN块.十六进制字符串。 + * @param primaryAccount  主账号.十六进制字符串。 + * @return 目的Pin块。 + */ + byte[] transPinFrOneKeyToAno(String srcKey, String desKey, int sca, String sPin, String primaryAccount); + + + /** + * 用一把DEK密钥加密数据, 报文总长度不大于8192 + * + * @param alg 加密算法 + * @param DEK DEK密钥 + * @param infoData 数据 + * @param vector 初始向量数据 可选项,当加密模式为CBC,CFB或OFB时才显示此项 + * @param disperseAlg 分散算法 + * @return 密文数据 + */ + byte[] SYD_Encrypt_Data(int alg, String DEK, byte[] infoData, byte[] vector, int disperseAlg, byte[] factor); + + + /** + * 用DEK密钥解密数据, 报文总长度不大于8192 + * + * @param alg 解密算法 + * @param DEK DEK密钥 + * @param infoData 数据密文 + * @param vector 初始向量数据 可选项,当加密模式为CBC,CFB或OFB时才显示此项 + * @param disperseAlg 分散算法 + * @return 解密后的明文数据 + */ + byte[] SYD_Decrypt_Data(int alg, String DEK, byte[] infoData, byte[] vector, int disperseAlg, byte[] factor); + + + /** + * 对于给定的数据生成一个MAC + * + * @param key LMK对(16-17)下加密的TAK + * @param infoData 生成MAC的数据 + * @param IV + * @param disperseNum 指定对根密钥分散的次数(1-3次) + * @param disperseAlg 分散算法 + * @return 所计算出的MAC + */ + byte[] SYD_MAC_Data(String key, String infoData, byte[] factor, String IV, int disperseNum, int disperseAlg); + + /** + * 对称加密数据 + * @param key 索引地址,指示用户密钥存储区的27位地址 + * @param intPutData 消息数据 + * @return + * iv: IV 数据域 + * msg_all: 消息数据 + */ + public String SYMEncrytByKeyIndex( String key, String intPutData); + + /** + * 对称解密数据 + * @param key 索引地址,指示用户密钥存储区的27位地址 + * @param intPutData 消息数据 + * @return 消息数据 + */ + public String SYMDecrytByKeyIndex(String key,String intPutData); + + //通过索引读取对称秘钥 + RetWrap readKey(String index); + +} diff --git a/src/main/java/com/sunyard/inf/sva/SydAttachedSVApi.java b/src/main/java/com/sunyard/inf/sva/SydAttachedSVApi.java new file mode 100644 index 0000000..b2ded56 --- /dev/null +++ b/src/main/java/com/sunyard/inf/sva/SydAttachedSVApi.java @@ -0,0 +1,181 @@ +package com.sunyard.inf.sva; + +import com.sunyard.RetWrap; +import com.sunyard.cert.X509; +/** + * 带原文的签名验签 + */ +public interface SydAttachedSVApi { + + /** + * sm2私钥签名 + * 用户id默认为1234567812345678 + * 签名结果R/S序列串先进行der编码,再进行base64编码 + * + * @param flag 私钥标志位,当为1时第二个参数传入存储私钥的索引,当为0时第二个参数传入私钥 + * @param privateKey 当私钥标志位为1时传入存储私钥的索引,当为0时传入私钥 + * @param publicKey 公钥 + * @param orgData 要签名的信息 + * @return 签名结果 + */ + String SM2SignC(int flag, String privateKey, byte[] publicKey, byte[] orgData); + String SM2SignC(int flag, String pUserID, String privateKey, byte[] publicKey, byte[] orgData); + /** + * SM2 私钥签名 + * @param pUserID 使用者的 ID,最大长度为 16 位数字,右对齐。 + * @param certNo 证书号 + * @param nOrgDataType 原始数据类型 0 : hash 1 : 原数据 + * @param publicKey 公钥的 DER 编码 + * @param orgData 原始数据 + * @return 签名的 base64 编码 + */ + String SM2SignC( + String pUserID, + String certNo, + int nOrgDataType, + byte[] publicKey, + byte[] orgData + ); + + /** + * RSA 私钥签名 + * @param HashMark 哈希标识 指示用于哈希证书数据的哈希算法的标识。0: SHA1 1: SHA256 2: MD5。 + * @param privateKeyTag 私钥标记 指示私钥位置的标记。数字为存储私钥的索引,除了全9表示使用由命令中提供的密钥。 + * 27位的索引号:16位机构号+3位密钥类型+8位密钥索引号 + * @param nOrgDataType 原始数据类型 0 : hash 1 : 原数据 + * @param orgData 原始数据 + * @return 签名的 base64 编码 + */ + byte[] RSASignC( + String privateKeyTag, + int HashMark, + int nOrgDataType, + byte[] orgData); + + + byte[] RSASign( + String privateKey, + int HashMark, + int nOrgDataType, + byte[] orgData); + + /** + * 采用 RSA 算法,用指定的公钥对指定的原始数据进行数字签名验证。 + * @param HashMark 哈希标识 + * @param nOrgDataType 签名方式 + * @param publicKey 公钥 + * @param orgData 原始数据 + * @param sign base64 格式的签名 + * @return true 验签通过 false 验签失败 + */ + boolean RSAVerify( + int HashMark, + int nOrgDataType, + byte[] publicKey, + byte[] orgData, + byte[] sign); + + /** + * sm2验签 + * 用户id默认为1234567812345678 + * + * @param publicKey 公钥的 DER 编码 + * @param orgData 要签名的信息 + * @param base64Sign 计算的签名,签名结果R/S序列串先进行der编码,再进行base64编码后的结果 + * @return true 验签成功,false 验签失败 + */ + boolean SM2Verify(byte[] publicKey, byte[] orgData, String base64Sign); + + /** + * 采用 SM2 算法,用指定的公钥对指定的原始数据进行数字签名验证。 + * @param certNo id 用于计算SM3-HASH + * @param nOrgDataType 原始数据类型 0 : hash 1 : 原数据,用1.2.3章节限定符亦可 + * @param publicKey 公钥 + * @param orgData 原始数据 + * @param sign base64 格式的签名 + * @return true 验签通过 false 验签失败 + */ + boolean SM2Verify( + String certNo, + int nOrgDataType, + byte[] publicKey, + byte[] orgData, + String sign + ); + + + /** + * SM2 私钥签名 + * @param certNo 证书号 + * @param orgData 原始数据 + * @return 签名的 base64 编码 + */ + String SM2SignCustomized( + String certNo, + byte[] orgData + ); + + /** + * 采用 SM2 算法,用指定的公钥对指定的原始数据进行数字签名验证。 + * @param certNo 证书号 + * @param orgData 原始数据 + * @param sign base64 格式的签名 + * @return true 验签通过 false 验签失败 + */ + boolean SM2VerifyCustomized( + String certNo, + byte[] orgData, + String sign + ); + + /** + * 带公钥证书与原始数据的数字签名(遵循 PKCS#7) + * 使用指定的证书 DN,从加密设备获取对应的私钥证书,对指定的原始数据编制带公钥证书的数字签名(遵循 PKCS#7)。 + * + * @param orgData 待签名数据 + * @param sCertDN 证书DN + * @return + * 符合PKCS7标准的签名结果 + */ + String attachedSign(byte[] orgData, String sCertDN); + + /** + * 带公钥证书与原始数据的数字签名验签(遵循 PKCS#7) + * 对指定的原始数据核验其带公钥证书签名。如签名有效(含证书无效)且需返回签名者公钥证书信息时,同时返回签名者公钥证书信息。 + * + * @param sign 已签名数据 + * @return true 验签通过 false 验签失败 + */ + boolean attachedVerify(String sign); + + /** + * 带公钥证书与原始数据的数字签名验签(遵循 PKCS#7) + * 对指定的原始数据核验其带公钥证书签名。如签名有效(含证书无效)且需返回签名者公钥证书信息时,同时返回签名者公钥证书信息。 + * + * @param sign 已签名数据 + * @return 成功返回签名的原数据,失败则报错 + */ + String attachedVerifyRD(String sign); + + /** + * 带公钥证书与原始数据的数字签名验签(遵循 PKCS#7) + * 对指定的原始数据核验其带公钥证书签名。如签名有效(含证书无效)且需返回签名者公钥证书信息时,同时返回签名者公钥证书信息。 + * + * @param sign 已签名数据 + * @return + * 若发送报文返回证书信息标志位为0,则返回已签名数据, + * 若发送报文返回证书信息标志位为1,则返回CERT_INFO结构的证书数据 + */ + X509 attachedVerifyAndGetX509(String sign); + + /** + * 带公钥证书与原始数据的数字签名验签(遵循 PKCS#7) + * 对指定的原始数据核验其带公钥证书签名。如签名有效(含证书无效)且需返回签名者公钥证书信息时,同时返回签名者公钥证书信息。 + * + * @param sign 已签名数据 + * @return + * 若发送报文返回证书信息标志位为0,则返回已签名数据, + * 若发送报文返回证书信息标志位为1,则返回CERT_INFO结构的证书数据 + */ + RetWrap attachedVerifyAndGetAll(String sign); +} \ No newline at end of file diff --git a/src/main/java/com/sunyard/inf/sva/SydDetachedSVApi.java b/src/main/java/com/sunyard/inf/sva/SydDetachedSVApi.java new file mode 100644 index 0000000..b5110dd --- /dev/null +++ b/src/main/java/com/sunyard/inf/sva/SydDetachedSVApi.java @@ -0,0 +1,178 @@ +package com.sunyard.inf.sva; + +import com.sunyard.RetWrap; +import com.sunyard.cert.X509; + +/** + * 不带原文的签名验签 + */ +public interface SydDetachedSVApi { + + /** + * 对指定的原始数据核验其带公钥证书签名(PKCS#7) + * @param orgData 待签名的原始数据 + * @param sign 签名数据 + * @return 验签是否通过 + */ + public boolean SYD_DetachedVerify( + byte[] orgData, + String sign); + + + /** + * 通过指定的私钥对指定的原始数据编制带公钥证书的数字签名(遵循PKCS#7) + * @param orgData 待签名的原始数据 + * @param sCertDN 签名者证书 DN + * @return 签名数据 + */ + public String SYD_DetachedSign( + byte[] orgData, + String sCertDN + ); + + + + /** + * 通过指定的私钥对指定的原始数据编制带公钥证书的数字签名(遵循PKCS#7) + * 待签名的原始数据将在接口内部进行 sm3 ,然后做 Detach 签名 + * @param orgData 待签名的原始数据 + * @param publicKey sm3 hash 所用的公钥 + * @param sCertDN 签名者证书 DN + * @return 签名数据 + */ + public String sm3AndDetachedSign( + byte[] orgData, + String publicKey, + String sCertDN + ); + + + + /** + * 对指定的原始数据核验其带公钥证书签名(PKCS#7) + * 原始数据将在接口内部进行 sm3 ,然后做 Detach 验签 + * @param orgData 待签名的原始数据 + * @param publicKey sm3 hash 所用的公钥 + * @param sign 签名数据 + * @return 验签是否通过 + */ + public boolean sm3AndDetachedVerify( + byte[] orgData, + String publicKey, + String sign); + + /** + * 通过指定的私钥对指定的原始数据编制带公钥证书的数字签名(遵循PKCS#7) + * 待签名的原始数据将在接口内部进行不带公钥的 sm3 ,然后做 Detach 签名 + * @param orgData 待签名的原始数据 + * @param sCertDN 签名者证书 DN + * @return 签名数据 + */ + String sm3WithoutPKDetachedSign(byte[] orgData, String sCertDN); + + /** + * 对指定的原始数据核验其带公钥证书签名(PKCS#7) + * 原始数据将在接口内部进行无公钥的 sm3 ,然后做 Detach 验签 + * + * @param orgData 待签名的原始数据 + * @param sign 签名数据 + * @return 验签是否通过 + */ + boolean sm3WithoutPKDetachedVerify(byte[] orgData, String sign); + + + /** + * + * 通过指定的私钥对指定的原始数据编制带公钥证书的数字签名(遵循PKCS#7) + * 数据模式可选 DATA_HASH 或 DATA_ORIGIN + * + * @param dataType 数据模式,输入的数据为 HASH 后的数据 DATA_HASH = 0 ,输入的数据为原始数据库 DATA_ORIGIN = 1 + * @param orgData 输入的数据 + * @param sCertDN 签名者证书 DN + * @return 签名数据 + */ + public String detachedSign( + int dataType, + byte[] orgData, + String sCertDN + ); + + /** + * 带公钥证书与签名属性的数字签名(遵循 PKCS#7) + * @param dataType 数据类型:0,hash 模式,1为非hash模式 + * @param orgData 当为hash模式时,值为hash值,当为非hash模式时,值为数据 + * @param keyTag 密钥对应的索引号 + * @return 签名的 DER 编码 + */ + public byte[] detachedSign( + int dataType, + byte[] orgData, + int keyTag + ); + + /** + * 带公钥证书的PKCS#7数字签名(序列号) + * @param dataType 数据类型:0,hash 模式,1为非hash模式 + * @param orgData 当为hash模式时,值为hash值,当为非hash模式时,值为要签名的信息 + * @param certificateNo X509证书序号 + * @return 符合PKCS7标准的签名结果 + */ + public String detachedSignbysn( + int dataType, + byte[] orgData, + String certificateNo); + + + /** + * 对指定的原始数据核验其带公钥证书签名(PKCS#7) + * 数据模式可选 DATA_HASH 或 DATA_ORIGIN + * + * @param dataType 输入的数据为 HASH 后的数据 DATA_HASH = 0 ,输入的数据为原始数据库 DATA_ORIGIN = 1 + * @param orgData 待签名的原始数据 + * @param sign 签名数据 + * @return 验签是否通过 + */ + boolean detachedVerify( + int dataType, + byte[] orgData, + String sign); + + /** + * 带公钥证书与签名属性的数字签名验签(遵循 PKCS#7) + * @param dataType 数据类型:0,hash 模式,1为非hash模式 + * @param orgData 当为hash模式时,值为hash值,当为非hash模式时,值为数据 + * @param sign 已签名数据 + * @return 是否正确 + */ + boolean detachedVerify( + int dataType, + byte[] orgData, + byte[] sign); + + /** + * 对指定的原始数据核验其带公钥证书签名(PKCS#7)返回证书信息 + * 数据模式可选 DATA_HASH 或 DATA_ORIGIN + * + * @param dataType 输入的数据为 HASH 后的数据 DATA_HASH = 0 ,输入的数据为原始数据库 DATA_ORIGIN = 1 + * @param orgData 待签名的原始数据 + * @param sign 签名数据 + * @return 证书 + */ + X509 detachedVerifyAndGetX509(int dataType, + byte[] orgData, + String sign); + + /** + * 计算SM3散列值 + * @param packSn 消息块号,0=仅一块,1=第一块,2=中间块,3=最后块 + * @param userId 用户 ID,只对“消息块号”为 0、1 时有效 + * @param publicKey 公钥的 DER 编码 + * @param msg 二进制的消息块 + * @param filterData 过渡消息数据,只对“消息块号”为 2、3 时有效 + * @return + * filterData: 过渡消息数据,只对“消息块号”为 2、1 时有效 + * hash: hash + */ + RetWrap SM3Hash(int packSn, String userId, byte[] publicKey, byte[] msg, byte[] filterData); + +} diff --git a/src/main/java/com/sunyard/inf/sva/SydNakedSVApi.java b/src/main/java/com/sunyard/inf/sva/SydNakedSVApi.java new file mode 100644 index 0000000..94faad0 --- /dev/null +++ b/src/main/java/com/sunyard/inf/sva/SydNakedSVApi.java @@ -0,0 +1,32 @@ +package com.sunyard.inf.sva; + +/** + * 不经过 CA 授信 + * 直接使用公私钥对签名验签 + */ +public interface SydNakedSVApi { + /** + * 使用指定的证书 DN,从加密设备获取对应的私钥证书,对指定的原始数据编制裸签名(遵循 PKCS#1) + * @param orgData 待签名的原始数据 + * @param sCertDN 签名者证书 DN + * @return 签名数据 + */ + public byte[] SYD_NakedSign( + byte[] orgData, + String sCertDN + ); + + + /** + * 使用指定的证书 DN,对指定的原始数据编制裸验签(遵循PKCS#1) + * @param orgData 待签名的原始数据 + * @param sign 签名数据 + * @param sCertDN 签名者证书 DN + * @return 验签是否通过 + */ + public boolean SYD_NakedVerify( + byte[] orgData, + byte[] sign, + String sCertDN + ); +} \ No newline at end of file diff --git a/src/main/java/com/sunyard/pool/HsmLinkInfo.java b/src/main/java/com/sunyard/pool/HsmLinkInfo.java new file mode 100644 index 0000000..4223695 --- /dev/null +++ b/src/main/java/com/sunyard/pool/HsmLinkInfo.java @@ -0,0 +1,63 @@ +package com.sunyard.pool; + + + + +/** + * 到加密机的链接信息 + */ +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) { + if (null == pcIpList && + null == iPortList && + pcIpList.length != iPortList.length) { + throw new IllegalArgumentException("入参错误"); + } + + if ( iAllDealTimeOut < pcIpList.length) { + 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/pool/ObjectInPool.java b/src/main/java/com/sunyard/pool/ObjectInPool.java new file mode 100644 index 0000000..4ab5b42 --- /dev/null +++ b/src/main/java/com/sunyard/pool/ObjectInPool.java @@ -0,0 +1,28 @@ +package com.sunyard.pool; + +public class ObjectInPool { + + private T object; + private long lasUseAt = System.currentTimeMillis(); + + public ObjectInPool(T object) { + this.object = object; + } + + public T getObjectForCheck() { + return this.object; + } + + public void updateLastUseTime(){ + this.lasUseAt = System.currentTimeMillis(); + } + + public T getObject() { + this.lasUseAt = System.currentTimeMillis(); + return this.object; + } + + public long getLasUseAt() { + return this.lasUseAt; + } +} diff --git a/src/main/java/com/sunyard/pool/PoolConfig.java b/src/main/java/com/sunyard/pool/PoolConfig.java new file mode 100644 index 0000000..4870fda --- /dev/null +++ b/src/main/java/com/sunyard/pool/PoolConfig.java @@ -0,0 +1,26 @@ +package com.sunyard.pool; + +public class PoolConfig { + + // 最大空闲时间 + private long maxIdle = 5 * 60 *1000; // 5 分钟 + + // 最大无用时间 + private long maxUseless = 30 * 60 * 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/pool/SydApiPool.java b/src/main/java/com/sunyard/pool/SydApiPool.java new file mode 100644 index 0000000..f4231be --- /dev/null +++ b/src/main/java/com/sunyard/pool/SydApiPool.java @@ -0,0 +1,84 @@ +package com.sunyard.pool; + +import com.sunyard.SydApi; +import com.sunyard.SydApiException; +import com.sunyard.proxy.ProxyInvocationHandler; +import racal.sunyard.main.SydApi4j; + +public class SydApiPool extends ThreadBasedConnectPool { + private HsmLinkInfo[] linkInfos; + + public SydApiPool(HsmLinkInfo[] linkInfos) { + this.linkInfos = linkInfos; + } + + protected SydApi initialValue() { + SydApi4j[] apis = new SydApi4j[this.linkInfos.length]; + boolean connected = false; + + for(int i = 0; i < apis.length; ++i) { + HsmLinkInfo info = this.linkInfos[i]; + + try { + apis[i] = (SydApi4j)(new SydApi4j()).connect(info.getPcIp(), info.getiPort(), (String)null, info.getiConnectTimeOut(), info.getiDealTimeOut()); + connected = true; + } catch (Exception var6) { + } + } + + if (!connected) { + throw new SydApiException("连接错误", -1); + } else { + ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(apis, this.linkInfos, false); + return proxyInvocationHandler.getProxy(); + } + } + + public boolean check(SydApi s) { + boolean ret = super.check(s); + if (!ret) { + return false; + } else { + ProxyInvocationHandler o = (ProxyInvocationHandler)s.getBindObject(); + + try { + SydApi4j[] hsms = o.getApis(); + boolean canUse = false; + int length = hsms.length; + + for(int i = 0; i < length; ++i) { + if (null != hsms[i]) { + try { + synchronized(hsms[i]) { + hsms[i].GenerateRandom(1); + canUse = true; + } + } catch (Exception var12) { + hsms[i] = null; + } + } else { + HsmLinkInfo[] infos = o.getApisInfos(); + HsmLinkInfo info = infos[i]; + + try { + hsms[i] = (SydApi4j)(new SydApi4j()).connect(info.getPcIp(), info.getiPort(), (String)null, info.getiConnectTimeOut(), info.getiDealTimeOut()); + canUse = true; + } catch (Exception e) { + } + } + } + + return canUse; + } catch (Exception e) { + return false; + } + } + } + + protected void free(SydApi o) { + if (null != o) { + o.disconnect(); + } + + } +} diff --git a/src/main/java/com/sunyard/pool/ThreadBasedConnectPool.java b/src/main/java/com/sunyard/pool/ThreadBasedConnectPool.java new file mode 100644 index 0000000..49ced4b --- /dev/null +++ b/src/main/java/com/sunyard/pool/ThreadBasedConnectPool.java @@ -0,0 +1,125 @@ +package com.sunyard.pool; + +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() { + // 检测和回收逻辑 + 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()) { + // 长时间未使用,回收链接 + + it.remove(); + + try { + free(oip.getObject()); + } catch (Exception e) { + } + continue; + } + + boolean checkPass = false; + try { + checkPass = check(entry.getValue().getObjectForCheck()); + } catch (Exception e) { + checkPass = false; + } + finally { + } + + if ( ! checkPass) { + // 检查未通过 + it.remove(); + + try { + free(oip.getObject()); + } catch (Exception e) { + } + continue; + } + } + + } + }, 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()); + } + + protected void afterInit(ObjectInPool oip, T value ){ + + } + + private T setInitialValue() { + T value = initialValue(); + ObjectInPool opi = new ObjectInPool<>(value); + map.put(Thread.currentThread(), opi); + afterInit( opi , value); + return value; + } +} diff --git a/src/main/java/com/sunyard/proxy/ProxyInvocationHandler.java b/src/main/java/com/sunyard/proxy/ProxyInvocationHandler.java new file mode 100644 index 0000000..1810f04 --- /dev/null +++ b/src/main/java/com/sunyard/proxy/ProxyInvocationHandler.java @@ -0,0 +1,156 @@ +package com.sunyard.proxy; + +import com.sunyard.SydApi; +import com.sunyard.SydApiException; +import com.sunyard.pool.HsmLinkInfo; +import racal.sunyard.main.SydApi4j; +import racal.sunyard.main.SydApiMuti; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class ProxyInvocationHandler implements InvocationHandler { + + private static Map innerFuncs = new HashMap(); + + static { + innerFuncs.put("connect", new SydApiException("集群连接模式,不需要该连接", 0)); + } + + private SydApi4j[] apis; + private HsmLinkInfo[] apisInfos; + private boolean isShortLinkMode = true; + + + public ProxyInvocationHandler(SydApi4j[] apis) { + this.apis = apis; + } + + public ProxyInvocationHandler(SydApi4j[] apis, HsmLinkInfo[] info, boolean isShortLinkMode) { + this.apis = apis; + this.apisInfos = info; + this.isShortLinkMode = isShortLinkMode; + } + + public SydApi4j[] getApis() { + return apis; + } + + + public HsmLinkInfo[] getApisInfos() { + return apisInfos; + } + + public SydApi getProxy() { + SydApi api = (SydApi) Proxy.newProxyInstance( + SydApi4j.class.getClassLoader(), + new Class[]{SydApi.class}, + this + ); + api.setBindObject( this ); + return api; + } + + public void disconnect() { + + if (null != apis && isShortLinkMode) { + for (SydApi4j api4j : this.apis) { + try { + if (null != api4j) { + api4j.disconnect(); + } + } catch (Exception e) { + // pass + } + } + } + } + + //处理代理实例并返回结果 + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + SydApiException le = null; + + if ("disconnect".equals(method.getName())) { + this.disconnect(); + } + + // 屏蔽部分非业务接口 + if ("connect".equals(method.getName())) { + throw new RuntimeException("不允许使用此接口"); + } + if (innerFuncs.containsKey(method.getName())) { + innerFuncs.get(method.getName()); + } + + + if ("deleteCert".equals(method.getName()) || "SYD_Get_X509_CertInfo_HA".equals(method.getName())) { + for (SydApi4j api : apis) { + if (null == api) { + if ("deleteCert".equals(method.getName())) { + throw new SydApiException("删除失败",56307); + } else { + throw new SydApiException("导入失败",56300); + } + } + try { + + Object ret = method.invoke(api, args); + if ( ret instanceof Boolean ) { + if ( ! ( Boolean ) ret ) { + throw new RuntimeException("结果错误"); + } + } + + } catch (SydApiException e) { + if ("deleteCert".equals(method.getName())) { + throw new SydApiException("删除失败",56307); + } else { + throw new SydApiException("导入失败",56300); + } + } + } + } + + for (SydApi4j api : apis) { + if (null == api) { + continue; + } + if ( isShortLinkMode ) { + try { + + return method.invoke(api, args); + + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } + } else { + synchronized (api) { + try { + return method.invoke(api, args); + + } catch (SydApiException e) { + le = e; + if (e.getRetCode() < 0) { + continue; + } + throw e; + } + } + } + } + throw le; + } +} + + + diff --git a/src/main/java/racal/sunyard/main/SydApiClusterBuilder.java b/src/main/java/racal/sunyard/main/SydApiClusterBuilder.java new file mode 100644 index 0000000..5846664 --- /dev/null +++ b/src/main/java/racal/sunyard/main/SydApiClusterBuilder.java @@ -0,0 +1,42 @@ +package racal.sunyard.main; + +import com.sunyard.SydApi; +import com.sunyard.SydApiException; +import com.sunyard.proxy.ProxyInvocationHandler; + +public class SydApiClusterBuilder { + + public static SydApi SYD_Short_Connect_Ex(String[] pcIpList, int[] iPortList, int iConnectTimeOut, int allDealTimeOut) { + if (pcIpList.length != iPortList.length) { + throw new IllegalArgumentException("ip与端口数量不一致"); + } + SydApi4j[] apis = new SydApi4j[pcIpList.length]; + int iDealTimeOut = allDealTimeOut / pcIpList.length; + boolean connected = false; + SydApi4j sydApi4j = new SydApi4j(); + for (int i = 0; i < pcIpList.length; i++) { + try { + apis[i] = (SydApi4j) sydApi4j.connect(pcIpList[i], iPortList[i], null, iConnectTimeOut, iDealTimeOut); + connected = true; + } catch (Exception e) { + // 忽略错误 +// log.error("网络连接错误 {} {} - 忽略", pcIpList[i], iPortList[i]); + } + + } + if (!connected) { + // TODO + throw new SydApiException("连接错误", -1); + } + + +// hsms = apis; +// isShortLinkMode = true; + + + + ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(apis); + return proxyInvocationHandler.getProxy(); + } + +} diff --git a/src/main/java/racal/sunyard/main/SydApiMuti.java b/src/main/java/racal/sunyard/main/SydApiMuti.java new file mode 100644 index 0000000..dc410dc --- /dev/null +++ b/src/main/java/racal/sunyard/main/SydApiMuti.java @@ -0,0 +1,4 @@ +package racal.sunyard.main; + +public class SydApiMuti extends SydApi4j { +} diff --git a/src/main/java/racal/sunyard/main/SydApiPoolBuilder.java b/src/main/java/racal/sunyard/main/SydApiPoolBuilder.java new file mode 100644 index 0000000..d1aef18 --- /dev/null +++ b/src/main/java/racal/sunyard/main/SydApiPoolBuilder.java @@ -0,0 +1,35 @@ +package racal.sunyard.main; + +import com.sunyard.SydApi; +import com.sunyard.pool.HsmLinkInfo; +import com.sunyard.pool.SydApiPool; + +public class SydApiPoolBuilder { + private SydApiPool pool; + + public SydApiPoolBuilder(String[] pcIpList, int[] iPortList, int iConnectTimeOut, int iDealTimeOut) { + HsmLinkInfo[] linkInfo = HsmLinkInfo.mutiHsmLinkInfo(pcIpList, iPortList, iConnectTimeOut, iDealTimeOut); + this.pool = new SydApiPool(linkInfo); + this.warmUp(pcIpList, iPortList, iConnectTimeOut, iDealTimeOut); + } + + public SydApi build() { + return (SydApi)this.pool.get(); + } + + private void warmUp(String[] pcIpList, int[] iPortList, int iConnectTimeOut, int iDealTimeOut) { +// SydApi4j api = null; + SydApi api = null; + try { +// api = new SydApi4j(); + api = SydApiClusterBuilder.SYD_Short_Connect_Ex(pcIpList, iPortList, iConnectTimeOut, iDealTimeOut); + } catch (Exception e) { + } finally { + if (null != api) { + api.disconnect(); + } + + } + + } +} diff --git a/src/main/java/racal/sunyard/main/SydHashApiTest.java b/src/main/java/racal/sunyard/main/SydHashApiTest.java new file mode 100644 index 0000000..5f6d7c7 --- /dev/null +++ b/src/main/java/racal/sunyard/main/SydHashApiTest.java @@ -0,0 +1,69 @@ +package racal.sunyard.main; + +public interface SydHashApiTest { + + /** + * 计算SM3散列值 + * @param sn 证书序号 + * @param userId 用户ID + * @param msg 原始数据,二进制的消息块 + * @return + */ + byte[] SM3HashSNaId(String sn, String userId, byte[] msg); + + /** + * 输入对指定的原始数据和公钥,通过 SM3 算法计算数据的散列值。 + * @param publicKey 公钥的 DER 编码(可以为空) + * @param msg 原始数据,二进制的消息块 + * @param block 消息块标志 + * @param mac 上一轮 mac 值,当 mac 不是 null,长度不为 0,则直接从第二包开始。 + * @return HASH 值,32 个 Bytes. + */ + byte[] SM3Hash(String publicKey, byte[] msg, int block, byte[] mac); + + /** + * 计算SM3散列值 + * @param publicKey 公钥的 DER 编码 (03420004 开头) + * @param userId 用户ID + * @param msg 原始数据,二进制的消息块 + * @return + */ + byte[] SM3Hash(String publicKey, String userId, byte[] msg); + + /** + * 输入对指定的原始数据和公钥,通过 SM3 算法计算数据的散列值。 + * + * @param publicKey 公钥(可以为空) + * @param msg 原始数据 + * @return HASH 值,32 个 Bytes. + */ + byte[] SM3Hash(String publicKey, byte[] msg); + + + /** + * 输入对指定的原始数据 (无公钥),通过 SM3 算法计算数据的散列值。 + * + * @param msg 原始数据 + * @return HASH 值,32 个 Bytes. + */ + byte[] SM3Hash(byte[] msg); + + + public byte[] MACCalc(int alg, int keyType, int fullmode, int maclen, String key, byte[] infoData); + + /** + * mac 计算 + * @param alg 0=DES 1=3DES 2=SM4 3=AES 4=IDEA 5=SM1 6=3DES-X9.19 + * @param keyType 0-TAK 1-ZAK + * @param fullMode 0-弱填充 1 强填充 + * @param AK 密钥 + * @param infoData <=1024 + * @param macLen 1=4Byte 2=8Byte 3=16Byte(仅在SM4/AES 下有效) + * @return mac 值 hex 格式 + */ + public String MACCalc(int alg, int keyType, String AK, int fullMode, byte[] infoData, int macLen); + public void MACCheck(int alg, int keyType, String AK, int fullMode, byte[] infoData, String mac); + + public String calcPBOCMAC(int mode, int keyType, String key, byte[] data, int block, byte[] iv); + } + diff --git a/src/test/java/SM3Test.java b/src/test/java/SM3Test.java new file mode 100644 index 0000000..51b1352 --- /dev/null +++ b/src/test/java/SM3Test.java @@ -0,0 +1,24 @@ +import com.sunyard.SydApi; +import com.sunyard.proto.Util; +import racal.sunyard.main.SydApi4j; + +import java.nio.charset.StandardCharsets; + +public class SM3Test { + + public static void main(String[] args) { + + SydApi api = new SydApi4j().connect("192.168.0.100", 8889, null, 1000); + try { + byte[] data = api.SM3Hash("test".getBytes(StandardCharsets.UTF_8)); + System.out.println("hex=" + Util.bytes2HexString(data)); + }catch ( Exception e ) { + e.printStackTrace(); + } + + + + + } + +} diff --git a/src/test/java/com/sunyard/sydapi/ChuanhuaDemo1.java b/src/test/java/com/sunyard/sydapi/ChuanhuaDemo1.java new file mode 100644 index 0000000..3e247a3 --- /dev/null +++ b/src/test/java/com/sunyard/sydapi/ChuanhuaDemo1.java @@ -0,0 +1,45 @@ +package com.sunyard.sydapi; + +import org.junit.Test; +import racal.sunyard.main.SydApi4j; + +/** + * 传化签名验签demo + * */ +public class ChuanhuaDemo1 { + + public static void main(String[] args) { + + // 调试模式 + System.setProperty("com.sunyard.sydapi4j.debug", "true"); + + // 建立链接(单台) + SydApi4j api = (SydApi4j) new SydApi4j().connect("192.168.0.100", 8889, null, 1000); + + try { + + final String testSN1 = "1004282451"; + final String testSN2 = "1004282452"; + + byte[] testData = "1234567812345678信达雅SUNYARDsunyard".getBytes("UTF-8"); + + System.out.println("\n\n----- 用指定的证书私钥对指定的数据进行数字签名。 -----"); + String signPri = api.netSign(testSN1, testData); + System.out.print("sign : "); + System.out.println(signPri); + // 验签传原始数据 + System.out.println("\n\n----- 用指定的证书私钥对指定的数据进行数字验证。 -----"); + if (api.netVerify(testSN1, testData, signPri)) { + System.out.println("验证通过"); + } else { + System.out.println("验证失败"); + } + + }catch (Exception e){ + e.printStackTrace(); + }finally { + api.disconnect(); + } + } + +} diff --git a/src/test/java/com/sunyard/sydapi/ChuanhuaDemo2.java b/src/test/java/com/sunyard/sydapi/ChuanhuaDemo2.java new file mode 100644 index 0000000..314b29d --- /dev/null +++ b/src/test/java/com/sunyard/sydapi/ChuanhuaDemo2.java @@ -0,0 +1,65 @@ +package com.sunyard.sydapi; + +import com.sunyard.proto.Util; +import org.junit.Assert; +import racal.sunyard.main.SydApi4j; + + +/** + * 传化国密加解密demo + * */ +public class ChuanhuaDemo2 { + + /*public static void write(String file, byte[] content) { + try { + File f = new File(file); + if (!f.exists()) { + f.createNewFile(); + } + FileOutputStream fos = new FileOutputStream(f); + fos.write(content); + } catch (Exception e) { + System.out.println("写入文件 " + file + " 异常"); + } + }*/ + public static void main(String[] args){ + + // 调试模式 + System.setProperty("com.sunyard.sydapi4j.debug", "true"); + + // 建立链接(单台) +// SydApi4j api = (SydApi4j) new SydApi4j().connect("192.168.0.100", 8889, null, 1000); + SydApi4j api = (SydApi4j) new SydApi4j().connect("172.16.18.59", 8889, null, 1000); + + + try{ + +// final String testSN1 = "1004282451";//签名 +// final String testSN2 = "1004282452";//加密 + final String userId = "1747"; + + byte[] testData = "1234567812345678信达雅SUNYARDsunyard@!#$%^加密s".getBytes("GBK"); + + String pk = api.SM2GetPublicKeyC(userId, 1); + System.out.println("pk= " + pk); + + System.out.println("\n\n----- 用输入的会话密钥,对指定报文数据进行加密处理。 SM2 -----"); + String sdata = api.SM2Encrypt(Util.hexString2Bytes(pk), testData); + System.out.println("加密后的数据: " + sdata); + + System.out.println("\n\n----- 用输入的会话密钥,对指定报文数据进行解密处理。 SM2 -----"); + byte[] data = api.SM2DecryptC(userId, sdata); + Assert.assertArrayEquals(testData, data); + System.out.println("解密后的数据: " + new String(data)); +// write("./data.txt",data); + + + }catch (Exception e){ + e.printStackTrace(); + }finally { + api.disconnect(); + } + + } + +} diff --git a/src/test/java/com/sunyard/sydapi/test/Test8011.java b/src/test/java/com/sunyard/sydapi/test/Test8011.java new file mode 100644 index 0000000..49d078d --- /dev/null +++ b/src/test/java/com/sunyard/sydapi/test/Test8011.java @@ -0,0 +1,32 @@ +package com.sunyard.sydapi.test; + +import racal.sunyard.main.SydApi4j; + +public class Test8011 { + + private static final String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; + + // private static final String dn = "C=CN,O=Sunyard,OU=8001,CN=8001"; + // private static final String dn = "1004282451"; + + + public static void main(String[] args) { + + System.setProperty("com.sunyard.sydapi4j.debug", "true"); + + SydApi4j api = (SydApi4j) new SydApi4j().connect("172.16.18.59", 8889, null, 1000); + + try { + + boolean sign = api.deleteCert(dn); + System.out.println(sign); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + api.disconnect(); + } + + + } +} diff --git a/src/test/java/sample/HSMPoolLongLink.java b/src/test/java/sample/HSMPoolLongLink.java new file mode 100644 index 0000000..dac017e --- /dev/null +++ b/src/test/java/sample/HSMPoolLongLink.java @@ -0,0 +1,51 @@ +package sample; + +import com.sunyard.SydApi; +import com.sunyard.proto.Util; +import org.junit.Assert; +import racal.sunyard.main.SydApiPoolBuilder; + +import java.nio.charset.StandardCharsets; + + +/** + * 集群模式 - 长连接 + */ +public class HSMPoolLongLink { + + public static void main(String[] args) { + + // 调试模式 + System.setProperty("com.sunyard.sydapi4j.debug", "true"); + + // 建立链接 + String[] pcipList = {"172.16.18.59","192.168.0.200"}; + int[] iportList = {8889,8889}; + + for (int i = 0; i < 1000; i++) { + int tmp = i; + new Thread(() -> { + SydApiPoolBuilder builder = new SydApiPoolBuilder(pcipList, iportList, 10, 1000); + SydApi api = builder.build(); + try { + for (int j = 0; j < 20; j++) { + byte[] data = api.SM3Hash("test".getBytes(StandardCharsets.UTF_8)); + System.out.println("hex=" + Util.bytes2HexString(data)); +// boolean sign = api.deleteCert("C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"); +// System.out.println(sign); + } + } catch (Exception e){ + e.printStackTrace(); + } + finally { + if (null != api) { + api.disconnect(); + } + } + }, i + "t").start(); + } + System.out.println(1); + } +} + + diff --git a/src/test/java/sample/HSMPoolShortLink.java b/src/test/java/sample/HSMPoolShortLink.java new file mode 100644 index 0000000..4768248 --- /dev/null +++ b/src/test/java/sample/HSMPoolShortLink.java @@ -0,0 +1,52 @@ +package sample; + +import com.sunyard.SydApi; +import com.sunyard.cert.X509; +import com.sunyard.proto.Util; +import racal.sunyard.main.SydApiClusterBuilder; + +import java.nio.charset.StandardCharsets; + + +/** + * 集群模式 - 短连接 + */ +public class HSMPoolShortLink { + + public static void main(String[] args) { + + // 调试模式 + System.setProperty("com.sunyard.sydapi4j.debug", "true"); + + // 建立链接 + String[] pcipList = {"172.16.18.59", "192.168.0.200"}; + int[] iportList = {8889, 8889}; + + + for (int i = 0; i < 1000; i++) { + int tmp = i; + new Thread(() -> { + SydApi api = SydApiClusterBuilder.SYD_Short_Connect_Ex( + pcipList, + iportList, + 10, + 1000); + try { + for (int j = 0; j < 20; j++) { + byte[] data = api.SM3Hash("test".getBytes(StandardCharsets.UTF_8)); + System.out.println("hex=" + Util.bytes2HexString(data)); +// boolean sign = api.deleteCert("C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"); +// System.out.println(sign); + } + + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (null != api) { + api.disconnect(); + } + } + }, i + "t").start(); + } + } +}