diff --git a/chsm-common/pom.xml b/chsm-common/pom.xml
index a92567f..dfc4c1d 100644
--- a/chsm-common/pom.xml
+++ b/chsm-common/pom.xml
@@ -49,6 +49,10 @@
org.apache.commons
commons-lang3
+
+ com.github.ben-manes.caffeine
+ caffeine
+
net.java.dev.jna
jna
diff --git a/chsm-common/src/main/java/com/sunyard/chsm/mapper/SpDeviceMapper.java b/chsm-common/src/main/java/com/sunyard/chsm/mapper/SpDeviceMapper.java
index 4e97a61..7906786 100644
--- a/chsm-common/src/main/java/com/sunyard/chsm/mapper/SpDeviceMapper.java
+++ b/chsm-common/src/main/java/com/sunyard/chsm/mapper/SpDeviceMapper.java
@@ -29,4 +29,7 @@ public interface SpDeviceMapper extends BaseMapper {
};
+
+
+
}
diff --git a/chsm-common/src/main/java/com/sunyard/chsm/model/dto/DeviceCheckRes.java b/chsm-common/src/main/java/com/sunyard/chsm/model/dto/DeviceCheckRes.java
index c5b76d4..dfe5f10 100644
--- a/chsm-common/src/main/java/com/sunyard/chsm/model/dto/DeviceCheckRes.java
+++ b/chsm-common/src/main/java/com/sunyard/chsm/model/dto/DeviceCheckRes.java
@@ -1,6 +1,7 @@
package com.sunyard.chsm.model.dto;
import com.sunyard.chsm.enums.DeviceTmkStatus;
+import com.sunyard.chsm.sdf.adapter.SdfApiAdapter;
import lombok.Data;
/**
@@ -17,5 +18,7 @@ public class DeviceCheckRes {
private boolean hasError = false;
private String message;
+ private SdfApiAdapter sdfApiAdapter;
+
}
diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/context/DeviceContext.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/context/DeviceContext.java
deleted file mode 100644
index d133840..0000000
--- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/context/DeviceContext.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.sunyard.chsm.sdf.context;
-
-import lombok.Data;
-
-/**
- * @author liulu
- * @since 2024/11/5
- */
-@Data
-public class DeviceContext {
-
- private String serviceIp;
- private Integer servicePort;
- private String manufacturer;
- private String manufacturerModel;
- private String accessCredentials;
- private String jnaLibName;
-
- private Integer weight;
-
-
-}
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 4e3c3f6..43ed7d4 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
@@ -167,13 +167,14 @@ public class TmkService {
}
Optional.ofNullable(hs).ifPresent(sdfApi::closeSession);
Optional.ofNullable(hd).ifPresent(sdfApi::closeDevice);
+ res.setSdfApiAdapter(sdfApi);
log.debug("==========> end check device : {}", res);
return res;
}
public void checkSoftDeviceTmk() {
- if (!isTmkInit() || !enableSoftDevice()) {
+ if (!isTmkInit() || !isEnableSoftDevice()) {
return;
}
byte[] softTmk = getSoftDeviceEncTmk();
@@ -203,7 +204,7 @@ public class TmkService {
if (Objects.nonNull(device)) {
return device;
}
- if (enableSoftDevice()) {
+ if (isEnableSoftDevice()) {
device = new Device();
device.setManufacturerModel(BouncyCastleProvider.PROVIDER_NAME);
device.setEncKeyIdx(1);
@@ -219,11 +220,16 @@ public class TmkService {
return null;
}
- private boolean isTmkInit() {
+ public boolean isTmkInit() {
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_INIT);
return conf != null && String.valueOf(true).equals(conf.getValue());
}
+ public boolean isEnableSoftDevice() {
+ ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.ENABLE_SOFT_DEVICE);
+ return conf != null && String.valueOf(true).equals(conf.getValue());
+ }
+
private void updateTmkInit(boolean value) {
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_INIT);
if (conf == null) {
@@ -238,15 +244,10 @@ public class TmkService {
}
}
- private boolean enableSoftDevice() {
- ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.ENABLE_SOFT_DEVICE);
- return conf != null && String.valueOf(true).equals(conf.getValue());
- }
-
private byte[] getSoftDeviceEncTmk() {
boolean tmkInit = isTmkInit();
Assert.isTrue(tmkInit, "主密钥未初始化");
- boolean enabled = enableSoftDevice();
+ boolean enabled = isEnableSoftDevice();
Assert.isTrue(enabled, "未启用软设备");
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.SOFT_ENC_TMK);
if (conf == null || ObjectUtils.isEmpty(conf.getValue())) {
diff --git a/chsm-web-server/pom.xml b/chsm-web-server/pom.xml
index 20d13af..bbd7030 100644
--- a/chsm-web-server/pom.xml
+++ b/chsm-web-server/pom.xml
@@ -54,10 +54,6 @@
io.jsonwebtoken
jjwt
-
- com.github.ben-manes.caffeine
- caffeine
-
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/WebServerApp.java b/chsm-web-server/src/main/java/com/sunyard/chsm/WebServerApp.java
index 902c04b..a0e6d11 100644
--- a/chsm-web-server/src/main/java/com/sunyard/chsm/WebServerApp.java
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/WebServerApp.java
@@ -1,6 +1,7 @@
package com.sunyard.chsm;
import lombok.extern.slf4j.Slf4j;
+import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -10,14 +11,11 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
*/
@Slf4j
@SpringBootApplication
+@MapperScan({"com.sunyard.chsm.**.mapper"})
public class WebServerApp {
public static void main(String[] args) {
-
-
-
-
SpringApplication.run(WebServerApp.class, args);
log.info("---------------------WebServerApp 启动完成-------------------");
}
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppTokenFilter.java b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppTokenFilter.java
index 5453057..c096aa3 100644
--- a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppTokenFilter.java
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppTokenFilter.java
@@ -69,9 +69,9 @@ public class AppTokenFilter extends OncePerRequestFilter {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getOutputStream().write(JsonUtils.toJsonBytes(R.error("token格式错误")));
} catch (Exception ex) {
- log.error("未知异常: {}", requestURI, ex);
+ log.error("系统异常: {}", requestURI, ex);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
- response.getOutputStream().write(JsonUtils.toJsonBytes(R.error("发生异常")));
+ response.getOutputStream().write(JsonUtils.toJsonBytes(R.error("系统异常")));
}
}
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java
index c8d4b4d..0ed9f13 100644
--- a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java
@@ -34,7 +34,7 @@ import static com.sunyard.chsm.constant.SecurityConstant.ATTRIBUTE_APP_USER;
@Component
public class AuthHandler implements HandlerInterceptor, InitializingBean {
- Cache>> cache = null;
+ private Cache>> cache = null;
/**
* token 过期时间, 分钟
@@ -45,7 +45,6 @@ public class AuthHandler implements HandlerInterceptor, InitializingBean {
@Resource
private CryptoServiceApiMapper cryptoServiceApiMapper;
-
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
@@ -58,6 +57,7 @@ public class AuthHandler implements HandlerInterceptor, InitializingBean {
HandlerMethod handlerMethod = (HandlerMethod) handler;
AuthCode authCode = handlerMethod.getMethodAnnotation(AuthCode.class);
if (authCode == null || ObjectUtils.isEmpty(authCode.value())) {
+ request.setAttribute("used_service_ids", user.getServiceIds());
return true;
}
@@ -73,6 +73,7 @@ public class AuthHandler implements HandlerInterceptor, InitializingBean {
response.getOutputStream().write(JsonUtils.toJsonBytes(R.error("无权访问")));
return false;
}
+ request.setAttribute("used_service_ids", codeServiceMap.get(code));
return true;
}
@@ -80,6 +81,7 @@ public class AuthHandler implements HandlerInterceptor, InitializingBean {
public void afterPropertiesSet() throws Exception {
cache = Caffeine.newBuilder()
.expireAfterWrite(Duration.ofMinutes(tokenExpireTime))
+ .maximumSize(400L)
.build();
}
}
diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/pool/DeviceContext.java b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/DeviceContext.java
new file mode 100644
index 0000000..885ec88
--- /dev/null
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/DeviceContext.java
@@ -0,0 +1,38 @@
+package com.sunyard.chsm.pool;
+
+import com.sunyard.chsm.sdf.adapter.SdfApiAdapter;
+import lombok.Data;
+import org.apache.commons.pool2.impl.GenericObjectPool;
+
+/**
+ * @author liulu
+ * @since 2024/11/5
+ */
+@Data
+public class DeviceContext {
+
+ private String ip;
+ private Integer port;
+ private String manufacturer;
+ private String model;
+ private Integer encKeyIdx;
+ private String accessCredentials;
+ private String jnaLibName;
+ private String deviceSerial;
+ private String pubKey;
+ private String encTmk;
+ private Integer weight;
+
+ private SdfApiAdapter sdfApiAdapter;
+ private GenericObjectPool pool;
+
+
+ public String getUnionId() {
+ return String.join("-", deviceSerial, pubKey);
+ }
+
+ public String getIpPort() {
+ return String.join("-", ip, String.valueOf(port));
+ }
+
+}
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
new file mode 100644
index 0000000..c0d4182
--- /dev/null
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/DeviceManager.java
@@ -0,0 +1,209 @@
+package com.sunyard.chsm.pool;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.sunyard.chsm.auth.AppUser;
+import com.sunyard.chsm.constant.SecurityConstant;
+import com.sunyard.chsm.enums.DeviceTmkStatus;
+import com.sunyard.chsm.mapper.CryptoServiceDeviceGroupMapper;
+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.service.TmkService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.pool2.impl.GenericObjectPool;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+/**
+ * @author liulu
+ * @since 2024/12/10
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class DeviceManager implements ApplicationRunner {
+
+ private static final Map ROUND_MAP = new HashMap<>();
+
+ private Map> deviceMap = new HashMap<>();
+
+ private boolean enableSoftDevice = false;
+
+ private final TmkService tmkService;
+ private final SpDeviceMapper spDeviceMapper;
+ private final CryptoServiceDeviceGroupMapper cryptoServiceDeviceGroupMapper;
+
+
+ private TMKContext chooseOne() {
+ RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
+ AppUser user = (AppUser) attributes.getAttribute(SecurityConstant.ATTRIBUTE_APP_USER, RequestAttributes.SCOPE_REQUEST);
+ Assert.notNull(user, "登录用户不能为空");
+ //noinspection unchecked
+ List serviceIds = (List) attributes.getAttribute("used_service_ids", RequestAttributes.SCOPE_REQUEST);
+ Assert.isTrue(!CollectionUtils.isEmpty(serviceIds), "应用: " + user.getName() + "没有可用服务");
+
+ AtomicInteger atomicInteger = ROUND_MAP.computeIfAbsent(user.getAppId(), k -> new AtomicInteger(1));
+ if (atomicInteger.get() > Integer.MAX_VALUE - 10000) {
+ atomicInteger.set(1);
+ }
+ List contexts = new ArrayList<>();
+ for (Long serviceId : serviceIds) {
+ 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);
+ }
+ }
+
+
+ public static DeviceContext getNextDevice(List devices, int totalCalls) {
+ if (devices == null || devices.isEmpty()) {
+ return null;
+ }
+
+ int totalWeight = 0;
+ for (DeviceContext device : devices) {
+ totalWeight += device.getWeight();
+ }
+ int index = totalCalls % totalWeight;
+
+ for (DeviceContext device : devices) {
+ if (index < device.getWeight()) {
+ return device;
+ }
+ index -= device.getWeight();
+ }
+
+ return null; // 理论上不会到这里
+ }
+
+
+ private void syncDevice() {
+ log.debug(">>>>>>>>>>>>>>> start sync device <<<<<<<<<<<<<<<");
+ enableSoftDevice = tmkService.isEnableSoftDevice();
+
+ List devices = spDeviceMapper.selectList(
+ new LambdaQueryWrapper()
+ .eq(Device::getTmkStatus, DeviceTmkStatus.finished)
+ .gt(Device::getGroupId, 0)
+ );
+ if (CollectionUtils.isEmpty(devices)) {
+ log.info("no device for sync ...");
+ deviceMap.clear();
+ return;
+ }
+ Map> groupDeviceMap = devices.stream().collect(Collectors.groupingBy(Device::getGroupId));
+ List serviceDeviceGroups = cryptoServiceDeviceGroupMapper
+ .selectList(new LambdaQueryWrapper()
+ .in(CryptoServiceDeviceGroup::getDeviceGroupId, groupDeviceMap.keySet()));
+ if (CollectionUtils.isEmpty(serviceDeviceGroups)) {
+ deviceMap.clear();
+ return;
+ }
+ Map> waitSyncMap = serviceDeviceGroups.stream()
+ .collect(Collectors.toMap(CryptoServiceDeviceGroup::getServiceId,
+ it -> groupDeviceMap.get(it.getDeviceGroupId())));
+
+ for (Map.Entry> entry : waitSyncMap.entrySet()) {
+
+ deviceMap.compute(entry.getKey(), (k, old) -> {
+ if (CollectionUtils.isEmpty(old)) {
+ return entry.getValue().stream().map(this::mapToContext).filter(Objects::nonNull).collect(Collectors.toList());
+ }
+ List newSerials = entry.getValue().stream()
+ .map(Device::getDeviceSerial)
+ .collect(Collectors.toList());
+
+ List oldSerials = old.stream()
+ .map(DeviceContext::getDeviceSerial)
+ .collect(Collectors.toList());
+
+ List noChanged = old.stream()
+ .filter(it -> newSerials.contains(it.getDeviceSerial()))
+ .collect(Collectors.toList());
+
+ List waitSync = entry.getValue().stream()
+ .filter(it -> !oldSerials.contains(it.getDeviceSerial()))
+ .collect(Collectors.toList());
+
+ noChanged.addAll(waitSync.stream().map(this::mapToContext).filter(Objects::nonNull).collect(Collectors.toList()));
+ return noChanged;
+ });
+ }
+
+
+ }
+
+ private DeviceContext mapToContext(Device device) {
+ try {
+ Assert.hasText(device.getEncTmk(), "TMK 状态异常");
+ DeviceCheckRes checkRes = tmkService.checkDevice(device);
+ if (!Objects.equals(checkRes.getDeviceSerial(), device.getDeviceSerial())
+ || !Objects.equals(checkRes.getPubKey(), device.getPubKey())) {
+ return null;
+ }
+ DeviceContext context = new DeviceContext();
+ context.setIp(device.getServiceIp());
+ context.setPort(device.getServicePort());
+ context.setModel(device.getManufacturerModel());
+ context.setEncKeyIdx(device.getEncKeyIdx());
+ context.setAccessCredentials(device.getAccessCredentials());
+ context.setDeviceSerial(device.getDeviceSerial());
+ context.setPubKey(device.getPubKey());
+ context.setEncTmk(device.getEncTmk());
+ context.setWeight(device.getWeight());
+
+ context.setSdfApiAdapter(checkRes.getSdfApiAdapter());
+
+ GenericObjectPoolConfig config = new GenericObjectPoolConfig<>();
+ config.setMaxWait(Duration.ofSeconds(5));
+ config.setJmxEnabled(false);
+ config.setMinIdle(2);
+ config.setTimeBetweenEvictionRuns(Duration.ofMinutes(1));
+ config.setTestWhileIdle(true);
+
+ TMKContextFactory tenantTMKContextFactory = new TMKContextFactory(checkRes.getSdfApiAdapter(), context);
+ GenericObjectPool pool = new GenericObjectPool<>(tenantTMKContextFactory, config);
+ context.setPool(pool);
+
+ return context;
+ } catch (Exception ex) {
+ log.warn("device conn error: {}", device, ex);
+ return null;
+ }
+ }
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ Executors.newSingleThreadScheduledExecutor()
+ .scheduleWithFixedDelay(this::syncDevice, 0L, 5L, TimeUnit.MINUTES);
+ }
+}
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
new file mode 100644
index 0000000..a6e6aa4
--- /dev/null
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java
@@ -0,0 +1,92 @@
+package com.sunyard.chsm.pool;
+
+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.model.EccKey;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.annotation.Resource;
+
+/**
+ * @author liulu
+ * @since 2024/12/10
+ */
+@Slf4j
+public class LoadBalancedSdfApiService implements SdfApiService {
+
+
+
+ @Resource
+ private DeviceManager deviceManager;
+
+
+
+ @Override
+ public byte[] generateRandom(int len) {
+
+
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] genSymKey(KeyAlg alg, Integer keyLen) {
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] genSymKey(KeyAlg alg) {
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) {
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data) {
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) {
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data) {
+ return new byte[0];
+ }
+
+ @Override
+ public EccKey genKeyPairEcc() {
+ return null;
+ }
+
+ @Override
+ public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) {
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] hmac(byte[] key, byte[] srcData) {
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] hash(byte[] pucData) {
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] encryptByTMK(byte[] data) {
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] decryptByTMK(byte[] data) {
+ return new byte[0];
+ }
+}
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
new file mode 100644
index 0000000..46e0d41
--- /dev/null
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContext.java
@@ -0,0 +1,21 @@
+package com.sunyard.chsm.pool;
+
+import lombok.Data;
+
+/**
+ * @author liulu
+ * @since 2024/12/10
+ */
+@Data
+public class TMKContext {
+
+ private String encTmk;
+ private String deviceHandle;
+ private String sessionHandle;
+ private String keyHandle;
+
+
+
+
+
+}
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
new file mode 100644
index 0000000..50e761a
--- /dev/null
+++ b/chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContextFactory.java
@@ -0,0 +1,101 @@
+package com.sunyard.chsm.pool;
+
+import com.sunyard.chsm.sdf.adapter.SdfApiAdapter;
+import com.sunyard.chsm.sdf.context.AlgId;
+import com.sunyard.chsm.sdf.model.EccCipher;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.pool2.BasePooledObjectFactory;
+import org.apache.commons.pool2.DestroyMode;
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.impl.DefaultPooledObject;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+import java.util.Arrays;
+
+/**
+ * @author liulu
+ * @since 2024/12/10
+ */
+@Slf4j
+public class TMKContextFactory extends BasePooledObjectFactory {
+
+ private static final byte[] checkData = "1234567812345678".getBytes();
+
+ private final SdfApiAdapter sdfApiAdapter;
+ private final DeviceContext context;
+ private String deviceHandle;
+
+ public TMKContextFactory(SdfApiAdapter sdfApiAdapter, DeviceContext context) {
+ this.sdfApiAdapter = sdfApiAdapter;
+ this.context = context;
+ this.deviceHandle = sdfApiAdapter.openDevice();
+ }
+
+
+ @Override
+ public TMKContext create() throws Exception {
+ TMKContext keyHandle = new TMKContext();
+ String hs;
+ try {
+ hs = sdfApiAdapter.openSession(deviceHandle);
+ } catch (Exception ex) {
+ // 再次尝试,
+ this.deviceHandle = sdfApiAdapter.openDevice();
+ hs = sdfApiAdapter.openSession(deviceHandle);
+ }
+ keyHandle.setSessionHandle(hs);
+ keyHandle.setEncTmk(context.getEncTmk());
+
+ sdfApiAdapter.getPrivateKeyAccessRight(hs, context.getEncKeyIdx(), context.getAccessCredentials().getBytes());
+ String hk = sdfApiAdapter.importKeyWithISKECC(hs, context.getEncKeyIdx(), EccCipher.fromHex(context.getEncTmk()));
+ keyHandle.setKeyHandle(hk);
+ log.info("create key handle with isk for {}", context.getIpPort());
+ return keyHandle;
+ }
+
+ @Override
+ public PooledObject wrap(TMKContext tmkContext) {
+ return new DefaultPooledObject<>(tmkContext);
+ }
+
+
+ @Override
+ public boolean validateObject(PooledObject p) {
+ log.info("开始检查设备{}, session 是否有效", context.getIpPort());
+ TMKContext handle = p.getObject();
+ if (handle == null) {
+ return false;
+ }
+ try {
+ byte[] encData = sdfApiAdapter.symEncrypt(handle.getSessionHandle(),
+ handle.getKeyHandle(), AlgId.SGD_SM4_ECB, new byte[0], checkData);
+ byte[] decData = sdfApiAdapter.symDecrypt(handle.getSessionHandle(),
+ handle.getKeyHandle(), AlgId.SGD_SM4_ECB, new byte[0], encData);
+ Assert.isTrue(Arrays.equals(checkData, decData), "密码机加解密异常");
+ return true;
+ } catch (Exception e) {
+ log.warn("设备{}, validateObject error", context.getIpPort());
+ return false;
+ }
+ }
+
+ @Override
+ public void destroyObject(PooledObject p, DestroyMode destroyMode) throws Exception {
+ TMKContext handle = p.getObject();
+ if (handle == null) {
+ return;
+ }
+ try {
+ String sessionHandle = handle.getSessionHandle();
+ if (StringUtils.hasText(handle.getKeyHandle())) {
+ sdfApiAdapter.destroyKey(sessionHandle, handle.getKeyHandle());
+ }
+ sdfApiAdapter.closeSession(sessionHandle);
+ } catch (Exception ex) {
+ //
+ log.warn("device: {}, {} destroyObject error ", context.getIpPort(), handle.getSessionHandle(), ex);
+ }
+ }
+
+}
diff --git a/chsm-web-server/src/main/resources/application.yml b/chsm-web-server/src/main/resources/application.yml
index a0236b6..32b3fce 100644
--- a/chsm-web-server/src/main/resources/application.yml
+++ b/chsm-web-server/src/main/resources/application.yml
@@ -31,7 +31,7 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
mybatis-plus:
- mapper-locations: classpath*:mapper/**/*Mapper.xml
+ mapper-locations: classpath:mapper/**/*Mapper.xml
# 原生配置
configuration:
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl