From 63fce073ddb2c0cfe124109f03563a797d70df02 Mon Sep 17 00:00:00 2001 From: liulu Date: Tue, 10 Dec 2024 17:21:17 +0800 Subject: [PATCH] sdf api --- chsm-common/pom.xml | 4 + .../sunyard/chsm/mapper/SpDeviceMapper.java | 3 + .../chsm/model/dto/DeviceCheckRes.java | 3 + .../chsm/sdf/context/DeviceContext.java | 22 -- .../com/sunyard/chsm/service/TmkService.java | 19 +- chsm-web-server/pom.xml | 4 - .../java/com/sunyard/chsm/WebServerApp.java | 6 +- .../com/sunyard/chsm/auth/AppTokenFilter.java | 4 +- .../com/sunyard/chsm/auth/AuthHandler.java | 6 +- .../com/sunyard/chsm/pool/DeviceContext.java | 38 ++++ .../com/sunyard/chsm/pool/DeviceManager.java | 209 ++++++++++++++++++ .../chsm/pool/LoadBalancedSdfApiService.java | 92 ++++++++ .../com/sunyard/chsm/pool/TMKContext.java | 21 ++ .../sunyard/chsm/pool/TMKContextFactory.java | 101 +++++++++ .../src/main/resources/application.yml | 2 +- 15 files changed, 490 insertions(+), 44 deletions(-) delete mode 100644 chsm-common/src/main/java/com/sunyard/chsm/sdf/context/DeviceContext.java create mode 100644 chsm-web-server/src/main/java/com/sunyard/chsm/pool/DeviceContext.java create mode 100644 chsm-web-server/src/main/java/com/sunyard/chsm/pool/DeviceManager.java create mode 100644 chsm-web-server/src/main/java/com/sunyard/chsm/pool/LoadBalancedSdfApiService.java create mode 100644 chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContext.java create mode 100644 chsm-web-server/src/main/java/com/sunyard/chsm/pool/TMKContextFactory.java 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