sdf api
This commit is contained in:
parent
4febd0520d
commit
63fce073dd
@ -49,6 +49,10 @@
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
|
@ -29,4 +29,7 @@ public interface SpDeviceMapper extends BaseMapper<Device> {
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
||||
}
|
@ -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())) {
|
||||
|
@ -54,10 +54,6 @@
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
@ -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 启动完成-------------------");
|
||||
}
|
||||
|
@ -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("系统异常")));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ import static com.sunyard.chsm.constant.SecurityConstant.ATTRIBUTE_APP_USER;
|
||||
@Component
|
||||
public class AuthHandler implements HandlerInterceptor, InitializingBean {
|
||||
|
||||
Cache<String, Map<String, List<Long>>> cache = null;
|
||||
private Cache<String, Map<String, List<Long>>> 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();
|
||||
}
|
||||
}
|
||||
|
@ -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<TMKContext> pool;
|
||||
|
||||
|
||||
public String getUnionId() {
|
||||
return String.join("-", deviceSerial, pubKey);
|
||||
}
|
||||
|
||||
public String getIpPort() {
|
||||
return String.join("-", ip, String.valueOf(port));
|
||||
}
|
||||
|
||||
}
|
@ -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<Long, AtomicInteger> ROUND_MAP = new HashMap<>();
|
||||
|
||||
private Map<Long, List<DeviceContext>> 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<Long> serviceIds = (List<Long>) 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<DeviceContext> 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<DeviceContext> 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<Device> devices = spDeviceMapper.selectList(
|
||||
new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getTmkStatus, DeviceTmkStatus.finished)
|
||||
.gt(Device::getGroupId, 0)
|
||||
);
|
||||
if (CollectionUtils.isEmpty(devices)) {
|
||||
log.info("no device for sync ...");
|
||||
deviceMap.clear();
|
||||
return;
|
||||
}
|
||||
Map<Long, List<Device>> groupDeviceMap = devices.stream().collect(Collectors.groupingBy(Device::getGroupId));
|
||||
List<CryptoServiceDeviceGroup> serviceDeviceGroups = cryptoServiceDeviceGroupMapper
|
||||
.selectList(new LambdaQueryWrapper<CryptoServiceDeviceGroup>()
|
||||
.in(CryptoServiceDeviceGroup::getDeviceGroupId, groupDeviceMap.keySet()));
|
||||
if (CollectionUtils.isEmpty(serviceDeviceGroups)) {
|
||||
deviceMap.clear();
|
||||
return;
|
||||
}
|
||||
Map<Long, List<Device>> waitSyncMap = serviceDeviceGroups.stream()
|
||||
.collect(Collectors.toMap(CryptoServiceDeviceGroup::getServiceId,
|
||||
it -> groupDeviceMap.get(it.getDeviceGroupId())));
|
||||
|
||||
for (Map.Entry<Long, List<Device>> 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<String> newSerials = entry.getValue().stream()
|
||||
.map(Device::getDeviceSerial)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<String> oldSerials = old.stream()
|
||||
.map(DeviceContext::getDeviceSerial)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<DeviceContext> noChanged = old.stream()
|
||||
.filter(it -> newSerials.contains(it.getDeviceSerial()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<Device> 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<TMKContext> 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<TMKContext> 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);
|
||||
}
|
||||
}
|
@ -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];
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -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<TMKContext> {
|
||||
|
||||
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<TMKContext> wrap(TMKContext tmkContext) {
|
||||
return new DefaultPooledObject<>(tmkContext);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean validateObject(PooledObject<TMKContext> 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<TMKContext> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user