commit a877436fcc6378c188e563b936d9ba378aafea31 Author: Cheney Date: Tue Nov 5 16:48:28 2024 +0800 first commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a401829 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# auto generated by UGit +translog filter=lfs diff=lfs merge=binary -text +*.zip filter=lfs diff=lfs merge=binary -text +*.pdf filter=lfs diff=lfs merge=binary -text +*.so filter=lfs diff=lfs merge=binary -text +*.jar filter=lfs diff=lfs merge=binary -text +*.o filter=lfs diff=lfs merge=binary -text +*.dll filter=lfs diff=lfs merge=binary -text +*.doc filter=lfs diff=lfs merge=binary -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b482f4c --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store +SydLog +.idea diff --git a/README.md b/README.md new file mode 100644 index 0000000..f070a66 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# sdf1102 + +java 对接 三合一版本加密机 SDF 接口封装 + + +## 注意 +git 自动转换回车会导致动态库错误。执行命令关闭自动转换。 +``` +git config --global core.autocrlf false +``` diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml new file mode 100644 index 0000000..00632c2 --- /dev/null +++ b/dependency-reduced-pom.xml @@ -0,0 +1,122 @@ + + + 4.0.0 + com.sunyard + sdf1102 + 1.0-SNAPSHOT + + + + maven-shade-plugin + 2.4.3 + + + package + + shade + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + ${project.artifactId}-${project.version} + + + com.sunyard.security.Main + + + META-INF/spring.handlers + + + META-INF/spring.schemas + + + META-INF/spring.tooling + + + Apache CXF + + + META-INF/cxf/cxf.extension + + + META-INF/extensions.xml + + + META-INF/cxf/extensions.xml + + + META-INF/cxf/bus-extensions.txt + + + META-INF/cxf/bus-extensions.xml + + + META-INF/wsdl.plugin.xml + + + META-INF/cxf/java2wsbeans.xml + + + META-INF/spring.handlers + + + META-INF/spring.schemas + + + + + + + + + + + com.github.edwgiz + maven-shade-plugin.log4j2-cachefile-transformer + 2.6.1 + + + + + + + + junit + junit + 4.12 + test + + + hamcrest-core + org.hamcrest + + + + + + + nexus-own + repo-release + ${ReleaseRepository} + + + nexus-own + repo-snapshot + ${SnapshotRepository} + + + + UTF-8 + 8 + 8 + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d34bf3d --- /dev/null +++ b/pom.xml @@ -0,0 +1,162 @@ + + + 4.0.0 + + com.sunyard + sdf1102 + 1.0-SNAPSHOT + + + 8 + 8 + UTF-8 + + + + + nexus-own + repo-snapshot + ${SnapshotRepository} + + + nexus-own + repo-release + ${ReleaseRepository} + + + + + + + + net.java.dev.jna + jna + 5.5.0 + + + + org.projectlombok + lombok + 1.18.28 + + + + com.sunyard + loadbalancing + 1.2.201905230000 + + + + junit + junit + 4.12 + test + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.3 + + + package + + shade + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + ${project.artifactId}-${project.version} + + + com.sunyard.security.Main + + + + META-INF/spring.handlers + + + META-INF/spring.schemas + + + META-INF/spring.tooling + + + Apache CXF + + + META-INF/cxf/cxf.extension + + + META-INF/extensions.xml + + + META-INF/cxf/extensions.xml + + + META-INF/cxf/bus-extensions.txt + + + META-INF/cxf/bus-extensions.xml + + + META-INF/wsdl.plugin.xml + + + META-INF/cxf/java2wsbeans.xml + + + META-INF/spring.handlers + + + META-INF/spring.schemas + + + + + + + + + + + com.github.edwgiz + maven-shade-plugin.log4j2-cachefile-transformer + 2.6.1 + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/sunyard/security/Main.java b/src/main/java/com/sunyard/security/Main.java new file mode 100644 index 0000000..bf05c71 --- /dev/null +++ b/src/main/java/com/sunyard/security/Main.java @@ -0,0 +1,69 @@ +package com.sunyard.security; + +import com.sun.jna.Pointer; +import com.sun.jna.ptr.PointerByReference; +import com.sunyard.security.sdf.SDFJna; +import com.sunyard.security.util.ByteUtil; + +public class Main { + private static PointerByReference phDeviceHandle = new PointerByReference(); + private static PointerByReference phSessionHandle = new PointerByReference();; + private static final byte[] data = new byte[16]; + private static final byte[] symKey = new byte[]{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; + private static final String ip = "172.16.17.245"; + + + public static void random(){ + + int oneSize = 16; + byte[] oneRadom = new byte[16]; // 注意这里初始化大小应为 oneSize + int ret = SDFJna.INSTANCE.SDF_GenerateRandom( phSessionHandle.getValue(), oneSize, oneRadom ); + + if (ret != 0) { + throw new RuntimeException(String.format("0x%02X", ret)); + } else { + System.out.println("调用成功"); + } + System.out.println( ByteUtil.bytes2HexString( oneRadom ) ); + } + + + public static void main(String[] args) { + + // 打开设备 + int ret = SDFJna.INSTANCE.SDF_OpenDevice( + phDeviceHandle, + ByteUtil.safeStringBytes(ip), + 8889, + 3000, + 3000, + 0); + + if (ret != 0) { + System.err.println("打开设备失败 错误码:" + String.format("0x%02X", ret)); + throw new RuntimeException(String.format("0x%02X", ret)); + } + Pointer hDeviceHandle = phDeviceHandle.getValue(); + // 打开会话 + ret = SDFJna.INSTANCE.SDF_OpenSession(hDeviceHandle, phSessionHandle); + if (ret != 0) { + System.err.println("打开设备失败 错误码:" + String.format("0x%02X", ret)); + throw new RuntimeException(String.format("0x%02X", ret)); + } + + + try { + random(); + + } finally { + if ( null != phSessionHandle.getValue() ) { + SDFJna.INSTANCE.SDF_CloseSession( phSessionHandle.getValue() ); + } + if ( null != phDeviceHandle.getValue() ) { + SDFJna.INSTANCE.SDF_CloseDevice(phDeviceHandle.getValue()); + } + } + + } + +} diff --git a/src/main/java/com/sunyard/security/enum/RdEnum.java b/src/main/java/com/sunyard/security/enum/RdEnum.java new file mode 100644 index 0000000..543d1ab --- /dev/null +++ b/src/main/java/com/sunyard/security/enum/RdEnum.java @@ -0,0 +1,15 @@ +package com.sunyard.security; + +public enum RdEnum { + RD_PATH("./lib/rd"), + RD_DATA_FILE_PATH("./data/data.bin"), + RD_DATA_PATH("./data/"), + RD_REPORT_PATH("./report/report.csv"); + private String value; + public String getValue() { + return value; + } + RdEnum(String value){ + this.value=value; + } +} diff --git a/src/main/java/com/sunyard/security/sdf/AlgorithmEnum.java b/src/main/java/com/sunyard/security/sdf/AlgorithmEnum.java new file mode 100644 index 0000000..791565a --- /dev/null +++ b/src/main/java/com/sunyard/security/sdf/AlgorithmEnum.java @@ -0,0 +1,49 @@ +package com.sunyard.security.sdf; + +/** + * @author 梁俊杰 + * @date 2024/05/22 + */ +public enum AlgorithmEnum { + /** + * sm4 ecb 算法标识 + */ + SGD_SM4_ECB(0x00000401), + + /** + * sm4 ecb 算法标识 + */ + SGD_SM4_CBC(0x00000402), + + /** + * sm2 算法标识 + */ + SGD_SM2(0x00020100), + + /** + * sm3 算法标识 + */ + SGD_SM3(0x00000001), + + /** + * 密码设备存储私钥的索引值 + */ + SM2_INDEX(0x02), + + SGD_SM4_MAC(0x00000410), + ; + + + AlgorithmEnum(int value){ + this.value = value; + } + + public int getValue() { + return value; + } + + /** + * 算法标识 + */ + private final int value; +} diff --git a/src/main/java/com/sunyard/security/sdf/LibEnum.java b/src/main/java/com/sunyard/security/sdf/LibEnum.java new file mode 100644 index 0000000..8a18456 --- /dev/null +++ b/src/main/java/com/sunyard/security/sdf/LibEnum.java @@ -0,0 +1,27 @@ +package com.sunyard.security.sdf; + +/** + * 动态库枚举类 + * @author admin + */ +public enum LibEnum { + + /** + * 动态库路径 + */ + LIB_PATH("./lib"), + LIB_NAME("sdf"); + + /** + * 值 + */ + private final String value; + + LibEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/com/sunyard/security/sdf/SDFJna.java b/src/main/java/com/sunyard/security/sdf/SDFJna.java new file mode 100644 index 0000000..c4f73bc --- /dev/null +++ b/src/main/java/com/sunyard/security/sdf/SDFJna.java @@ -0,0 +1,401 @@ +package com.sunyard.security.sdf; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; + +/** + * @author sunyard + */ +public interface SDFJna extends Library { + + /** + * 加载动态库 + */ + SDFJna INSTANCE = Native.load(LibEnum.LIB_NAME.getValue(), SDFJna.class); + + + /** + * 打开设备 + * @param phDeviceHandle 设备句柄 + * @return int 响应码 + */ + int SDF_OpenDevice(PointerByReference phDeviceHandle, byte[] ip, int port, int connTimeout, int dealTimeout, int ipMode); + + /** + * 关闭设备 + * @param hDeviceHandle 设备句柄 + * @return int 响应码 + */ + int SDF_CloseDevice(Pointer hDeviceHandle); + + /** + * 打开会话 + * @param hDeviceHandle 设备句柄 + * @param phSessionHandle 会话句柄 + * @return int 响应码 + */ + int SDF_OpenSession(Pointer hDeviceHandle, PointerByReference phSessionHandle); + + /** + * 关闭会话 + * @param hSessionHandle 会话句柄 + * @return int 响应码 + */ + int SDF_CloseSession(Pointer hSessionHandle); + + /** + * 生成随机数 + * @param hSessionHandle 会话句柄 + * @param uiLength 生成随机数长度 + * @param pucRandom 存放随机数容器 + * @return int 响应码 + */ + int SDF_GenerateRandom(Pointer hSessionHandle, int uiLength, byte[] pucRandom); + + + int SDF_ImportKey(Pointer hSessionHandle, byte[] pucKey, int uiKeyLen, PointerByReference phKeyhandle); + /** + * 导出签名公钥 + * @param phSessionHandle + * @param uiKeyIndex + * @param pucPublicKey + * @return + */ + int SDF_ExportSignPublicKey_ECC(Pointer phSessionHandle, + int uiKeyIndex, + byte[] pucPublicKey); + + /** + * 导出加密公钥 + * @param phSessionHandle + * @param uiKeyIndex + * @param pucPublicKey + * @return + */ + int SDF_ExportEncPublicKey_ECC(Pointer phSessionHandle, + int uiKeyIndex, + byte[] pucPublicKey); + + /** + * 生成会话密钥并用内部 ECC公钥加密输出,输出密钥句柄 + * @param phSessionHandle + * @param uiIPKIndex + * @param uiKeyBits + * @param puckey + * @param phKeyhandle + * @return + */ + int SDF_GenerateKeyWithIPK_ECC(Pointer phSessionHandle, + int uiIPKIndex, + int uiKeyBits , + byte[] puckey, + PointerByReference phKeyhandle); + + /** + * 生成会话密钥并用外部ECC公钥加密输出,输出密钥句柄 + * @param hSessionHandle 会话句柄 + * @param uiKeyBits 密钥长度 + * @param uiAlgID 算法标识 + * @param pucPublicKey ECC公钥结构 + * @param pucKey 密钥密文 + * @param phKeyHandle 密钥句柄 + * @return int 响应码 + */ + int SDF_GenerateKeyWithEPK_ECC( + Pointer hSessionHandle, + int uiKeyBits, + int uiAlgID, + byte[] pucPublicKey, + byte[] pucKey, + PointerByReference phKeyHandle + ); + + /** + * 导入会话密钥并用内部ECC私钥解密 + * @param phSessionHandle + * @param uiISKIndex + * @param puckey + * @param phKeyhandle + * @return + */ + int SDF_ImportKeyWithISK_ECC(Pointer phSessionHandle, + int uiISKIndex, + byte[] puckey, + PointerByReference phKeyhandle); + + + /** + * 销毁会话密钥 + * @param phSessionHandle + * @param phKeyhandle + * @return + */ + int SDF_DestroyKey(Pointer phSessionHandle, PointerByReference phKeyhandle); + + + /** + * 生成ECC密钥对 + * @param phSessionHandle 会话句柄 + * @param uiAlgID 算法标识 + * @param uiKeyBits 密钥长度 + * @param pucPublicKey 输出的ECC公钥结构 + * @param pucPrivateKey 输出的ECC私钥结构 + * @return int 响应码 + */ + int SDF_GenerateKeyPair_ECC( + Pointer phSessionHandle, + int uiAlgID, + int uiKeyBits, + byte[] pucPublicKey, + byte[] pucPrivateKey + ); + + + /** + * 对称加密 + * @param phSessionHandle 会话句柄 + * @param hKeyHandle 密钥句柄 + * @param uiAlgID 算法标识 + * @param pucIV IV数据 + * @param pucData 待加密数据 + * @param pucDataLength 待加密数据长度 + * @param pucEncData 存放密文容器 + * @param pucEncDataLength 密文长度 + * @return int 响应码 + */ + int SDF_Encrypt( + Pointer phSessionHandle, + Pointer hKeyHandle, + int uiAlgID, + byte[] pucIV, + byte[] pucData, + int pucDataLength, + byte[] pucEncData, + IntByReference pucEncDataLength + ); + + /** + * 对称解密 + * @param phSessionHandle 会话句柄 + * @param hKeyHandle 密钥句柄 + * @param uiAlgID 算法标识 + * @param pucIV IV数据 + * @param purEncData 指向密文数据的指针 + * @param encDataLength 密文数据长度 + * @param pucData 输出明文数据 + * @param pucDataLength 输出明文数据长度 + * @return int 响应码 + */ + int SDF_Decrypt( + Pointer phSessionHandle, + Pointer hKeyHandle, + int uiAlgID, + byte[] pucIV, + byte[] purEncData, + int encDataLength, + byte[] pucData, + IntByReference pucDataLength + ); + + + + /** + * 杂凑运算初始化 + * @param phSessionHandle 会话句柄 + * @param uiAlgID 算法标识 + * @param pucPublicKey ECC公钥结构 + * @param pucID 签名者的ID值 + * @param pucIDlength 签名者ID的长度 + * @return int 响应码 + */ + int SDF_HashInit(Pointer phSessionHandle, int uiAlgID, byte[] pucPublicKey, String pucID, int pucIDlength); + + /** + * 多包杂凑运算 + * @param phSessionHandle 会话句柄 + * @param pucData 输入的数据明文 + * @param uiDataLength 输入的数据明文长度 + * @return int 响应码 + */ + int SDF_HashUpdate( + Pointer phSessionHandle, // 使用IntByReference,因为SessionHandle可能是引用类型的 + byte[] pucData, // 输入的明文数据作为字节数组 + int uiDataLength // 明文数据长度 + ); + + /** + * 杂凑运算结束 + * @param phSessionHandle 会话句柄 + * @param pucHash 杂凑结果 + * @param pucHashLength 杂凑结果长度 + * @return int 响应码 + */ + int SDF_HashFinal(Pointer phSessionHandle, byte[] pucHash, IntByReference pucHashLength); + + + int SDF_CalculateMAC(Pointer phSessionHandle, + Pointer hKeyHadnle, + int uiAlgID, + byte[] pucIV, + byte[] purData, + int pucDatalength, + byte[] pucMAC, + IntByReference pucMACLength); + + /** + * 外部ECC签名 + * @param phSessionHandle 会话句柄 + * @param uiAlgID 算法标识 + * @param pucPublicKey ECC公钥结构 + * @param pucData 输入的数据明文 + * @param pucDataLength 输入的数据明文长度 + * @param pucECCSignature 输出的签名值数据 + * @return int 响应码 + */ + int SDF_ExternalSign_ECC( + Pointer phSessionHandle, + int uiAlgID, + byte[] pucPublicKey, + byte[] pucData, + int pucDataLength, + byte[] pucECCSignature + ); + + /** + * 外部ECC验签 + * @param phSessionHandle 会话句柄 + * @param uiAlgID 算法标识 + * @param pucPublicKey ECC公钥结构 + * @param pucData 输入的数据明文 + * @param pucDataLength 输入的数据明文长度 + * @param pucECCSignature 输入的签名值数据 + * @return int 响应码 + */ + int SDF_ExternalVerify_ECC(Pointer phSessionHandle, int uiAlgID, byte[] pucPublicKey, byte[] pucData, int pucDataLength, byte[] pucECCSignature); + + /** + * 内部密钥ECC签名 + * @param phSessionHandle + * @param uiAlgID + * @param uiISKIndex + * @param pucData + * @param pucDatalength + * @param pucECCSignature + * @return + */ + int SDF_InternalSign_ECC(Pointer phSessionHandle, + int uiISKIndex, + byte[] pucData, + int pucDatalength, + byte[] pucECCSignature); + + + /** + * 内部密钥ECC签名 + * @param phSessionHandle + * @param uiISKIndex + * @param pucData + * @param pucDatalength + * @param pucECCSignature + * @return + */ + int SDF_InternalVerify_ECC(Pointer phSessionHandle, + int uiISKIndex, + byte[] pucData, + int pucDatalength, + byte[] pucECCSignature); + + /** + * 密钥加密 + * @param phSessionHandle 会话句柄 + * @param uiAlgID 算法标识 + * @param pucPublicKey ECC公钥结构 + * @param pucData 输入的数据明文 + * @param pucDatalength 输入的数据明文长度 + * @param pucEncData 输出的密文数据 + * @return int 响应码 + */ + int SDF_ExternalEncrypt_ECC(Pointer phSessionHandle, int uiAlgID, byte[] pucPublicKey, byte[] pucData, int pucDatalength, byte[] pucEncData); + + /** + * 密钥解密 + * @param phSessionHandle 会话句柄 + * @param uiAlgID 算法标识 + * @param pucPrivateKey ECC私钥结构 + * @param pucEncData 输入的密文数据 + * @param pucDataOut 输出的数据明文 + * @param pucDatalength 输出的数据明文长度 + * @return int 响应码 + */ + int SDF_ExternalDecrypt_ECC(Pointer phSessionHandle, int uiAlgID, byte[] pucPrivateKey, byte[] pucEncData, byte[] pucDataOut, IntByReference pucDatalength); + + /** + * 生成密钥协商数据 + * @param phSessionHandle 会话句柄 + * @param uiISKIndex 密码设备存储私钥的索引值 + * @param uiKeyBits 要求协商的密钥长度 + * @param pucSponsorID 参与密钥协商的发起方ID值 + * @param uiSponsorIDLength 发起方ID长度 + * @param pucSponsorPublicKey 返回的发起方ECC公钥结构 + * @param pucSponsorTmpPublicKey 返回的发起方临时ECC公钥结构 + * @param phAgreementHandle 返回的协商对象,用于计算协商密钥 + * @return int 响应码 + */ + int SDF_GenerateAgreementDataWithECC(Pointer phSessionHandle, int uiISKIndex, int uiKeyBits, + String pucSponsorID, int uiSponsorIDLength, + byte[] pucSponsorPublicKey, byte[] pucSponsorTmpPublicKey, + PointerByReference phAgreementHandle); + + /** + * 生成密钥协商数据并计算密钥 + * @param phSessionHandle 会话句柄 + * @param uiISKIndex 密码设备存储私钥的索引值 + * @param uiKeyBits 要求协商的密钥长度 + * @param pucResponseID 参与密钥协商的响应方ID值 + * @param uiResponseIDLength 响应方ID长度 + * @param pucSponsorID 参与密钥协商的发起方ID值 + * @param uiSponsorIDLength 发起方ID长度 + * @param pucSponsorPublicKey 发起方ECC公钥结构 + * @param pucSponsorTmpPublicKey 发起方临时ECC公钥结构 + * @param pucResponsePublicKey 响应方ECC公钥结构 + * @param pucResponseTmpPublicKey 响应方临时ECC公钥结构 + * @param phKeyhandle 返回的密钥句柄 + * @return + */ + int SDF_GenerateAgreementDataAndKeyWithECC( + Pointer phSessionHandle, + int uiISKIndex, + int uiKeyBits, + String pucResponseID, + int uiResponseIDLength, + String pucSponsorID, + int uiSponsorIDLength, + byte[] pucSponsorPublicKey, + byte[] pucSponsorTmpPublicKey, + byte[] pucResponsePublicKey, + byte[] pucResponseTmpPublicKey, + PointerByReference phKeyhandle + ); + + /** + * 获取私钥访问权 + * @param phSessionHandle 会话句柄 + * @param uiKeyIndex 密码设备存储私钥的索引值 + * @param pucPassword 使用私钥权限的标识码 + * @param uiPwdLength 私钥访问控制码长度,不少于8字节 + * @return int 响应码 + */ + int SDF_GetPrivateKeyAccessRight(Pointer phSessionHandle, int uiKeyIndex, String pucPassword, int uiPwdLength); + + /** + * 释放私钥访问权 + * @param phSessionHandle 会话句柄 + * @param uiKeyIndex 密码设备存储私钥的索引值 + * @return int 响应码 + */ + int SDF_ReleasePrivateKeyAccessRight(Pointer phSessionHandle, int uiKeyIndex); + + } diff --git a/src/main/java/com/sunyard/security/util/ByteUtil.java b/src/main/java/com/sunyard/security/util/ByteUtil.java new file mode 100644 index 0000000..c196b83 --- /dev/null +++ b/src/main/java/com/sunyard/security/util/ByteUtil.java @@ -0,0 +1,114 @@ +package com.sunyard.security.util; + +import java.util.Arrays; + +public class ByteUtil { + /** + * PKCS5/PKCS7 标准填充数据 + * @param data + * @return + */ + public static byte[] pkcsFullPadding(byte[] data) { + int remainder = data.length % 16; + remainder = 16 - remainder; + + byte[] buff = new byte[ data.length + remainder ]; + System.arraycopy( data, 0, buff, 0, data.length ); + Arrays.fill( buff, data.length, buff.length, (byte)( 0xFF & remainder )); + return buff; + } + + + + /** + * PKCS5/PKCS7 标准去除填充数据 + * @param data + * @param len 有效数据长度 + * @return + */ + public static byte[] pkcsRemovePadding(byte[] data, int len) { + if ( data.length < len ) { + throw new IllegalArgumentException(); + } + int remainder = data[ len - 1 ]; + if ( remainder < 0 || remainder > 16 || remainder > len ) { + throw new IllegalArgumentException(); + } + len -= remainder; + byte[] buff = new byte[ len ]; + System.arraycopy( data, 0, buff, 0, len ); + return buff; + } + + public static byte[] pkcsRemovePadding(byte[] data){ + return pkcsRemovePadding( data, data.length ); + } + + + public static String bytes2HexString(byte[] b) { + StringBuilder bs = new StringBuilder(); + + for (int i = 0; i < b.length; ++i) { + String hex = Integer.toHexString(b[i] & 255); + if (hex.length() == 1) { + hex = '0' + hex; + } + + bs.append(hex.toUpperCase()); + } + + return bs.toString(); + } + + public static String bytes2HexString(byte[] b, int len) { + StringBuilder bs = new StringBuilder(); + + for (int i = 0; i < len; ++i) { + String hex = Integer.toHexString(b[i] & 255); + if (hex.length() == 1) { + hex = '0' + hex; + } + + bs.append(hex.toUpperCase()); + } + + return bs.toString(); + } + + private static byte charToByte(char c) { + return (byte) "0123456789ABCDEF".indexOf(c); + } + + public static byte[] hexString2Bytes(String hex) { + if (hex != null && !hex.equals("")) { + if (hex.length() % 2 != 0) { + return new byte[0]; + } else { + hex = hex.toUpperCase(); + int len = hex.length() / 2; + byte[] b = new byte[len]; + char[] hc = hex.toCharArray(); + + for (int i = 0; i < len; ++i) { + int p = 2 * i; + b[i] = (byte) (charToByte(hc[p]) << 4 | charToByte(hc[p + 1]) & 0xff ); + } + + return b; + } + } else { + return new byte[0]; + } + } + + + public static byte[] safeStringBytes(String str){ + if ( null == str || str.isEmpty()) { + return new byte[] { 0x30 }; + } + int len = str.getBytes().length; + byte[] ret = new byte[len + 1]; + System.arraycopy(str.getBytes(), 0, ret, 0, len); + return ret; + } +} diff --git a/src/main/resources/linux-aarch64/libsdf.so b/src/main/resources/linux-aarch64/libsdf.so new file mode 100644 index 0000000..fe31239 --- /dev/null +++ b/src/main/resources/linux-aarch64/libsdf.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f642b7788f38da6950f274b35f9bf6ce5ee9859869f4a5b55553a68fb8b4be42 +size 188432 diff --git a/src/main/resources/linux-x86-64/libsdf.so b/src/main/resources/linux-x86-64/libsdf.so new file mode 100644 index 0000000..79b50aa --- /dev/null +++ b/src/main/resources/linux-x86-64/libsdf.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab77dace1c56ece5655cdeadbcea505bbcf09a2486f33487f4728dde4446ef4e +size 200216 diff --git a/src/main/resources/win32-x86-64/sdf.dll b/src/main/resources/win32-x86-64/sdf.dll new file mode 100644 index 0000000..8751b5a --- /dev/null +++ b/src/main/resources/win32-x86-64/sdf.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e386a8857618224dbd0e96aae9475be3278f9e598dac96f9be17e9f241aedf4 +size 264907 diff --git a/src/test/java/MutiThreads.java b/src/test/java/MutiThreads.java new file mode 100644 index 0000000..7f4bdd4 --- /dev/null +++ b/src/test/java/MutiThreads.java @@ -0,0 +1,117 @@ +import com.sun.jna.Pointer; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; +import com.sunyard.security.sdf.AlgorithmEnum; +import com.sunyard.security.sdf.SDFJna; +import com.sunyard.security.util.ByteUtil; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class MutiThreads { + + private PointerByReference phDeviceHandle = new PointerByReference(); + + private static final byte[] data = new byte[16]; + private static final byte[] symKey = new byte[]{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; + private static final String ip = "172.16.17.245"; + + private static final int thread_max = 16; + private static final int func_maxcall = 10000; + + @Before + public void before(){ + // 打开设备 + int ret = SDFJna.INSTANCE.SDF_OpenDevice( + phDeviceHandle, + ByteUtil.safeStringBytes(ip), + 8889, + 3000, + 3000, + 0); + + if (ret != 0) { + System.err.println("打开设备失败 错误码:" + String.format("0x%02X", ret)); + throw new RuntimeException(String.format("0x%02X", ret)); + } + } + + + @After + public void after(){ + if ( null != phDeviceHandle.getValue() ) { + SDFJna.INSTANCE.SDF_CloseDevice(phDeviceHandle.getValue()); + } + } + + private void genSessionKey(PointerByReference phSessionHandle, PointerByReference phkeyHandle){ + + int ret = SDFJna.INSTANCE.SDF_ImportKey(phSessionHandle.getValue(), symKey, symKey.length ,phkeyHandle); + if (ret != 0) { + throw new RuntimeException("genSessionKey " + String.format("0x%02X", ret)); + } + } + + /** + * 多线程加解密 + */ + @Test + public void sm4_en(){ + System.out.println(" sm4 en 测试开始"); + + Thread[] threads = new Thread[thread_max]; + for ( int i = 0; i < thread_max; i++ ) { + threads[i] = new Thread(new Runnable() { + @Override + public void run() { + + PointerByReference phSessionHandle = new PointerByReference(); + try { + Pointer hDeviceHandle = phDeviceHandle.getValue(); + // 打开会话 + int ret = SDFJna.INSTANCE.SDF_OpenSession(hDeviceHandle, phSessionHandle); + if (ret != 0) { + System.err.println("打开设备失败 错误码:" + String.format("0x%02X", ret)); + throw new RuntimeException(String.format("0x%02X", ret)); + } + + PointerByReference phkeyHandle = new PointerByReference(); + genSessionKey(phSessionHandle, phkeyHandle); + + for (int c= 0; c < func_maxcall; c++ ) { + byte[] enData = new byte[32]; + IntByReference intByReference = new IntByReference(); + ret = SDFJna.INSTANCE.SDF_Encrypt(phSessionHandle.getValue(), phkeyHandle.getValue(), AlgorithmEnum.SGD_SM4_ECB.getValue(), null, data, data.length, enData, intByReference); + if (ret != 0) { + throw new RuntimeException("加密失败 " + String.format("0x%02X", ret)); + } + } + } finally { + if ( null != phSessionHandle.getValue() ) { + SDFJna.INSTANCE.SDF_CloseSession( phSessionHandle.getValue() ); + } + } + } + }); + } + + long start = System.currentTimeMillis(); + for (Thread thread : threads) { + thread.start(); + } + + for (Thread thread : threads) { + try { + thread.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + long end = System.currentTimeMillis(); + long delta = end - start; + double p = (double) thread_max * func_maxcall * 1000.0 / delta; + System.out.println( " sm4 en " + p + "TPS"); + } + +} diff --git a/src/test/java/SDFTest.java b/src/test/java/SDFTest.java new file mode 100644 index 0000000..1c34f07 --- /dev/null +++ b/src/test/java/SDFTest.java @@ -0,0 +1,259 @@ +import com.sun.jna.Pointer; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; +import com.sunyard.security.sdf.AlgorithmEnum; +import com.sunyard.security.sdf.SDFJna; +import com.sunyard.security.util.ByteUtil; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class SDFTest { + + private PointerByReference phDeviceHandle = new PointerByReference(); + private PointerByReference phSessionHandle = new PointerByReference();; + private static final byte[] data = new byte[16]; + private static final byte[] symKey = new byte[]{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; + private static final String ip = "172.16.17.245"; + + + @Before + public void before(){ + // 打开设备 + int ret = SDFJna.INSTANCE.SDF_OpenDevice( + phDeviceHandle, + ByteUtil.safeStringBytes(ip), + 8889, + 3000, + 3000, + 0); + + if (ret != 0) { + System.err.println("打开设备失败 错误码:" + String.format("0x%02X", ret)); + throw new RuntimeException(String.format("0x%02X", ret)); + } + Pointer hDeviceHandle = phDeviceHandle.getValue(); + // 打开会话 + ret = SDFJna.INSTANCE.SDF_OpenSession(hDeviceHandle, phSessionHandle); + if (ret != 0) { + System.err.println("打开设备失败 错误码:" + String.format("0x%02X", ret)); + throw new RuntimeException(String.format("0x%02X", ret)); + } + } + + + @After + public void after(){ + if ( null != phSessionHandle.getValue() ) { + SDFJna.INSTANCE.SDF_CloseSession( phSessionHandle.getValue() ); + } + if ( null != phDeviceHandle.getValue() ) { + SDFJna.INSTANCE.SDF_CloseDevice(phDeviceHandle.getValue()); + } + } + + @Test + public void random(){ + + int oneSize = 16; + byte[] oneRadom = new byte[16]; // 注意这里初始化大小应为 oneSize + int ret = SDFJna.INSTANCE.SDF_GenerateRandom( phSessionHandle.getValue(), oneSize, oneRadom ); + + if (ret != 0) { + throw new RuntimeException(String.format("0x%02X", ret)); + } else { + System.out.println("调用成功"); + } + Assert.assertEquals( ret, 0 ); + System.out.println( ByteUtil.bytes2HexString( oneRadom ) ); + } + + + private void genSessionKey(PointerByReference phkeyHandle){ + + int ret = SDFJna.INSTANCE.SDF_ImportKey(phSessionHandle.getValue(), symKey, symKey.length ,phkeyHandle); + if (ret != 0) { + throw new RuntimeException("genSessionKey " + String.format("0x%02X", ret)); + } + } + + + /** + * SDF 接口内没有填充 + * 输入数据必须 16 的整倍数 + */ + @Test + public void sym_ecb(){ + int ret = 0; + PointerByReference phkeyHandle = new PointerByReference(); + genSessionKey(phkeyHandle); + + + System.out.println( "data=" + ByteUtil.bytes2HexString( data )); + byte[] enData = new byte[32]; + IntByReference intByReference = new IntByReference(); + ret = SDFJna.INSTANCE.SDF_Encrypt(phSessionHandle.getValue(), phkeyHandle.getValue(), AlgorithmEnum.SGD_SM4_ECB.getValue(), null, data, data.length, enData, intByReference); + if (ret != 0) { + throw new RuntimeException("加密失败 " + String.format("0x%02X", ret)); + } + System.out.println( intByReference.getValue() ); + System.out.println( "enData=" + ByteUtil.bytes2HexString( enData )); + byte[] rawData = new byte[32]; + ret = SDFJna.INSTANCE.SDF_Decrypt(phSessionHandle.getValue(), phkeyHandle.getValue(), AlgorithmEnum.SGD_SM4_ECB.getValue(), null, enData, intByReference.getValue(), rawData, intByReference); + if (ret != 0) { + throw new RuntimeException("解密失败 " + String.format("0x%02X", ret)); + } + System.out.println("长度" + intByReference.getValue()); + System.out.println( "rawData=" + ByteUtil.bytes2HexString( rawData , intByReference.getValue())); + } + + + @Test + public void sym_cbc(){ + int ret = 0; + PointerByReference phkeyHandle = new PointerByReference(); + genSessionKey(phkeyHandle); + + byte[] iv = new byte[16]; + + System.out.println( "data=" + ByteUtil.bytes2HexString( data )); + byte[] enData = new byte[32]; + IntByReference intByReference = new IntByReference(); + ret = SDFJna.INSTANCE.SDF_Encrypt(phSessionHandle.getValue(), phkeyHandle.getValue(), AlgorithmEnum.SGD_SM4_CBC.getValue(), iv, data, data.length, enData, intByReference); + if (ret != 0) { + throw new RuntimeException("加密失败 " + String.format("0x%02X", ret)); + } + System.out.println( intByReference.getValue() ); + System.out.println( "enData=" + ByteUtil.bytes2HexString( enData )); + byte[] rawData = new byte[32]; + iv = new byte[16]; + ret = SDFJna.INSTANCE.SDF_Decrypt(phSessionHandle.getValue(), phkeyHandle.getValue(), AlgorithmEnum.SGD_SM4_CBC.getValue(), iv, enData, intByReference.getValue(), rawData, intByReference); + if (ret != 0) { + throw new RuntimeException("解密失败 " + String.format("0x%02X", ret)); + } + System.out.println( "rawData=" + ByteUtil.bytes2HexString( rawData , intByReference.getValue())); + } + + @Test + public void mac(){ + int ret = 0; + PointerByReference phkeyHandle = new PointerByReference(); + genSessionKey(phkeyHandle); + + byte[] mac = new byte[32]; + IntByReference macLen = new IntByReference(); + ret = SDFJna.INSTANCE.SDF_CalculateMAC(phSessionHandle.getValue(), + phkeyHandle.getValue(), + AlgorithmEnum.SGD_SM4_MAC.getValue(), + new byte[16], + data, + data.length, + mac, + macLen + ); + if (ret != 0) { + throw new RuntimeException("CalculateMAC " + String.format("0x%02X", ret)); + } + System.out.println( ByteUtil.bytes2HexString( mac , macLen.getValue()) ); + } + + + @Test + public void hash(){ + int ret = 0; + byte[] mac = new byte[32]; + IntByReference macLen = new IntByReference(); + + ret = SDFJna.INSTANCE.SDF_HashInit( phSessionHandle.getValue(), AlgorithmEnum.SGD_SM3.getValue(), null, null, 0 ); + if (ret != 0) { + throw new RuntimeException("HashInit " + String.format("0x%02X", ret)); + } + ret = SDFJna.INSTANCE.SDF_HashUpdate(phSessionHandle.getValue(), data, data.length); + if (ret != 0) { + throw new RuntimeException("HashUpdate " + String.format("0x%02X", ret)); + } + ret = SDFJna.INSTANCE.SDF_HashFinal(phSessionHandle.getValue(), mac, macLen); + if (ret != 0) { + throw new RuntimeException("HashFinal " + String.format("0x%02X", ret)); + } + System.out.println( ByteUtil.bytes2HexString( mac , macLen.getValue()) ); + } + + + /** + * 非对称 签名验签 + * 外部密钥 + */ + @Test + public void asym_ext_sv(){ + byte[] puk = new byte[256]; + byte[] pak = new byte[256]; + byte[] hash = new byte[32]; + int ret = SDFJna.INSTANCE.SDF_GenerateKeyPair_ECC(phSessionHandle.getValue(), AlgorithmEnum.SGD_SM2.getValue(), 256, puk, pak); + if (ret != 0) { + throw new RuntimeException("生成非对称密钥 " + String.format("0x%02X", ret)); + } + + byte[] sign = new byte[512]; + ret = SDFJna.INSTANCE.SDF_ExternalSign_ECC( + phSessionHandle.getValue(), + AlgorithmEnum.SGD_SM2.getValue(), pak, hash, hash.length, sign + ); + if (ret != 0) { + throw new RuntimeException("ExternalSign_ECC " + String.format("0x%02X", ret)); + } + + // 验签 + ret = SDFJna.INSTANCE.SDF_ExternalVerify_ECC(phSessionHandle.getValue(), AlgorithmEnum.SGD_SM2.getValue(), puk, hash, hash.length, sign); + if (ret != 0) { + throw new RuntimeException("ExternalSign_ECC " + String.format("0x%02X", ret)); + } + } + + + /** + * 非对称 加密解密 + * 外部密钥 + */ + @Test + public void asym_en(){ + + byte[] puk = new byte[256]; + byte[] pak = new byte[256]; + int ret = SDFJna.INSTANCE.SDF_GenerateKeyPair_ECC(phSessionHandle.getValue(), AlgorithmEnum.SGD_SM2.getValue(), 256, puk, pak); + if (ret != 0) { + throw new RuntimeException("生成非对称密钥 " + String.format("0x%02X", ret)); + } + + + System.out.println( "ret= " + ret); + System.out.println( "puk= " + ByteUtil.bytes2HexString( puk )); + System.out.println( "pak= " + ByteUtil.bytes2HexString( pak )); + + + + byte[] enc = new byte[512]; + ret = SDFJna.INSTANCE.SDF_ExternalEncrypt_ECC( + phSessionHandle.getValue(), + AlgorithmEnum.SGD_SM2.getValue(), + puk, + data, data.length, enc + ); + if (ret != 0) { + throw new RuntimeException("ExternalEncrypt_ECC " + String.format("0x%02X", ret)); + } + + byte[] buffer = new byte[512]; + IntByReference bufferLen = new IntByReference( buffer.length ); + ret = SDFJna.INSTANCE.SDF_ExternalDecrypt_ECC( + phSessionHandle.getValue(), + AlgorithmEnum.SGD_SM2.getValue(), + pak, + enc, buffer, bufferLen + ); + if (ret != 0) { + throw new RuntimeException("ExternalEncrypt_ECC " + String.format("0x%02X", ret)); + } + } +} \ No newline at end of file