sdf 接口

This commit is contained in:
liulu 2024-11-05 09:46:15 +08:00
parent b13a9f54ac
commit db484a070d
14 changed files with 541 additions and 1 deletions

View File

@ -41,6 +41,14 @@
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
</dependency>
</dependencies>

View File

@ -0,0 +1,16 @@
package com.sunyard.chsm.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sunyard.chsm.model.entity.TmkInfo;
import org.apache.ibatis.annotations.Mapper;
/**
* @author liulu
* @since 2024/10/29
*/
@Mapper
public interface TmkInfoMapper extends BaseMapper<TmkInfo> {
}

View File

@ -23,6 +23,10 @@ public class Device {
private String manufacturerModel;
private String accessCredentials;
private Boolean connected;
private LocalDateTime lastCheckTime;
private LocalDateTime lastConnectedTime;
private Long groupId;
private String groupName;
private Integer weight;

View File

@ -0,0 +1,25 @@
package com.sunyard.chsm.model.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @author liulu
* @since 2024/11/4
*/
@Data
@TableName("sp_tmk_info")
public class TmkInfo {
private Long id;
private String deviceSerial;
private String encTmk;
private String remark;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,109 @@
package com.sunyard.chsm.sdf.adapter;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
import com.sunyard.chsm.sdf.lib.SdfLibrary;
import com.sunyard.chsm.sdf.model.DeviceInfo;
import com.sunyard.chsm.sdf.model.EccKey;
import com.sunyard.chsm.sdf.model.EccPubKey;
import org.springframework.util.Assert;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author liulu
* @since 2024/11/4
*/
public abstract class JnaSdfAdaptor implements SdfApiAdapter {
protected static final Map<String, Pointer> DEVICE_HANDLE_CONTEXT = new ConcurrentHashMap<>();
protected static final Map<String, Pointer> SESSION_HANDLE_CONTEXT = new ConcurrentHashMap<>();
protected static final Map<String, Pointer> KEY_HANDLE_CONTEXT = new ConcurrentHashMap<>();
protected abstract SdfLibrary getSdfLibrary();
protected abstract int getAlgId(String alg);
@Override
public String openDevice() {
PointerByReference phDeviceHandle = new PointerByReference();
getSdfLibrary().SDF_OpenDevice(phDeviceHandle);
String key = UUID.randomUUID().toString();
DEVICE_HANDLE_CONTEXT.put(key, phDeviceHandle.getValue());
return key;
}
@Override
public boolean closeDevice(String deviceHandle) {
Pointer pointer = DEVICE_HANDLE_CONTEXT.remove(deviceHandle);
if (pointer != null) {
int res = getSdfLibrary().SDF_CloseDevice(pointer);
return res == 0;
}
return true;
}
@Override
public String openSession(String deviceHandle) {
Pointer device = getDeviceHandle(deviceHandle);
PointerByReference phSessionHandle = new PointerByReference();
getSdfLibrary().SDF_OpenSession(device, phSessionHandle);
String key = UUID.randomUUID().toString();
SESSION_HANDLE_CONTEXT.put(key, phSessionHandle.getValue());
return key;
}
@Override
public void closeSession(String sessionHandle) {
Pointer pointer = SESSION_HANDLE_CONTEXT.remove(sessionHandle);
if (pointer != null) {
getSdfLibrary().SDF_CloseSession(pointer);
}
}
protected Pointer getDeviceHandle(String deviceHandle) {
Pointer pointer = DEVICE_HANDLE_CONTEXT.get(deviceHandle);
Assert.notNull(pointer, "设备句柄不存在");
return pointer;
}
protected Pointer getSessionHandle(String sessionHandle) {
Pointer pointer = SESSION_HANDLE_CONTEXT.get(sessionHandle);
Assert.notNull(pointer, "会话句柄不存在");
return pointer;
}
protected Pointer getKeyHandle(String keyHandle) {
Pointer pointer = KEY_HANDLE_CONTEXT.get(keyHandle);
Assert.notNull(pointer, "密钥句柄不存在");
return pointer;
}
@Override
public DeviceInfo getDeviceInfo(String sessionHandle) {
return null;
}
@Override
public byte[] generateRandom(String sessionHandle, int uiLength) {
byte[] pucRandom = new byte[uiLength];
Pointer hSessionHandle = getSessionHandle(sessionHandle);
getSdfLibrary().SDF_GenerateRandom(hSessionHandle, uiLength, pucRandom);
return pucRandom;
}
@Override
public EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex) {
return null;
}
@Override
public EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits) {
return null;
}
}

