设备连接检查
This commit is contained in:
parent
f4361d2fd5
commit
29c5fb261f
@ -4,7 +4,7 @@ package com.sunyard.chsm.enums;
|
||||
* @author liulu
|
||||
* @since 2024/12/7
|
||||
*/
|
||||
public enum TmkStatusEnum {
|
||||
public enum DeviceTmkStatus {
|
||||
|
||||
device_error,
|
||||
key_error,
|
@ -3,7 +3,7 @@ package com.sunyard.chsm.mapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.sunyard.chsm.enums.TmkStatusEnum;
|
||||
import com.sunyard.chsm.enums.DeviceTmkStatus;
|
||||
import com.sunyard.chsm.model.entity.Device;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@ -16,14 +16,7 @@ import java.util.List;
|
||||
@Mapper
|
||||
public interface SpDeviceMapper extends BaseMapper<Device> {
|
||||
|
||||
default List<Device> selectConnedList() {
|
||||
return selectList(
|
||||
new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getConnected, true)
|
||||
);
|
||||
}
|
||||
|
||||
default Device selectOneByStatus(TmkStatusEnum status) {
|
||||
default Device selectOneByStatus(DeviceTmkStatus status) {
|
||||
Page<Device> devicePage = selectPage(
|
||||
Page.of(1L, 1L),
|
||||
new LambdaQueryWrapper<Device>().eq(Device::getTmkStatus, status.name())
|
||||
|
@ -0,0 +1,21 @@
|
||||
package com.sunyard.chsm.model.dto;
|
||||
|
||||
import com.sunyard.chsm.enums.DeviceTmkStatus;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
@Data
|
||||
public class DeviceCheckRes {
|
||||
|
||||
private DeviceTmkStatus status;
|
||||
private String deviceSerial;
|
||||
private String pubKey;
|
||||
private String encTmk;
|
||||
private boolean hasError = false;
|
||||
private String message;
|
||||
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.sunyard.chsm.dto;
|
||||
package com.sunyard.chsm.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -120,7 +120,7 @@ public class BcSdfApiAdaptor implements SdfApiAdapter {
|
||||
ECPublicKeyParameters pub = BCECUtils.createECPublicKeyParameters(pubKey.getX(), pubKey.getY());
|
||||
ECPrivateKeyParameters pri = BCECUtils.createECPrivateKeyParameters(getD());
|
||||
try {
|
||||
byte[] k = BCSM2Utils.decrypt(pri, pucEncDateIn.getC1C3C2Bytes());
|
||||
byte[] k = BCSM2Utils.decrypt(pri, LangUtils.merge(new byte[]{0x04}, pucEncDateIn.getC1C3C2Bytes()));
|
||||
byte[] encrypt = BCSM2Utils.encrypt(pub, k);
|
||||
return EccCipher.fromBytes(encrypt);
|
||||
} catch (InvalidCipherTextException e) {
|
||||
@ -133,7 +133,7 @@ public class BcSdfApiAdaptor implements SdfApiAdapter {
|
||||
ECPrivateKeyParameters pri = BCECUtils.createECPrivateKeyParameters(getD());
|
||||
|
||||
try {
|
||||
byte[] pucKey = BCSM2Utils.decrypt(pri, eccCipher.getC1C3C2Bytes());
|
||||
byte[] pucKey = BCSM2Utils.decrypt(pri, LangUtils.merge(new byte[]{0x04}, eccCipher.getC1C3C2Bytes()));
|
||||
Assert.isTrue(pucKey.length == 16, "密钥长度错误");
|
||||
String key = UUID.randomUUID().toString();
|
||||
KEY_HANDLE_CONTEXT.put(key, pucKey);
|
||||
|
@ -0,0 +1,236 @@
|
||||
package com.sunyard.chsm.service;
|
||||
|
||||
import com.sunyard.chsm.constant.ParamConfKeyConstant;
|
||||
import com.sunyard.chsm.enums.DeviceTmkStatus;
|
||||
import com.sunyard.chsm.mapper.ParamConfMapper;
|
||||
import com.sunyard.chsm.mapper.SpDeviceMapper;
|
||||
import com.sunyard.chsm.model.dto.DeviceCheckRes;
|
||||
import com.sunyard.chsm.model.dto.TmkStatus;
|
||||
import com.sunyard.chsm.model.entity.Device;
|
||||
import com.sunyard.chsm.model.entity.ParamConf;
|
||||
import com.sunyard.chsm.sdf.adapter.SdfApiAdapter;
|
||||
import com.sunyard.chsm.sdf.adapter.SdfApiAdapterFactory;
|
||||
import com.sunyard.chsm.sdf.context.AlgId;
|
||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
||||
import com.sunyard.chsm.sdf.model.EccCipher;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
import com.sunyard.chsm.utils.CodecUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TmkService {
|
||||
|
||||
private final SpDeviceMapper spDeviceMapper;
|
||||
private final ParamConfMapper paramConfMapper;
|
||||
|
||||
public void initTmk() {
|
||||
boolean tmkInit = isTmkInit();
|
||||
Assert.isTrue(!tmkInit, "主密钥已经初始化");
|
||||
|
||||
Device device = getOneByStatus(DeviceTmkStatus.available);
|
||||
Assert.notNull(device, "没有可以用于初始化主密钥的设备");
|
||||
SdfApiAdapter sdfApi = SdfApiAdapterFactory.newInstance(device.getManufacturerModel(), device.getServiceIp(), device.getServicePort());
|
||||
|
||||
String hd = sdfApi.openDevice();
|
||||
String hs = sdfApi.openSession(hd);
|
||||
byte[] rk = sdfApi.generateRandom(hs, 16);
|
||||
EccPubKey pubKey = sdfApi.exportEncPublicKeyECC(hs, device.getEncKeyIdx());
|
||||
EccCipher cipher = sdfApi.externalEncryptECC(hs, pubKey, rk);
|
||||
sdfApi.getPrivateKeyAccessRight(hs, device.getEncKeyIdx(), device.getAccessCredentials().getBytes());
|
||||
String hk = sdfApi.importKeyWithISKECC(hs, device.getEncKeyIdx(), cipher);
|
||||
byte[] encrk = sdfApi.symEncrypt(hs, hk, AlgId.SGD_SM4_ECB, new byte[0], rk);
|
||||
byte[] prk = sdfApi.symDecrypt(hs, hk, AlgId.SGD_SM4_ECB, new byte[0], encrk);
|
||||
Assert.isTrue(Arrays.equals(rk, prk), "密码机加解密异常");
|
||||
|
||||
sdfApi.destroyKey(hs, hk);
|
||||
sdfApi.closeSession(hs);
|
||||
sdfApi.closeDevice(hd);
|
||||
|
||||
if (enableSoftDevice()) {
|
||||
updateSoftDeviceEncTmk(cipher.getC1C3C2Bytes());
|
||||
} else {
|
||||
Device up = new Device();
|
||||
up.setId(device.getId());
|
||||
up.setEncTmk(cipher.getC1C3C2Hex());
|
||||
up.setTmkStatus(DeviceTmkStatus.finished.name());
|
||||
spDeviceMapper.updateById(up);
|
||||
}
|
||||
updateTmkInit(true);
|
||||
|
||||
}
|
||||
|
||||
public TmkStatus getTMKStatus() {
|
||||
TmkStatus status = new TmkStatus();
|
||||
boolean init = isTmkInit();
|
||||
if (init) {
|
||||
status.setHasDevice(true);
|
||||
status.setTmkInit(true);
|
||||
return status;
|
||||
}
|
||||
status.setTmkInit(false);
|
||||
Device device = getOneByStatus(DeviceTmkStatus.available);
|
||||
status.setHasDevice(device != null);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
public DeviceCheckRes checkDevice(Device check) {
|
||||
|
||||
log.debug("==========> begin check device : {}", check);
|
||||
DeviceCheckRes res = new DeviceCheckRes();
|
||||
SdfApiAdapter sdfApi = SdfApiAdapterFactory.newInstance(check.getManufacturerModel(), check.getServiceIp(), check.getServicePort());
|
||||
String hd = sdfApi.openDevice();
|
||||
String hs = null;
|
||||
|
||||
try {
|
||||
hs = sdfApi.openSession(hd);
|
||||
DeviceInfo info = sdfApi.getDeviceInfo(hs);
|
||||
log.debug("get DeviceInfo: {}", info);
|
||||
res.setDeviceSerial(info.getDeviceSerial());
|
||||
res.setStatus(DeviceTmkStatus.key_error);
|
||||
} catch (Exception e) {
|
||||
log.warn("check device connect error: {}:{}", check.getServiceIp(), check.getServicePort(), e);
|
||||
res.setHasError(true);
|
||||
res.setStatus(DeviceTmkStatus.device_error);
|
||||
res.setMessage(e.getMessage());
|
||||
}
|
||||
if (res.isHasError()) {
|
||||
Optional.ofNullable(hs).ifPresent(sdfApi::closeSession);
|
||||
Optional.ofNullable(hd).ifPresent(sdfApi::closeDevice);
|
||||
log.debug("==========> end check device : {}", res);
|
||||
return res;
|
||||
}
|
||||
try {
|
||||
EccPubKey pubKey = sdfApi.exportEncPublicKeyECC(hs, check.getEncKeyIdx());
|
||||
if (Arrays.equals(pubKey.getPubKeyBytes(), new byte[64])) {
|
||||
throw new IllegalArgumentException("加密密钥索引不正确");
|
||||
}
|
||||
res.setPubKey(pubKey.getPubKeyHex());
|
||||
log.debug("export enc pubKey at index: {}, {}", check.getEncKeyIdx(), res.getPubKey());
|
||||
sdfApi.getPrivateKeyAccessRight(hs, check.getEncKeyIdx(), check.getAccessCredentials().getBytes());
|
||||
if (isTmkInit()) {
|
||||
log.debug("tmk is init...");
|
||||
EccCipher cipher;
|
||||
if (Objects.equals(check.getDeviceSerial(), res.getDeviceSerial())
|
||||
&& Objects.equals(check.getPubKey(), res.getPubKey())
|
||||
&& StringUtils.hasText(check.getEncTmk())) {
|
||||
cipher = EccCipher.fromHex(check.getEncTmk());
|
||||
log.debug("device serial, pubKey not changed, use origin device enc tmk");
|
||||
} else {
|
||||
log.debug("device serial, pubKey is changed, or no tmk in origin device");
|
||||
Device device = getOneByStatus(DeviceTmkStatus.finished);
|
||||
Assert.notNull(device, "系统主密钥设备异常,请联系管理员排查");
|
||||
log.debug("get device from finished: {}", device);
|
||||
SdfApiAdapter tmkAdapter = SdfApiAdapterFactory.newInstance(device.getManufacturerModel(), device.getServiceIp(), device.getServicePort());
|
||||
String tmkHd = tmkAdapter.openDevice();
|
||||
String tmkHs = tmkAdapter.openSession(tmkHd);
|
||||
tmkAdapter.getPrivateKeyAccessRight(tmkHs, device.getEncKeyIdx(), device.getAccessCredentials().getBytes());
|
||||
cipher = tmkAdapter.exchangeDigitEnvelopeBaseOnECC(tmkHs, device.getEncKeyIdx(), pubKey, EccCipher.fromHex(device.getEncTmk()));
|
||||
log.debug("exchanged envelope from finished success ...");
|
||||
}
|
||||
String hk = sdfApi.importKeyWithISKECC(hs, check.getEncKeyIdx(), cipher);
|
||||
sdfApi.destroyKey(hs, hk);
|
||||
if (!Objects.equals(check.getEncTmk(), cipher.getC1C3C2Hex())) {
|
||||
res.setEncTmk(cipher.getC1C3C2Hex());
|
||||
}
|
||||
res.setStatus(DeviceTmkStatus.finished);
|
||||
} else {
|
||||
byte[] random = sdfApi.generateRandom(hs, 16);
|
||||
EccCipher eccCipher = sdfApi.externalEncryptECC(hs, pubKey, random);
|
||||
String hk = sdfApi.importKeyWithISKECC(hs, check.getEncKeyIdx(), eccCipher);
|
||||
sdfApi.destroyKey(hs, hk);
|
||||
res.setStatus(DeviceTmkStatus.available);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("check device encKey error: {}:{}", check.getServiceIp(), check.getServicePort(), e);
|
||||
res.setHasError(true);
|
||||
res.setStatus(DeviceTmkStatus.key_error);
|
||||
res.setMessage(e.getMessage());
|
||||
}
|
||||
Optional.ofNullable(hs).ifPresent(sdfApi::closeSession);
|
||||
Optional.ofNullable(hd).ifPresent(sdfApi::closeDevice);
|
||||
log.debug("==========> end check device : {}", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
private Device getOneByStatus(DeviceTmkStatus status) {
|
||||
if (enableSoftDevice()) {
|
||||
Device device = new Device();
|
||||
device.setManufacturerModel(BouncyCastleProvider.PROVIDER_NAME);
|
||||
device.setEncKeyIdx(1);
|
||||
device.setServiceIp("127.0.0.1");
|
||||
device.setServicePort(8889);
|
||||
device.setAccessCredentials("543");
|
||||
device.setEncTmk(CodecUtils.encodeHex(getSoftDeviceEncTmk()));
|
||||
return device;
|
||||
}
|
||||
|
||||
return spDeviceMapper.selectOneByStatus(status);
|
||||
}
|
||||
|
||||
private boolean isTmkInit() {
|
||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_INIT);
|
||||
return conf != null && String.valueOf(true).equals(conf.getValue());
|
||||
}
|
||||
|
||||
private void updateTmkInit(boolean value) {
|
||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_INIT);
|
||||
if (conf == null) {
|
||||
conf = new ParamConf();
|
||||
conf.setValue(String.valueOf(value));
|
||||
conf.setKey(ParamConfKeyConstant.TMK_INIT);
|
||||
conf.setCreatTime(LocalDateTime.now());
|
||||
paramConfMapper.insert(conf);
|
||||
} else {
|
||||
conf.setValue(String.valueOf(value));
|
||||
paramConfMapper.updateById(conf);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
Assert.isTrue(enabled, "未启用软设备");
|
||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.SOFT_ENC_TMK);
|
||||
Assert.notNull(conf, "数据异常, 未找到软设备主密钥记录");
|
||||
return CodecUtils.decodeBase64(conf.getValue());
|
||||
}
|
||||
|
||||
private void updateSoftDeviceEncTmk(byte[] encTmk) {
|
||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.SOFT_ENC_TMK);
|
||||
if (conf == null) {
|
||||
conf = new ParamConf();
|
||||
conf.setValue(CodecUtils.encodeBase64(encTmk));
|
||||
conf.setKey(ParamConfKeyConstant.SOFT_ENC_TMK);
|
||||
conf.setCreatTime(LocalDateTime.now());
|
||||
paramConfMapper.insert(conf);
|
||||
} else {
|
||||
conf.setValue(CodecUtils.encodeBase64(encTmk));
|
||||
paramConfMapper.updateById(conf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package com.sunyard.chsm.controller;
|
||||
|
||||
import com.sunyard.chsm.dto.TmkStatus;
|
||||
import com.sunyard.chsm.model.R;
|
||||
import com.sunyard.chsm.service.DeviceService;
|
||||
import com.sunyard.chsm.model.dto.TmkStatus;
|
||||
import com.sunyard.chsm.service.TmkService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -23,7 +23,7 @@ import javax.annotation.Resource;
|
||||
public class TmkController {
|
||||
|
||||
@Resource
|
||||
private DeviceService deviceService;
|
||||
private TmkService tmkService;
|
||||
|
||||
/**
|
||||
* 查询主密钥生成状态
|
||||
@ -32,7 +32,7 @@ public class TmkController {
|
||||
*/
|
||||
@GetMapping("/status")
|
||||
public R<TmkStatus> getTMKStatus() {
|
||||
TmkStatus status = deviceService.getTMKStatus();
|
||||
TmkStatus status = tmkService.getTMKStatus();
|
||||
return R.data(status);
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ public class TmkController {
|
||||
*/
|
||||
@PostMapping("/init")
|
||||
public R<Void> initTmk() {
|
||||
deviceService.initTmk();
|
||||
tmkService.initTmk();
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package com.sunyard.chsm.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.sunyard.chsm.dto.DeviceDTO;
|
||||
import com.sunyard.chsm.dto.TmkStatus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -23,7 +22,4 @@ public interface DeviceService {
|
||||
|
||||
void delete(Long id);
|
||||
|
||||
TmkStatus getTMKStatus();
|
||||
|
||||
void initTmk();
|
||||
}
|
||||
|
@ -4,28 +4,16 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
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.constant.ParamConfKeyConstant;
|
||||
import com.sunyard.chsm.dto.DeviceDTO;
|
||||
import com.sunyard.chsm.dto.TmkStatus;
|
||||
import com.sunyard.chsm.enums.ManufacturerEnum;
|
||||
import com.sunyard.chsm.enums.ManufacturerModelEnum;
|
||||
import com.sunyard.chsm.enums.TmkStatusEnum;
|
||||
import com.sunyard.chsm.mapper.ParamConfMapper;
|
||||
import com.sunyard.chsm.mapper.SpDeviceMapper;
|
||||
import com.sunyard.chsm.mapper.TmkInfoMapper;
|
||||
import com.sunyard.chsm.model.dto.DeviceCheckRes;
|
||||
import com.sunyard.chsm.model.entity.Device;
|
||||
import com.sunyard.chsm.model.entity.ParamConf;
|
||||
import com.sunyard.chsm.sdf.adapter.SdfApiAdapter;
|
||||
import com.sunyard.chsm.sdf.adapter.SdfApiAdapterFactory;
|
||||
import com.sunyard.chsm.sdf.context.AlgId;
|
||||
import com.sunyard.chsm.sdf.model.EccCipher;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
import com.sunyard.chsm.service.DeviceService;
|
||||
import com.sunyard.chsm.utils.CodecUtils;
|
||||
import com.sunyard.chsm.service.TmkService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
@ -34,7 +22,6 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@ -52,9 +39,7 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
@Resource
|
||||
private SpDeviceMapper spDeviceMapper;
|
||||
@Resource
|
||||
private ParamConfMapper paramConfMapper;
|
||||
@Resource
|
||||
private TmkInfoMapper tmkInfoMapper;
|
||||
private TmkService tmkService;
|
||||
|
||||
@Override
|
||||
public Page<DeviceDTO.DeviceView> selectPageList(DeviceDTO.Query query) {
|
||||
@ -152,10 +137,13 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
device.setWeight(1);
|
||||
device.setCreateTime(LocalDateTime.now());
|
||||
|
||||
Pair<String, String> pair = checkDeviceSdf(save);
|
||||
device.setTmkStatus(StringUtils.hasText(pair.getSecond()) ? TmkStatusEnum.finished.name() : TmkStatusEnum.available.name());
|
||||
device.setPubKey(pair.getFirst());
|
||||
device.setEncTmk(pair.getSecond());
|
||||
DeviceCheckRes checkRes = tmkService.checkDevice(device);
|
||||
Assert.isTrue(!checkRes.isHasError(), checkRes.getMessage());
|
||||
|
||||
device.setTmkStatus(checkRes.getStatus().name());
|
||||
device.setDeviceSerial(checkRes.getDeviceSerial());
|
||||
device.setPubKey(checkRes.getPubKey());
|
||||
device.setEncTmk(checkRes.getEncTmk());
|
||||
|
||||
spDeviceMapper.insert(device);
|
||||
return device.getId();
|
||||
@ -169,44 +157,6 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
Assert.isNull(exist, "设备IP和端口已存在");
|
||||
}
|
||||
|
||||
private Pair<String, String> checkDeviceSdf(DeviceDTO.DeviceSave save) {
|
||||
SdfApiAdapter sdfApiAdapter = SdfApiAdapterFactory.newInstance(save.getManufacturerModel(), save.getServiceIp(), save.getServicePort());
|
||||
|
||||
String hd = sdfApiAdapter.openDevice();
|
||||
String hs = null;
|
||||
try {
|
||||
String encTmk = "";
|
||||
hs = sdfApiAdapter.openSession(hd);
|
||||
EccPubKey eccPubKey = sdfApiAdapter.exportEncPublicKeyECC(hs, save.getEncKeyIdx());
|
||||
if (Arrays.equals(eccPubKey.getPubKeyBytes(), new byte[64])) {
|
||||
throw new IllegalArgumentException("加密密钥索引不正确");
|
||||
}
|
||||
sdfApiAdapter.getPrivateKeyAccessRight(hs, save.getEncKeyIdx(), save.getAccessCredentials().getBytes());
|
||||
if (isTmkInit()) {
|
||||
Device device = getOneByStatus(TmkStatusEnum.finished);
|
||||
Assert.notNull(device, "系统主密钥设备异常");
|
||||
|
||||
SdfApiAdapter tmkAdapter = SdfApiAdapterFactory.newInstance(save.getManufacturerModel(), save.getServiceIp(), save.getServicePort());
|
||||
String tmkHd = tmkAdapter.openDevice();
|
||||
String tmkHs = tmkAdapter.openSession(tmkHd);
|
||||
tmkAdapter.getPrivateKeyAccessRight(tmkHs, device.getEncKeyIdx(), device.getAccessCredentials().getBytes());
|
||||
EccCipher cipher = tmkAdapter.exchangeDigitEnvelopeBaseOnECC(tmkHs, device.getEncKeyIdx(), eccPubKey, EccCipher.fromHex(device.getEncTmk()));
|
||||
String hk = sdfApiAdapter.importKeyWithISKECC(hs, save.getEncKeyIdx(), cipher);
|
||||
sdfApiAdapter.destroyKey(hs, hk);
|
||||
encTmk = cipher.getC1C3C2Hex();
|
||||
} else {
|
||||
byte[] random = sdfApiAdapter.generateRandom(hs, 16);
|
||||
EccCipher eccCipher = sdfApiAdapter.externalEncryptECC(hs, eccPubKey, random);
|
||||
String hk = sdfApiAdapter.importKeyWithISKECC(hs, save.getEncKeyIdx(), eccCipher);
|
||||
sdfApiAdapter.destroyKey(hs, hk);
|
||||
}
|
||||
return Pair.of(eccPubKey.getPubKeyHex(), encTmk);
|
||||
} finally {
|
||||
Optional.ofNullable(hs).ifPresent(sdfApiAdapter::closeSession);
|
||||
sdfApiAdapter.closeDevice(hd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DeviceDTO.DeviceSave update) {
|
||||
Assert.notNull(update.getId(), "id不能为空");
|
||||
@ -229,10 +179,14 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
if (ipChanged
|
||||
|| !Objects.equals(exist.getEncKeyIdx(), update.getEncKeyIdx())
|
||||
|| !Objects.equals(exist.getAccessCredentials(), update.getAccessCredentials())) {
|
||||
Pair<String, String> pair = checkDeviceSdf(update);
|
||||
up.setTmkStatus(StringUtils.hasText(pair.getSecond()) ? TmkStatusEnum.finished.name() : TmkStatusEnum.available.name());
|
||||
up.setPubKey(pair.getFirst());
|
||||
up.setEncTmk(pair.getSecond());
|
||||
|
||||
DeviceCheckRes checkRes = tmkService.checkDevice(up);
|
||||
Assert.isTrue(!checkRes.isHasError(), checkRes.getMessage());
|
||||
|
||||
up.setTmkStatus(checkRes.getStatus().name());
|
||||
up.setDeviceSerial(checkRes.getDeviceSerial());
|
||||
up.setPubKey(checkRes.getPubKey());
|
||||
up.setEncTmk(checkRes.getEncTmk());
|
||||
}
|
||||
spDeviceMapper.updateById(up);
|
||||
}
|
||||
@ -242,120 +196,6 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
spDeviceMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TmkStatus getTMKStatus() {
|
||||
TmkStatus status = new TmkStatus();
|
||||
boolean init = isTmkInit();
|
||||
if (init) {
|
||||
status.setHasDevice(true);
|
||||
status.setTmkInit(true);
|
||||
return status;
|
||||
}
|
||||
status.setTmkInit(false);
|
||||
Device device = getOneByStatus(TmkStatusEnum.available);
|
||||
status.setHasDevice(device != null);
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initTmk() {
|
||||
boolean tmkInit = isTmkInit();
|
||||
Assert.isTrue(!tmkInit, "主密钥已经初始化");
|
||||
|
||||
Device device = getOneByStatus(TmkStatusEnum.available);
|
||||
Assert.notNull(device, "没有可以用于初始化主密钥的设备");
|
||||
SdfApiAdapter sdfApi = SdfApiAdapterFactory.newInstance(device.getManufacturerModel(), device.getServiceIp(), device.getServicePort());
|
||||
|
||||
String hd = sdfApi.openDevice();
|
||||
String hs = sdfApi.openSession(hd);
|
||||
byte[] rk = sdfApi.generateRandom(hs, 16);
|
||||
EccPubKey pubKey = sdfApi.exportEncPublicKeyECC(hs, device.getEncKeyIdx());
|
||||
EccCipher cipher = sdfApi.externalEncryptECC(hs, pubKey, rk);
|
||||
sdfApi.getPrivateKeyAccessRight(hs, device.getEncKeyIdx(), device.getAccessCredentials().getBytes());
|
||||
String hk = sdfApi.importKeyWithISKECC(hs, device.getEncKeyIdx(), cipher);
|
||||
byte[] encrk = sdfApi.symEncrypt(hs, hk, AlgId.SGD_SM4_ECB, new byte[0], rk);
|
||||
byte[] prk = sdfApi.symDecrypt(hs, hk, AlgId.SGD_SM4_ECB, new byte[0], encrk);
|
||||
Assert.isTrue(Arrays.equals(rk, prk), "密码机加解密异常");
|
||||
|
||||
sdfApi.destroyKey(hs, hk);
|
||||
sdfApi.closeSession(hs);
|
||||
sdfApi.closeDevice(hd);
|
||||
|
||||
if (enableSoftDevice()) {
|
||||
updateSoftDeviceEncTmk(cipher.getC1C3C2Bytes());
|
||||
} else {
|
||||
Device up = new Device();
|
||||
up.setId(device.getId());
|
||||
up.setEncTmk(cipher.getC1C3C2Hex());
|
||||
up.setTmkStatus(TmkStatusEnum.finished.name());
|
||||
spDeviceMapper.updateById(up);
|
||||
}
|
||||
updateTmkInit(true);
|
||||
}
|
||||
|
||||
private Device getOneByStatus(TmkStatusEnum status) {
|
||||
if (enableSoftDevice()) {
|
||||
Device device = new Device();
|
||||
device.setManufacturerModel(BouncyCastleProvider.PROVIDER_NAME);
|
||||
device.setEncKeyIdx(1);
|
||||
device.setServiceIp("127.0.0.1");
|
||||
device.setServicePort(8889);
|
||||
device.setAccessCredentials("543");
|
||||
device.setEncTmk(CodecUtils.encodeHex(getSoftDeviceEncTmk()));
|
||||
return device;
|
||||
}
|
||||
|
||||
return spDeviceMapper.selectOneByStatus(status);
|
||||
}
|
||||
|
||||
private boolean isTmkInit() {
|
||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_INIT);
|
||||
return conf != null && String.valueOf(true).equals(conf.getValue());
|
||||
}
|
||||
|
||||
private void updateTmkInit(boolean value) {
|
||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.TMK_INIT);
|
||||
if (conf == null) {
|
||||
conf = new ParamConf();
|
||||
conf.setValue(String.valueOf(value));
|
||||
conf.setKey(ParamConfKeyConstant.TMK_INIT);
|
||||
conf.setCreatTime(LocalDateTime.now());
|
||||
paramConfMapper.insert(conf);
|
||||
} else {
|
||||
conf.setValue(String.valueOf(value));
|
||||
paramConfMapper.updateById(conf);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
Assert.isTrue(enabled, "未启用软设备");
|
||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.SOFT_ENC_TMK);
|
||||
Assert.notNull(conf, "数据异常, 未找到软设备主密钥记录");
|
||||
return CodecUtils.decodeBase64(conf.getValue());
|
||||
}
|
||||
|
||||
private void updateSoftDeviceEncTmk(byte[] encTmk) {
|
||||
ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.SOFT_ENC_TMK);
|
||||
if (conf == null) {
|
||||
conf = new ParamConf();
|
||||
conf.setValue(CodecUtils.encodeBase64(encTmk));
|
||||
conf.setKey(ParamConfKeyConstant.SOFT_ENC_TMK);
|
||||
conf.setCreatTime(LocalDateTime.now());
|
||||
paramConfMapper.insert(conf);
|
||||
} else {
|
||||
conf.setValue(CodecUtils.encodeBase64(encTmk));
|
||||
paramConfMapper.updateById(conf);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkName(String name) {
|
||||
LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getName, name);
|
||||
|
@ -0,0 +1,78 @@
|
||||
package com.sunyard.chsm.task;
|
||||
|
||||
import com.sunyard.chsm.enums.DeviceTmkStatus;
|
||||
import com.sunyard.chsm.mapper.ParamConfMapper;
|
||||
import com.sunyard.chsm.mapper.SpDeviceMapper;
|
||||
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.context.AlgId;
|
||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
||||
import com.sunyard.chsm.sdf.model.EccCipher;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/12/10
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class CheckDeviceRunner implements Runnable {
|
||||
|
||||
private final SpDeviceMapper spDeviceMapper;
|
||||
private final ParamConfMapper paramConfMapper;
|
||||
private final Device device;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean hasError = false;
|
||||
DeviceTmkStatus status = DeviceTmkStatus.device_error;
|
||||
SdfApiAdapter sdfApi = SdfApiAdapterFactory.newInstance(device.getManufacturerModel(), device.getServiceIp(), device.getServicePort());
|
||||
String hd = sdfApi.openDevice();
|
||||
String hs = null;
|
||||
|
||||
try {
|
||||
hs = sdfApi.openSession(hd);
|
||||
DeviceInfo info = sdfApi.getDeviceInfo(hs);
|
||||
log.info("get DeviceInfo: {}", info);
|
||||
status = DeviceTmkStatus.key_error;
|
||||
} catch (Exception e) {
|
||||
log.warn("check device connect error: {}:{}", device.getServiceIp(), device.getServicePort(), e);
|
||||
hasError = true;
|
||||
}
|
||||
if(hasError) {
|
||||
// update status
|
||||
return;
|
||||
}
|
||||
try {
|
||||
EccPubKey pubKey = sdfApi.exportEncPublicKeyECC(hs, device.getEncKeyIdx());
|
||||
status = DeviceTmkStatus.key_error;
|
||||
} catch (Exception e) {
|
||||
log.warn("check device connect error: {}:{}", device.getServiceIp(), device.getServicePort(), e);
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
byte[] rk = sdfApi.generateRandom(hs, 16);
|
||||
EccPubKey pubKey = sdfApi.exportEncPublicKeyECC(hs, device.getEncKeyIdx());
|
||||
EccCipher cipher = sdfApi.externalEncryptECC(hs, pubKey, rk);
|
||||
sdfApi.getPrivateKeyAccessRight(hs, device.getEncKeyIdx(), device.getAccessCredentials().getBytes());
|
||||
String hk = sdfApi.importKeyWithISKECC(hs, device.getEncKeyIdx(), cipher);
|
||||
byte[] encrk = sdfApi.symEncrypt(hs, hk, AlgId.SGD_SM4_ECB, new byte[0], rk);
|
||||
byte[] prk = sdfApi.symDecrypt(hs, hk, AlgId.SGD_SM4_ECB, new byte[0], encrk);
|
||||
Assert.isTrue(Arrays.equals(rk, prk), "密码机加解密异常");
|
||||
|
||||
sdfApi.destroyKey(hs, hk);
|
||||
sdfApi.closeSession(hs);
|
||||
sdfApi.closeDevice(hd);
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -3,12 +3,11 @@ 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.sdf.adapter.SdfApiAdapter;
|
||||
import com.sunyard.chsm.sdf.adapter.SdfApiAdapterFactory;
|
||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
import com.sunyard.chsm.service.TmkService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
@ -20,6 +19,7 @@ import javax.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
@ -31,7 +31,8 @@ public class DeviceTask implements InitializingBean {
|
||||
|
||||
@Resource
|
||||
private SpDeviceMapper spDeviceMapper;
|
||||
|
||||
@Resource
|
||||
private TmkService tmkService;
|
||||
@Resource
|
||||
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
|
||||
@Resource
|
||||
@ -49,33 +50,26 @@ public class DeviceTask implements InitializingBean {
|
||||
if (CollectionUtils.isEmpty(records)) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (Device record : records) {
|
||||
boolean connected = false;
|
||||
try {
|
||||
SdfApiAdapter sdfApiAdapter = SdfApiAdapterFactory.newInstance(record.getManufacturerModel(), record.getServiceIp(), record.getServicePort());
|
||||
String dh = sdfApiAdapter.openDevice();
|
||||
String sh = sdfApiAdapter.openSession(dh);
|
||||
DeviceInfo info = sdfApiAdapter.getDeviceInfo(sh);
|
||||
log.info("get DeviceInfo: {}", info);
|
||||
EccPubKey eccPubKey = sdfApiAdapter.exportEncPublicKeyECC(sh, 2);
|
||||
log.info("exportEncPublicKeyECC: {}", eccPubKey.getPubKeyHex());
|
||||
sdfApiAdapter.closeSession(sh);
|
||||
sdfApiAdapter.closeDevice(dh);
|
||||
connected = true;
|
||||
threadPoolTaskExecutor.execute(() -> {
|
||||
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);
|
||||
|
||||
} catch (Exception ex) {
|
||||
log.warn("设备 {}:{} 连接异常", record.getServiceIp(), record.getServicePort(), ex);
|
||||
}
|
||||
Device up = new Device();
|
||||
up.setId(record.getId());
|
||||
up.setConnected(connected);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
if (connected) {
|
||||
up.setLastConnectedTime(now);
|
||||
}
|
||||
up.setLastCheckTime(now);
|
||||
spDeviceMapper.updateById(up);
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user