diff --git a/chsm-common/src/main/java/com/sunyard/chsm/enums/TmkStatusEnum.java b/chsm-common/src/main/java/com/sunyard/chsm/enums/DeviceTmkStatus.java similarity index 82% rename from chsm-common/src/main/java/com/sunyard/chsm/enums/TmkStatusEnum.java rename to chsm-common/src/main/java/com/sunyard/chsm/enums/DeviceTmkStatus.java index 64a2858..993f126 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/enums/TmkStatusEnum.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/enums/DeviceTmkStatus.java @@ -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, 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 39da966..4e97a61 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 @@ -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 { - default List selectConnedList() { - return selectList( - new LambdaQueryWrapper() - .eq(Device::getConnected, true) - ); - } - - default Device selectOneByStatus(TmkStatusEnum status) { + default Device selectOneByStatus(DeviceTmkStatus status) { Page devicePage = selectPage( Page.of(1L, 1L), new LambdaQueryWrapper().eq(Device::getTmkStatus, status.name()) 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 new file mode 100644 index 0000000..c5b76d4 --- /dev/null +++ b/chsm-common/src/main/java/com/sunyard/chsm/model/dto/DeviceCheckRes.java @@ -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; + + +} diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/dto/TmkStatus.java b/chsm-common/src/main/java/com/sunyard/chsm/model/dto/TmkStatus.java similarity index 87% rename from chsm-web-manage/src/main/java/com/sunyard/chsm/dto/TmkStatus.java rename to chsm-common/src/main/java/com/sunyard/chsm/model/dto/TmkStatus.java index d5ea4a8..422df63 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/dto/TmkStatus.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/model/dto/TmkStatus.java @@ -1,4 +1,4 @@ -package com.sunyard.chsm.dto; +package com.sunyard.chsm.model.dto; import lombok.Data; diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java index abba1f8..7ce8b1a 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/BcSdfApiAdaptor.java @@ -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); 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 new file mode 100644 index 0000000..1bac0c9 --- /dev/null +++ b/chsm-common/src/main/java/com/sunyard/chsm/service/TmkService.java @@ -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); + } + } + + +} diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/TmkController.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/TmkController.java index 8aaa2a2..6cc9705 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/TmkController.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/TmkController.java @@ -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 getTMKStatus() { - TmkStatus status = deviceService.getTMKStatus(); + TmkStatus status = tmkService.getTMKStatus(); return R.data(status); } @@ -41,7 +41,7 @@ public class TmkController { */ @PostMapping("/init") public R initTmk() { - deviceService.initTmk(); + tmkService.initTmk(); return R.ok(); } diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/DeviceService.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/DeviceService.java index 5faf30c..543fb27 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/DeviceService.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/DeviceService.java @@ -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(); } diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java index db099aa..d8681ce 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/DeviceServiceImpl.java @@ -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 selectPageList(DeviceDTO.Query query) { @@ -152,10 +137,13 @@ public class DeviceServiceImpl implements DeviceService { device.setWeight(1); device.setCreateTime(LocalDateTime.now()); - Pair 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 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 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 wrapper = new LambdaQueryWrapper() .eq(Device::getName, name); diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/task/CheckDeviceRunner.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/task/CheckDeviceRunner.java new file mode 100644 index 0000000..d8afdcf --- /dev/null +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/task/CheckDeviceRunner.java @@ -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); + + + } +} diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/task/DeviceTask.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/task/DeviceTask.java index bd9ee68..b28af6c 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/task/DeviceTask.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/task/DeviceTask.java @@ -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); + }); } } }