View File

@ -0,0 +1,71 @@
package com.sunyard.chsm.sdf.adapter;
import com.sunyard.chsm.sdf.model.DeviceInfo;
import com.sunyard.chsm.sdf.model.EccKey;
import com.sunyard.chsm.sdf.model.EccPubKey;
/**
* @author liulu
* @since 2024/11/4
*/
public interface SdfApiAdapter {
/**
* 打开设备
*
* @return
*/
String openDevice();
/**
* 关闭设备
*
* @param deviceHandle 已打开的设备句柄
* @return 0 成功; 非0 失败,返回错误代码
*/
boolean closeDevice(String deviceHandle);
/**
* 创建会话
*
* @return 与密码设备建立的新会话句柄
*/
String openSession(String deviceHandle);
void closeSession(String sessionHandle);
/**
* 获取设备信息
*
* @param sessionHandle 与设备建立的会话句柄
* @return 设备能力描述信息内容及格式见设备信息定义
*/
DeviceInfo getDeviceInfo(String sessionHandle);
/**
* 产生随机数
*
* @param uiLength 随机数长度
* @return pucRandom 返回随机数
*/
byte[] generateRandom(String sessionHandle, int uiLength);
/**
* 导出ECC加密公钥
*
* @param uiKeyIndex 密码设备存储的ECC密钥对索引值
* @return pucPublicKeyEcc 返回ECC加密公钥
*/
EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex);
/**
* 产生ECC密钥对并输出
*
* @param alg 指定算法标识 SGD_SM2_1
* @param uiKeyBits 指定密钥模长
* @return pucPublicKeyEcc 返回公钥 | pucPrivateKeyEcc 返回私钥
*/
EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits);
}

View File

@ -0,0 +1,34 @@
package com.sunyard.chsm.sdf.adapter;
import com.sunyard.chsm.enums.ManufacturerModelEnum;
import com.sunyard.chsm.sdf.context.DeviceContext;
import org.springframework.util.Assert;
import java.util.Objects;
/**
* @author liulu
* @since 2024/11/5
*/
public class SdfApiAdapterFactory {
public static SdfApiAdapter newInstance(DeviceContext device) {
Assert.hasText(device.getManufacturerModel(), "设备型号不能为空");
ManufacturerModelEnum model = ManufacturerModelEnum.of(device.getManufacturerModel());
if (Objects.isNull(model)) {
// bc adaptor
return null;
}
switch (model) {
case enc001:
return new SunyardJnaSdfAdaptor(device.getServiceIp(), device.getServicePort());
default:
return null;
}
}
}

View File

@ -0,0 +1,75 @@
package com.sunyard.chsm.sdf.adapter;
import com.sun.jna.Native;
import com.sun.jna.ptr.PointerByReference;
import com.sunyard.chsm.sdf.lib.SdfLibrary;
import com.sunyard.chsm.sdf.lib.SunyardSdfLibrary;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author liulu
* @since 2024/11/4
*/
public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {
private static final Map<String, SunyardSdfLibrary> SDF_LIB_MAP = new ConcurrentHashMap<>();
private final String ip;
private final Integer port;
private final String libName;
private final Integer connTimeout;
private final Integer dealTimeout;
public SunyardJnaSdfAdaptor(String ip, int port) {
this(ip, port, "libsdf");
}
public SunyardJnaSdfAdaptor(String ip, int port, String libName) {
this(ip, port, libName, 3000, 3000);
}
public SunyardJnaSdfAdaptor(String ip, int port, String libName, int connTimeout, int dealTimeout) {
this.ip = ip;
this.port = port;
this.libName = libName;
this.connTimeout = connTimeout;
this.dealTimeout = dealTimeout;
SDF_LIB_MAP.computeIfAbsent(libName, k -> Native.load(libName, SunyardSdfLibrary.class));
}
@Override
public String openDevice() {
SunyardSdfLibrary sdfLibrary = (SunyardSdfLibrary) getSdfLibrary();
PointerByReference phDeviceHandle = new PointerByReference();
sdfLibrary.SDF_OpenDevice(phDeviceHandle, safeStringBytes(ip), port, connTimeout, dealTimeout, 0);
String key = UUID.randomUUID().toString();
DEVICE_HANDLE_CONTEXT.put(key, phDeviceHandle.getValue());
return key;
}
@Override
protected SdfLibrary getSdfLibrary() {
return SDF_LIB_MAP.get(libName);
}
@Override
protected int getAlgId(String alg) {
return 0;
}
public static byte[] safeStringBytes(String str) {
if (null == str || str.isEmpty()) {
return new byte[]{0x30};
}
int len = str.getBytes().length;
byte[] ret = new byte[len + 1];
System.arraycopy(str.getBytes(), 0, ret, 0, len);
return ret;
}
}

View File

@ -0,0 +1,22 @@
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;
}

View File

@ -0,0 +1,66 @@
package com.sunyard.chsm.sdf.lib;
import com.sun.jna.Library;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
/**
* @author liulu
* @since 2024/11/4
*/
public interface SdfLibrary extends Library {
/**
* 打开设备
*
* @param phDeviceHandle 返回设备句柄
* @return 0 成功; 非0 失败,返回错误代码
*/
int SDF_OpenDevice(PointerByReference phDeviceHandle);
/**
* 关闭设备
*
* @param hDeviceHandle 已打开的设备句柄
* @return 0 成功; 非0 失败,返回错误代码
*/
int SDF_CloseDevice(Pointer hDeviceHandle);
/**
* 创建会话
*
* @param hDeviceHandle 已打开的设备句柄
* @param phSessionHandle 返回与密码设备建立的新会话句柄
* @return 0 成功; 非0 失败,返回错误代码
*/
int SDF_OpenSession(Pointer hDeviceHandle, PointerByReference phSessionHandle);
/**
* 关闭会话
*
* @param hSessionHandle 与密码设备已建立的会话句柄
* @return 0 成功; 非0 失败,返回错误代码
*/
int SDF_CloseSession(Pointer hSessionHandle);
/**
* 获取设备信息
*
* @param hSessionHandle 与设备建立的会话句柄
* @param pstDeviceInfo 设备能力描述信息内容及格式见设备信息定义
* @return 0 成功; 非0 失败,返回错误代码
*/
int SDF_GetDeviceInfo(Pointer hSessionHandle, byte[] pstDeviceInfo);
/**
* 产生随机数
*
* @param hSessionHandle 与设备建立的会话句柄
* @param uiLength 欲获取的随机数长度
* @param pucRandom 缓冲区指针用于存放获取的随机数
* @return 0 成功; 非0 失败,返回错误代码
*/
int SDF_GenerateRandom(Pointer hSessionHandle, int uiLength, byte[] pucRandom);
}

View File

@ -0,0 +1,21 @@
package com.sunyard.chsm.sdf.lib;
import com.sun.jna.ptr.PointerByReference;
/**
* @author liulu
* @since 2024/11/4
*/
public interface SunyardSdfLibrary extends SdfLibrary {
/**
* 打开设备
* @param phDeviceHandle 设备句柄
* @return int 响应码
*/
int SDF_OpenDevice(PointerByReference phDeviceHandle, byte[] ip, int port, int connTimeout, int dealTimeout, int ipMode);
}

View File

