From 3dc061907f1ab1282d7248f340e056ed60a31f86 Mon Sep 17 00:00:00 2001 From: liulu Date: Wed, 11 Dec 2024 11:49:40 +0800 Subject: [PATCH] sdf api --- .../java/com/sunyard/chsm/enums/Padding.java | 1 + .../com/sunyard/chsm/sdf/BCSdfApiService.java | 17 +++++- .../com/sunyard/chsm/sdf/SdfApiService.java | 30 ++++++---- .../chsm/sdf/adapter/BcSdfApiAdaptor.java | 16 ++++- .../chsm/sdf/adapter/JnaSdfAdaptor.java | 49 ++++++++++++++- .../chsm/sdf/adapter/SdfApiAdapter.java | 16 ++--- .../sdf/adapter/SdfApiAdapterFactory.java | 7 ++- .../com/sunyard/chsm/sdf/lib/SdfLibrary.java | 2 +- .../com/sunyard/chsm/sdf/model/EccPriKey.java | 16 +++++ .../sunyard/chsm/sdf/util/PaddingUtil.java | 2 +- .../com/sunyard/chsm/service/TmkService.java | 4 +- .../sunyard/chsm/service/DeviceService.java | 2 + .../chsm/service/impl/DeviceServiceImpl.java | 34 +++++++++++ .../com/sunyard/chsm/task/DeviceTask.java | 54 ++--------------- .../com/sunyard/chsm/pool/DeviceManager.java | 60 +++++++++++++++---- .../chsm/pool/LoadBalancedSdfApiService.java | 49 ++++++++++++--- .../com/sunyard/chsm/pool/TMKContext.java | 8 ++- .../sunyard/chsm/pool/TMKContextFactory.java | 1 + 18 files changed, 264 insertions(+), 104 deletions(-) diff --git a/chsm-common/src/main/java/com/sunyard/chsm/enums/Padding.java b/chsm-common/src/main/java/com/sunyard/chsm/enums/Padding.java index dd058bb..b5788fd 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/enums/Padding.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/enums/Padding.java @@ -15,6 +15,7 @@ import java.util.Objects; public enum Padding { NOPadding("NoPadding", "NoPadding"), PCKS5Padding( "PKCS5Padding", "PKCS5Padding"), + PCKS7Padding( "PKCS7Padding", "PKCS7Padding"), ; private final String code; diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/BCSdfApiService.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/BCSdfApiService.java index efa11c2..31075e1 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/BCSdfApiService.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/BCSdfApiService.java @@ -5,6 +5,7 @@ import com.sunyard.chsm.enums.AlgMode; import com.sunyard.chsm.enums.KeyAlg; import com.sunyard.chsm.enums.KeyCategory; import com.sunyard.chsm.enums.Padding; +import com.sunyard.chsm.sdf.context.AlgId; import com.sunyard.chsm.sdf.model.EccKey; import com.sunyard.chsm.sdf.util.LangUtils; import com.sunyard.chsm.utils.gm.BCSM2Utils; @@ -21,7 +22,11 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; -import java.security.*; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; /** @@ -86,12 +91,22 @@ public class BCSdfApiService extends AbstractSdfApiService { return symCalc(Cipher.ENCRYPT_MODE, alg, mode, padding, key, data); } + @Override + public byte[] symEncrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) { + return new byte[0]; + } + @Override public byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { return symCalc(Cipher.DECRYPT_MODE, alg, mode, padding, key, data); } + @Override + public byte[] symDecrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) { + return new byte[0]; + } + /** * 对称加解密的统一实现 diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/SdfApiService.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/SdfApiService.java index a7a4ad1..840addf 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/SdfApiService.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/SdfApiService.java @@ -4,6 +4,7 @@ package com.sunyard.chsm.sdf; import com.sunyard.chsm.enums.AlgMode; import com.sunyard.chsm.enums.KeyAlg; import com.sunyard.chsm.enums.Padding; +import com.sunyard.chsm.sdf.context.AlgId; import com.sunyard.chsm.sdf.model.EccKey; @@ -23,41 +24,48 @@ public interface SdfApiService { byte[] generateRandom(int len); - /** * 生成对称密钥 - * @param alg 算法,只支持对称算法 + * + * @param alg 算法,只支持对称算法 * @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。 * 禁止传 null * @return 对称密钥 */ byte[] genSymKey(KeyAlg alg, Integer keyLen); + byte[] genSymKey(KeyAlg alg); /** * 对称加密 - * @param alg 算法,只支持对称算法 - * @param mode 轮模式 + * + * @param alg 算法,只支持对称算法 + * @param mode 轮模式 * @param padding 填充模式 - * @param key 密钥值,明文 - * @param data 原始数据 + * @param key 密钥值,明文 + * @param data 原始数据 */ byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data); + byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data); + byte[] symEncrypt(AlgId alg, byte[] key, byte[] iv, byte[] data); + /** * 对称解密 - * @param alg 算法,只支持对称算法 - * @param key 密钥值,明文 - * @param mode 轮模式 + * + * @param alg 算法,只支持对称算法 + * @param key 密钥值,明文 + * @param mode 轮模式 * @param padding 填充模式 - * @param data 密文数据 + * @param data 密文数据 */ byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data); + byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data); - + byte[] symDecrypt(AlgId alg, byte[] key, byte[] iv, byte[] data); /** diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java index 7ce8b1a..ea7e90d 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java @@ -98,7 +98,7 @@ public class BcSdfApiAdaptor implements SdfApiAdapter { @SneakyThrows @Override - public EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits) { + public EccKey generateKeyPairECC(String sessionHandle, AlgId alg) { // 生成密钥对 KeyPair keyPair = BCSM2Utils.generateKeyPair(); BCECPublicKey pubKey = (BCECPublicKey) keyPair.getPublic(); @@ -171,9 +171,14 @@ public class BcSdfApiAdaptor implements SdfApiAdapter { @Override - @SneakyThrows public byte[] symEncrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucData) { byte[] symKey = getSymKey(keyHandle); + return externalSymEncrypt(sessionHandle, symKey, alg, pucIv, pucData); + } + + @Override + @SneakyThrows + public byte[] externalSymEncrypt(String sessionHandle, byte[] symKey, AlgId alg, byte[] pucIv, byte[] pucData) { switch (alg) { case SGD_SM4_ECB: return BCSM4Utils.encrypt_ECB_NoPadding(symKey, pucData); @@ -185,9 +190,14 @@ public class BcSdfApiAdaptor implements SdfApiAdapter { } @Override - @SneakyThrows public byte[] symDecrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucEncData) { byte[] symKey = getSymKey(keyHandle); + return externalSymDecrypt(sessionHandle, symKey, alg, pucIv, pucEncData); + } + + @Override + @SneakyThrows + public byte[] externalSymDecrypt(String sessionHandle, byte[] symKey, AlgId alg, byte[] pucIv, byte[] pucEncData) { switch (alg) { case SGD_SM4_ECB: return BCSM4Utils.decrypt_ECB_NoPadding(symKey, pucEncData); diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java index 94a8569..f21e761 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java @@ -8,6 +8,7 @@ import com.sunyard.chsm.sdf.lib.SdfLibrary; import com.sunyard.chsm.sdf.model.DeviceInfo; import com.sunyard.chsm.sdf.model.EccCipher; import com.sunyard.chsm.sdf.model.EccKey; +import com.sunyard.chsm.sdf.model.EccPriKey; import com.sunyard.chsm.sdf.model.EccPubKey; import com.sunyard.chsm.sdf.model.SDF_DeviceInfo; import com.sunyard.chsm.sdf.util.LangUtils; @@ -129,8 +130,13 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter { } @Override - public EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits) { - return null; + public EccKey generateKeyPairECC(String sessionHandle, AlgId alg) { + byte[] sdfPubKey = new byte[132]; + byte[] sdfPriKey = new byte[68]; + + Pointer hSessionHandle = getSessionHandle(sessionHandle); + sdfLibrary.SDF_GenerateKeyPair_ECC(hSessionHandle, getAlgId(alg), 256, sdfPubKey, sdfPriKey); + return new EccKey(EccPubKey.fromBytes(sdfPubKey).getPubKeyBytes(), EccPriKey.fromBytes(sdfPriKey).getD()); } @Override @@ -200,6 +206,25 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter { return pucEncData; } + @Override + public byte[] externalSymEncrypt(String sessionHandle, byte[] symKey, AlgId alg, byte[] pucIv, byte[] pucData) { + int uiDataLength = pucData.length; + byte[] pucEncData = new byte[uiDataLength]; + Pointer hSessionHandle = getSessionHandle(sessionHandle); + int length = symKey.length; + PointerByReference phKeyHandle = new PointerByReference(); + // 先导入密钥 + sdfLibrary.SDF_ImportKey(hSessionHandle, symKey, length, phKeyHandle); + //加密 + Pointer hKeyHandle = phKeyHandle.getValue(); + IntByReference puiLength = new IntByReference(); + sdfLibrary.SDF_Encrypt(hSessionHandle, hKeyHandle, getAlgId(alg), + pucIv, pucData, uiDataLength, pucEncData, puiLength); + // 使用后销毁密钥 + sdfLibrary.SDF_DestroyKey(hSessionHandle, hKeyHandle); + return pucEncData; + } + @Override public byte[] symDecrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucEncData) { Pointer hSessionHandle = getSessionHandle(sessionHandle); @@ -212,4 +237,24 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter { pucIv, pucEncData, uiEncDataLength, pucData, puiLength); return pucData; } + + @Override + public byte[] externalSymDecrypt(String sessionHandle, byte[] symKey, AlgId alg, byte[] pucIv, byte[] pucEncData) { + int uiEncDataLength = pucEncData.length; + byte[] pucData = new byte[uiEncDataLength]; + + PointerByReference phKeyHandle = new PointerByReference(); + Pointer hSessionHandle = getSessionHandle(sessionHandle); + int length = symKey.length; + // 导入会话密钥 + sdfLibrary.SDF_ImportKey(hSessionHandle, symKey, length, phKeyHandle); + // 解密 + Pointer hKeyHandle = phKeyHandle.getValue(); + IntByReference puiLength = new IntByReference(); + sdfLibrary.SDF_Decrypt(hSessionHandle, hKeyHandle, getAlgId(alg), + pucIv, pucEncData, uiEncDataLength, pucData, puiLength); + // 销毁会话密钥 + sdfLibrary.SDF_DestroyKey(hSessionHandle, hKeyHandle); + return pucData; + } } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java index 4ab5ee4..c17c2f0 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java @@ -51,7 +51,7 @@ public interface SdfApiAdapter { * @return pucRandom 返回随机数 */ byte[] generateRandom(String sessionHandle, int uiLength); - + /** * 导出ECC加密公钥 * @@ -61,13 +61,12 @@ public interface SdfApiAdapter { EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex); /** - * 产生ECC密钥对并输出 + * 产生ECC密钥对并输出 密钥模长 256 * * @param alg 指定算法标识 SGD_SM2_1 - * @param uiKeyBits 指定密钥模长 * @return pucPublicKeyEcc 返回公钥 | pucPrivateKeyEcc 返回私钥 */ - EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits); + EccKey generateKeyPairECC(String sessionHandle, AlgId alg); boolean getPrivateKeyAccessRight(String hSessionHandle, int uiKeyIndex, byte[] pucPassword); @@ -75,7 +74,7 @@ public interface SdfApiAdapter { * 导入会话密钥并用内部ECC私钥解密 * * @param uiIskIndex 密码设备内部存储加密私钥的索引值,对应于加密时的公钥 - * @param eccCipher 缓冲区指针,用于存放返回的密钥密文 + * @param eccCipher 缓冲区指针,用于存放返回的密钥密文 * @return phKeyHandle 返回密钥句柄 */ String importKeyWithISKECC(String sessionHandle, int uiIskIndex, EccCipher eccCipher); @@ -103,8 +102,8 @@ public interface SdfApiAdapter { /** * 外部密钥ECC公钥加密 * - * @param pubKey 外部ECC公钥结构 - * @param pucData 缓冲区指针,用于存放外部输入的数据 + * @param pubKey 外部ECC公钥结构 + * @param pucData 缓冲区指针,用于存放外部输入的数据 * @return pucEncData 返回数据密文 */ EccCipher externalEncryptECC(String sessionHandle, EccPubKey pubKey, byte[] pucData); @@ -121,6 +120,8 @@ public interface SdfApiAdapter { */ byte[] symEncrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucData); + byte[] externalSymEncrypt(String sessionHandle, byte[] symKey, AlgId alg, byte[] pucIv, byte[] pucData); + /** * 对称解密 * @@ -133,4 +134,5 @@ public interface SdfApiAdapter { */ byte[] symDecrypt(String sessionHandle, String keyHandle, AlgId alg, byte[] pucIv, byte[] pucEncData); + byte[] externalSymDecrypt(String sessionHandle, byte[] symKey, AlgId alg, byte[] pucIv, byte[] pucEncData); } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapterFactory.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapterFactory.java index 4e4cd67..f95097d 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapterFactory.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapterFactory.java @@ -13,6 +13,10 @@ import java.util.Objects; public class SdfApiAdapterFactory { + public static SdfApiAdapter getBcAdapter() { + return BcSdfApiAdaptor.INSTANCE; + } + public static SdfApiAdapter newInstance(String model, String ip, Integer port) { Assert.hasText(model, "设备型号不能为空"); @@ -31,7 +35,4 @@ public class SdfApiAdapterFactory { } - - - } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/lib/SdfLibrary.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/lib/SdfLibrary.java index e89fcc9..88d1a05 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/lib/SdfLibrary.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/lib/SdfLibrary.java @@ -221,7 +221,7 @@ public interface SdfLibrary extends Library { * @param phKeyhandle * @return */ - int SDF_DestroyKey(Pointer phSessionHandle, PointerByReference phKeyhandle); + int SDF_DestroyKey(Pointer phSessionHandle, Pointer phKeyhandle); /** diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccPriKey.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccPriKey.java index 31d0f81..78c94b3 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccPriKey.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccPriKey.java @@ -3,6 +3,10 @@ package com.sunyard.chsm.sdf.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.springframework.util.Assert; + +import java.util.Arrays; +import java.util.Objects; /** * @author liulu @@ -18,5 +22,17 @@ public class EccPriKey { // 私 钥 private byte[] D; + public static EccPriKey fromBytes(byte[] priKey) { + Assert.notNull(priKey, "公钥数据不能为null"); + if (Objects.equals(priKey.length, 132)) { + // 00010000 + priKey = Arrays.copyOfRange(priKey, 4, priKey.length); + } + Assert.isTrue(Objects.equals(priKey.length, 32) || Objects.equals(priKey.length, 64), "Ecc私钥数据格式错误"); + if (Objects.equals(priKey.length, 32)) { + return new EccPriKey(256, priKey); + } + return new EccPriKey(256, Arrays.copyOfRange(priKey, 32, 64)); + } } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/util/PaddingUtil.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/util/PaddingUtil.java index 5aaa532..7a71309 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/util/PaddingUtil.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/util/PaddingUtil.java @@ -30,7 +30,7 @@ public abstract class PaddingUtil { } } - public static byte[] PKCS5Padding(byte[] content) throws Exception { + public static byte[] PKCS5Padding(byte[] content) { return PKCS7Padding(content, 8); } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/service/TmkService.java b/chsm-common/src/main/java/com/sunyard/chsm/service/TmkService.java index 43ed7d4..0212f69 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/service/TmkService.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/service/TmkService.java @@ -187,7 +187,7 @@ public class TmkService { log.warn("data error, no tmk found in system"); return; } - SdfApiAdapter softAdapter = SdfApiAdapterFactory.newInstance(BouncyCastleProvider.PROVIDER_NAME, "", 0); + SdfApiAdapter softAdapter = SdfApiAdapterFactory.getBcAdapter(); EccPubKey pubKey = softAdapter.exportEncPublicKeyECC("", 1); SdfApiAdapter tmkAdapter = SdfApiAdapterFactory.newInstance(device.getManufacturerModel(), device.getServiceIp(), device.getServicePort()); @@ -244,7 +244,7 @@ public class TmkService { } } - private byte[] getSoftDeviceEncTmk() { + public byte[] getSoftDeviceEncTmk() { boolean tmkInit = isTmkInit(); Assert.isTrue(tmkInit, "主密钥未初始化"); boolean enabled = isEnableSoftDevice(); diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/DeviceService.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/DeviceService.java index 543fb27..d448cd3 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/DeviceService.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/DeviceService.java @@ -22,4 +22,6 @@ public interface DeviceService { void delete(Long id); + void checkDeviceStatus(); + } diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java index d8681ce..2f2ea12 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.sunyard.chsm.dto.DeviceDTO; +import com.sunyard.chsm.enums.DeviceTmkStatus; import com.sunyard.chsm.enums.ManufacturerEnum; import com.sunyard.chsm.enums.ManufacturerModelEnum; import com.sunyard.chsm.mapper.SpDeviceMapper; @@ -203,4 +204,37 @@ public class DeviceServiceImpl implements DeviceService { Assert.isNull(exist, "设备名称已存在"); } + @Override + public void checkDeviceStatus() { + + for (int i = 1; i < 500; i++) { + Page devicePage = spDeviceMapper.selectPage( + new Page<>(i, 20L), + new LambdaQueryWrapper().orderByAsc(Device::getId) + ); + List records = devicePage.getRecords(); + if (CollectionUtils.isEmpty(records)) { + break; + } + for (Device record : records) { + DeviceCheckRes checkRes = tmkService.checkDevice(record); + Device up = new Device(); + up.setId(record.getId()); + up.setConnected(checkRes.getStatus() != DeviceTmkStatus.device_error); + LocalDateTime now = LocalDateTime.now(); + if (up.getConnected()) { + up.setLastConnectedTime(now); + } + up.setLastCheckTime(now); + + up.setTmkStatus(checkRes.getStatus().name()); + up.setDeviceSerial(checkRes.getDeviceSerial()); + if (!Objects.equals(checkRes.getPubKey(), record.getPubKey())) { + up.setPubKey(checkRes.getPubKey()); + } + up.setEncTmk(checkRes.getEncTmk()); + spDeviceMapper.updateById(up); + } + } + } } diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/task/DeviceTask.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/task/DeviceTask.java index 3f6fd32..77bb3aa 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/task/DeviceTask.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/task/DeviceTask.java @@ -1,25 +1,15 @@ package com.sunyard.chsm.task; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.sun.jna.Platform; -import com.sunyard.chsm.enums.DeviceTmkStatus; -import com.sunyard.chsm.mapper.SpDeviceMapper; -import com.sunyard.chsm.model.dto.DeviceCheckRes; -import com.sunyard.chsm.model.entity.Device; +import com.sunyard.chsm.service.DeviceService; import com.sunyard.chsm.service.TmkService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.InitializingBean; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.time.Duration; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Objects; /** * @author liulu @@ -29,53 +19,17 @@ import java.util.Objects; @Component public class DeviceTask implements InitializingBean { - @Resource - private SpDeviceMapper spDeviceMapper; @Resource private TmkService tmkService; @Resource - private ThreadPoolTaskScheduler threadPoolTaskScheduler; + private DeviceService deviceService; @Resource - private ThreadPoolTaskExecutor threadPoolTaskExecutor; - - - private void checkDeviceStatus() { - - for (int i = 1; i < 500; i++) { - Page devicePage = spDeviceMapper.selectPage( - new Page<>(i, 20L), - new LambdaQueryWrapper().orderByAsc(Device::getId) - ); - List records = devicePage.getRecords(); - if (CollectionUtils.isEmpty(records)) { - break; - } - for (Device record : records) { - DeviceCheckRes checkRes = tmkService.checkDevice(record); - Device up = new Device(); - up.setId(record.getId()); - up.setConnected(checkRes.getStatus() != DeviceTmkStatus.device_error); - LocalDateTime now = LocalDateTime.now(); - if (up.getConnected()) { - up.setLastConnectedTime(now); - } - up.setLastCheckTime(now); - - up.setTmkStatus(checkRes.getStatus().name()); - up.setDeviceSerial(checkRes.getDeviceSerial()); - if (!Objects.equals(checkRes.getPubKey(), record.getPubKey())) { - up.setPubKey(checkRes.getPubKey()); - } - up.setEncTmk(checkRes.getEncTmk()); - spDeviceMapper.updateById(up); - } - } - } + private ThreadPoolTaskScheduler threadPoolTaskScheduler; @Override public void afterPropertiesSet() throws Exception { if (Platform.isLinux() || Platform.isWindows()) { - threadPoolTaskScheduler.scheduleWithFixedDelay(this::checkDeviceStatus, Duration.ofMinutes(5L)); + threadPoolTaskScheduler.scheduleWithFixedDelay(deviceService::checkDeviceStatus, Duration.ofMinutes(5L)); threadPoolTaskScheduler.scheduleWithFixedDelay(tmkService::checkSoftDeviceTmk, Duration.ofMinutes(5L)); } else { log.warn("操作系统: {} 不支持启动检查设备状态定时任务", System.getProperty("os.name")); diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/DeviceManager.java b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/DeviceManager.java index c0d4182..8e1c86e 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/DeviceManager.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/DeviceManager.java @@ -9,6 +9,9 @@ import com.sunyard.chsm.mapper.SpDeviceMapper; import com.sunyard.chsm.model.dto.DeviceCheckRes; import com.sunyard.chsm.model.entity.CryptoServiceDeviceGroup; import com.sunyard.chsm.model.entity.Device; +import com.sunyard.chsm.sdf.adapter.SdfApiAdapter; +import com.sunyard.chsm.sdf.adapter.SdfApiAdapterFactory; +import com.sunyard.chsm.sdf.model.EccCipher; import com.sunyard.chsm.service.TmkService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -48,13 +51,22 @@ public class DeviceManager implements ApplicationRunner { private Map> deviceMap = new HashMap<>(); private boolean enableSoftDevice = false; + private TMKContext softContext; private final TmkService tmkService; private final SpDeviceMapper spDeviceMapper; private final CryptoServiceDeviceGroupMapper cryptoServiceDeviceGroupMapper; - private TMKContext chooseOne() { + public void returnContextToPool(TMKContext context) { + Optional.ofNullable(context.getPool()) + .ifPresent(it -> { + context.setPool(null); + it.returnObject(context); + }); + } + + public TMKContext chooseOne() { RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); AppUser user = (AppUser) attributes.getAttribute(SecurityConstant.ATTRIBUTE_APP_USER, RequestAttributes.SCOPE_REQUEST); Assert.notNull(user, "登录用户不能为空"); @@ -71,16 +83,40 @@ public class DeviceManager implements ApplicationRunner { Optional.ofNullable(deviceMap.get(serviceId)) .ifPresent(contexts::addAll); } - DeviceContext device = getNextDevice(contexts, atomicInteger.getAndIncrement()); - - try { - return device.getPool().borrowObject(); - } catch (Exception e) { - - - throw new RuntimeException(e); + TMKContext tmkContext; + if (device == null) { + tmkContext = getSoftContext(); + } else { + try { + GenericObjectPool pool = device.getPool(); + tmkContext = pool.borrowObject(2000); + tmkContext.setPool(pool); + } catch (Exception e) { + tmkContext = getSoftContext(); + } } + Assert.notNull(tmkContext, "应用: " + user.getName() + "没有可用的密码设备"); + return tmkContext; + } + + public synchronized TMKContext getSoftContext() { + if (!enableSoftDevice) { + return null; + } + if (Objects.nonNull(softContext)) { + return softContext; + } + byte[] softEncTmk = tmkService.getSoftDeviceEncTmk(); + if (softEncTmk == null || softEncTmk.length == 0) { + return null; + } + SdfApiAdapter bcAdapter = SdfApiAdapterFactory.getBcAdapter(); + String hk = bcAdapter.importKeyWithISKECC("", 1, EccCipher.fromBytes(softEncTmk)); + softContext = new TMKContext(); + softContext.setSdfApiAdapter(bcAdapter); + softContext.setKeyHandle(hk); + return softContext; } @@ -146,7 +182,7 @@ public class DeviceManager implements ApplicationRunner { .map(DeviceContext::getDeviceSerial) .collect(Collectors.toList()); - List noChanged = old.stream() + List nc = old.stream() .filter(it -> newSerials.contains(it.getDeviceSerial())) .collect(Collectors.toList()); @@ -154,8 +190,8 @@ public class DeviceManager implements ApplicationRunner { .filter(it -> !oldSerials.contains(it.getDeviceSerial())) .collect(Collectors.toList()); - noChanged.addAll(waitSync.stream().map(this::mapToContext).filter(Objects::nonNull).collect(Collectors.toList())); - return noChanged; + nc.addAll(waitSync.stream().map(this::mapToContext).filter(Objects::nonNull).collect(Collectors.toList())); + return nc; }); } diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java index a6e6aa4..272730f 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java @@ -4,10 +4,13 @@ import com.sunyard.chsm.enums.AlgMode; import com.sunyard.chsm.enums.KeyAlg; import com.sunyard.chsm.enums.Padding; import com.sunyard.chsm.sdf.SdfApiService; +import com.sunyard.chsm.sdf.context.AlgId; import com.sunyard.chsm.sdf.model.EccKey; +import com.sunyard.chsm.sdf.util.PaddingUtil; import lombok.extern.slf4j.Slf4j; import javax.annotation.Resource; +import java.util.function.Function; /** * @author liulu @@ -17,32 +20,51 @@ import javax.annotation.Resource; public class LoadBalancedSdfApiService implements SdfApiService { - @Resource private DeviceManager deviceManager; + private T apply(Function fun) { + TMKContext context = deviceManager.chooseOne(); + try { + return fun.apply(context); + } finally { + deviceManager.returnContextToPool(context); + } + } @Override public byte[] generateRandom(int len) { - - - return new byte[0]; + return apply(s -> s.getSdfApiAdapter().generateRandom(s.getSessionHandle(), len)); } @Override public byte[] genSymKey(KeyAlg alg, Integer keyLen) { - return new byte[0]; + return generateRandom(keyLen); } @Override public byte[] genSymKey(KeyAlg alg) { - return new byte[0]; + return generateRandom(16); } @Override public byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { - return new byte[0]; + byte[] paddingData = null; + switch (padding) { + case NOPadding: + paddingData = data; + break; + case PCKS5Padding: + paddingData = PaddingUtil.PKCS5Padding(data); + break; + case PCKS7Padding: + paddingData = PaddingUtil.PKCS7Padding(data); + break; + } + byte[] finalPaddingData = paddingData; + return apply(s -> s.getSdfApiAdapter() + .externalSymEncrypt(s.getSessionHandle(), key, null, null, finalPaddingData)); } @Override @@ -50,6 +72,11 @@ public class LoadBalancedSdfApiService implements SdfApiService { return new byte[0]; } + @Override + public byte[] symEncrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) { + return apply(s -> s.getSdfApiAdapter().externalSymEncrypt(s.getSessionHandle(), key, alg, iv, PaddingUtil.PKCS7Padding(data))); + } + @Override public byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) { return new byte[0]; @@ -60,9 +87,15 @@ public class LoadBalancedSdfApiService implements SdfApiService { return new byte[0]; } + @Override + public byte[] symDecrypt(AlgId alg, byte[] key, byte[] iv, byte[] data) { + byte[] decrypt = apply(s -> s.getSdfApiAdapter().externalSymDecrypt(s.getSessionHandle(), key, alg, iv, data)); + return PaddingUtil.PKCS7Unpadding(decrypt); + } + @Override public EccKey genKeyPairEcc() { - return null; + return apply(s -> s.getSdfApiAdapter().generateKeyPairECC(s.getSessionHandle(), AlgId.SGD_SM2_1)); } @Override diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContext.java b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContext.java index 46e0d41..cd06a75 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContext.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContext.java @@ -1,6 +1,8 @@ package com.sunyard.chsm.pool; +import com.sunyard.chsm.sdf.adapter.SdfApiAdapter; import lombok.Data; +import org.apache.commons.pool2.impl.GenericObjectPool; /** * @author liulu @@ -9,13 +11,13 @@ import lombok.Data; @Data public class TMKContext { + private String encTmk; private String deviceHandle; private String sessionHandle; private String keyHandle; - - - + private SdfApiAdapter sdfApiAdapter; + private GenericObjectPool pool; } diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContextFactory.java b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContextFactory.java index 50e761a..03d79bc 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContextFactory.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContextFactory.java @@ -50,6 +50,7 @@ public class TMKContextFactory extends BasePooledObjectFactory { sdfApiAdapter.getPrivateKeyAccessRight(hs, context.getEncKeyIdx(), context.getAccessCredentials().getBytes()); String hk = sdfApiAdapter.importKeyWithISKECC(hs, context.getEncKeyIdx(), EccCipher.fromHex(context.getEncTmk())); keyHandle.setKeyHandle(hk); + keyHandle.setSdfApiAdapter(sdfApiAdapter); log.info("create key handle with isk for {}", context.getIpPort()); return keyHandle; }