@ -123,6 +123,7 @@ public class DeviceServiceImpl implements DeviceService {
Assert.isTrue(manufacturerModel.getManufacturer() == manufacturer, "设备厂商和型号不匹配");
checkName(save.getName());
checkIpPort(save.getServiceIp(), save.getServicePort());
Device device = new Device();
BeanUtils.copyProperties(save, device);
@ -136,6 +137,14 @@ public class DeviceServiceImpl implements DeviceService {
return device.getId();
}
private void checkIpPort(String serviceIp, Integer servicePort) {
LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<Device>()
.eq(Device::getServiceIp, serviceIp)
.eq(Device::getServicePort, servicePort);
Device exist = spDeviceMapper.selectOne(wrapper);
Assert.isNull(exist, "设备IP和端口已存在");
}
@Override
public void update(DeviceDTO.DeviceSave update) {
Assert.notNull(update.getId(), "id不能为空");
@ -145,13 +154,16 @@ public class DeviceServiceImpl implements DeviceService {
if (!Objects.equals(exist.getName(), update.getName())) {
checkName(update.getName());
}
if (!Objects.equals(exist.getServiceIp(), update.getServiceIp())
|| !Objects.equals(exist.getServicePort(), update.getServicePort())) {
checkIpPort(update.getServiceIp(), update.getServicePort());
}
Device up = new Device();
BeanUtils.copyProperties(update, up);
up.setUpdateTime(LocalDateTime.now());
spDeviceMapper.updateById(up);
}
@Override

View File

@ -0,0 +1,61 @@
package com.sunyard.chsm.task;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sunyard.chsm.mapper.SpDeviceMapper;
import com.sunyard.chsm.model.entity.Device;
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.util.List;
/**
* @author liulu
* @since 2024/11/4
*/
@Component
public class DeviceTask implements InitializingBean {
@Resource
private SpDeviceMapper spDeviceMapper;
@Resource
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
@Resource
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
private void checkDeviceStatus() {
for (int i = 1; i < 500; i++) {
Page<Device> devicePage = spDeviceMapper.selectPage(
new Page<>(i, 100L),
new LambdaQueryWrapper<Device>().orderByAsc(Device::getId)
);
List<Device> records = devicePage.getRecords();
if (CollectionUtils.isEmpty(records)) {
break;
}
for (Device record : records) {
}
}
}
@Override
public void afterPropertiesSet() throws Exception {
threadPoolTaskScheduler.scheduleWithFixedDelay(this::checkDeviceStatus, Duration.ofMinutes(5L));
}
}

View File

@ -11,6 +11,9 @@ CREATE TABLE sp_device (
manage_ip VARCHAR(30) COMMENT '管理ip',
manage_port INT COMMENT '管理端口',
access_credentials VARCHAR(1000) COMMENT '访问凭证',
connected TINYINT NOT NULL DEFAULT 0,
last_connected_time TIMESTAMP ,
last_check_time TIMESTAMP ,
status VARCHAR(25) DEFAULT '' COMMENT '设备状态',
group_id BIGINT NOT NULL DEFAULT 0 COMMENT '设备组id',
group_name VARCHAR(255) NOT NULL DEFAULT '' COMMENT '设备组名称',
@ -21,6 +24,7 @@ CREATE TABLE sp_device (
PRIMARY KEY (id)
);
-- 设备组
CREATE TABLE sp_device_group (
id BIGINT NOT NULL COMMENT 'id',
name VARCHAR(255) NOT NULL DEFAULT '' COMMENT '服务名称',
@ -30,6 +34,18 @@ CREATE TABLE sp_device_group (
PRIMARY KEY (id)
);
-- TMK
CREATE TABLE sp_tmk_info (
id BIGINT NOT NULL COMMENT 'id',
device_serial VARCHAR(255) NOT NULL DEFAULT '' COMMENT '设备序列号',
enc_tmk VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'tmk密文',
pub_key VARCHAR(400) NOT NULL DEFAULT '' COMMENT '设备公钥',
remark VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注',
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
PRIMARY KEY (id)
);
-- 密码服务
CREATE TABLE sp_crypto_service (
id BIGINT NOT NULL COMMENT 'id',