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 44adc5e..95ac364 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 @@ -1,13 +1,25 @@ package com.sunyard.chsm.mapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.sunyard.chsm.model.entity.Device; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * @author liulu * @since 2024/10/17 */ @Mapper public interface SpDeviceMapper extends BaseMapper { + + default List selectConnedList() { + return selectList( + new LambdaQueryWrapper() + .eq(Device::getConnected, true) + ); + } + + } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/model/entity/TmkInfo.java b/chsm-common/src/main/java/com/sunyard/chsm/model/entity/TmkInfo.java index 3de73f9..d009592 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/model/entity/TmkInfo.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/model/entity/TmkInfo.java @@ -17,6 +17,7 @@ public class TmkInfo { private String deviceSerial; private String encTmk; + private String pubKey; private String remark; private LocalDateTime createTime; 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 024134d..2ecd009 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 @@ -2,14 +2,16 @@ 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.EccPriKey; -import com.sunyard.chsm.sdf.model.EccPubKey; import com.sunyard.chsm.sdf.util.LangUtils; +import com.sunyard.chsm.utils.gm.BCECUtils; import com.sunyard.chsm.utils.gm.BCSM2Utils; import lombok.SneakyThrows; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.BigIntegers; import java.math.BigInteger; @@ -70,10 +72,10 @@ public class BcSdfApiAdaptor implements SdfApiAdapter { } @Override - public EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex) { + public byte[] exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex) { BigInteger d = new BigInteger(1, getD()); ECPoint q = BCSM2Utils.G_POINT.multiply(d).normalize(); - return new EccPubKey(256, q.getXCoord().getEncoded(), q.getYCoord().getEncoded()); + return LangUtils.merge(q.getXCoord().getEncoded(), q.getYCoord().getEncoded()); } private byte[] getD() { @@ -93,7 +95,29 @@ public class BcSdfApiAdaptor implements SdfApiAdapter { byte[] x = pubKey.getQ().getXCoord().getEncoded(); byte[] y = pubKey.getQ().getYCoord().getEncoded(); byte[] d = BigIntegers.asUnsignedByteArray(32, priKey.getD()); - return new EccKey(new EccPubKey(256, x, y), new EccPriKey(256, d)); + return new EccKey(LangUtils.merge(x, y), d); + } + + @Override + public byte[] exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, byte[] pubKey, byte[] pucEncDateIn) { + return new byte[0]; + } + + @Override + public byte[] externalEncryptECC(String sessionHandle, byte[] pubKey, byte[] pucData) { + if (pubKey[0] == 4) { + pubKey = Arrays.copyOfRange(pubKey, 1, 65); + } + ECPublicKeyParameters parameters = BCECUtils.createECPublicKeyParameters( + Arrays.copyOfRange(pubKey, 0, 32), + Arrays.copyOfRange(pubKey, 32, 64) + ); + try { + byte[] encrypt = BCSM2Utils.encrypt(parameters, pucData); + return Arrays.copyOfRange(encrypt, 1, encrypt.length); + } catch (InvalidCipherTextException e) { + throw new RuntimeException(e); + } } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java index 2e68105..26627a4 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/JnaSdfAdaptor.java @@ -2,11 +2,12 @@ package com.sunyard.chsm.sdf.adapter; import com.sun.jna.Pointer; import com.sun.jna.ptr.PointerByReference; +import com.sunyard.chsm.sdf.context.AlgId; 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 com.sunyard.chsm.sdf.model.SDF_DeviceInfo; +import com.sunyard.chsm.sdf.util.LangUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.util.Assert; @@ -117,15 +118,28 @@ public abstract class JnaSdfAdaptor implements SdfApiAdapter { } @Override - public EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex) { + public byte[] exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex) { byte[] pubKey = new byte[132]; Pointer hSessionHandle = getSessionHandle(sessionHandle); sdfLibrary.SDF_ExportEncPublicKey_ECC(hSessionHandle, uiKeyIndex, pubKey); - return new EccPubKey(256, Arrays.copyOfRange(pubKey, 36, 68), Arrays.copyOfRange(pubKey, 100, 132)); + return LangUtils.merge(Arrays.copyOfRange(pubKey, 36, 68), Arrays.copyOfRange(pubKey, 100, 132)); } @Override public EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits) { return null; } + + @Override + public byte[] exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, byte[] pubKey, byte[] pucEncDateIn) { + return new byte[0]; + } + + @Override + public byte[] externalEncryptECC(String sessionHandle, byte[] pubKey, byte[] pucData) { + byte[] encData = new byte[128 + 32 + 4 + pucData.length]; + Pointer hSessionHandle = getSessionHandle(sessionHandle); + sdfLibrary.SDF_ExternalEncrypt_ECC(hSessionHandle, getAlgId(AlgId.SGD_SM2_3), pubKey, pucData, pucData.length, encData); + return encData; + } } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java index d03100e..423acc2 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/adapter/SdfApiAdapter.java @@ -2,7 +2,6 @@ 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 @@ -54,9 +53,9 @@ public interface SdfApiAdapter { * 导出ECC加密公钥 * * @param uiKeyIndex 密码设备存储的ECC密钥对索引值 - * @return pucPublicKeyEcc 返回ECC加密公钥 + * @return pucPublicKeyEcc 返回ECC加密公钥x+y */ - EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex); + byte[] exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex); /** * 产生ECC密钥对并输出 @@ -68,4 +67,10 @@ public interface SdfApiAdapter { EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits); + byte[] exchangeDigitEnvelopeBaseOnECC(String sessionHandle, int uiKeyIndex, byte[] pubKey, byte[] pucEncDateIn); + + + byte[] externalEncryptECC(String sessionHandle, byte[] pubKey, byte[] pucData); + + } diff --git a/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccKey.java b/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccKey.java index 0696e00..91be065 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccKey.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/sdf/model/EccKey.java @@ -12,10 +12,10 @@ import lombok.NoArgsConstructor; @NoArgsConstructor public class EccKey { - private EccPubKey pubKey; - private EccPriKey priKey; + private byte[] pubKey; + private byte[] priKey; - public EccKey(EccPubKey pubKey, EccPriKey priKey) { + public EccKey(byte[] pubKey, byte[] priKey) { this.pubKey = pubKey; this.priKey = priKey; } 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 new file mode 100644 index 0000000..d8b0cbe --- /dev/null +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/TmkController.java @@ -0,0 +1,35 @@ +package com.sunyard.chsm.controller; + +import com.sunyard.chsm.service.DeviceService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + * 主密钥管理 + * + * @author liulu + * @since 2024/11/8 + */ +@Slf4j +@RestController +@RequestMapping("/tmk") +public class TmkController { + + @Resource + private DeviceService deviceService; + + /** + * 初始化主密钥 + */ + @PostMapping("/init") + public void initTmk() { + deviceService.initTmk(); + + } + + +} 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 b0206f1..86116ac 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 @@ -21,4 +21,7 @@ public interface DeviceService { void update(DeviceDTO.DeviceSave update); void delete(Long id); + + 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 012b858..770449a 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 @@ -8,9 +8,19 @@ import com.sunyard.chsm.dto.DeviceDTO; import com.sunyard.chsm.enums.ManufacturerEnum; import com.sunyard.chsm.enums.ManufacturerModelEnum; import com.sunyard.chsm.mapper.SpDeviceMapper; +import com.sunyard.chsm.mapper.TmkInfoMapper; import com.sunyard.chsm.model.entity.Device; +import com.sunyard.chsm.model.entity.TmkInfo; +import com.sunyard.chsm.sdf.adapter.BcSdfApiAdaptor; +import com.sunyard.chsm.sdf.adapter.SdfApiAdapter; +import com.sunyard.chsm.sdf.adapter.SdfApiAdapterFactory; +import com.sunyard.chsm.sdf.context.DeviceContext; +import com.sunyard.chsm.sdf.model.DeviceInfo; import com.sunyard.chsm.service.DeviceService; +import com.sunyard.ssp.modules.sysconf.paramconf.entity.ParamConf; +import com.sunyard.ssp.modules.sysconf.paramconf.mapper.ParamConfMapper; import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.util.encoders.Hex; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -36,6 +46,10 @@ public class DeviceServiceImpl implements DeviceService { @Resource private SpDeviceMapper spDeviceMapper; + @Resource + private ParamConfMapper paramConfMapper; + @Resource + private TmkInfoMapper tmkInfoMapper; @Override public Page selectPageList(DeviceDTO.Query query) { @@ -171,6 +185,70 @@ public class DeviceServiceImpl implements DeviceService { spDeviceMapper.deleteById(id); } + @Override + public void initTmk() { + ParamConf tmkInit = paramConfMapper.selectByKey("tmk_init"); + Assert.isTrue(tmkInit == null || !"true".equals(tmkInit.getValue()), "主密钥已经初始化"); + List conned = spDeviceMapper.selectConnedList(); + + LocalDateTime now = LocalDateTime.now(); + if (CollectionUtils.isEmpty(conned)) { + // + BcSdfApiAdaptor sdfApi = new BcSdfApiAdaptor(); + byte[] sk = sdfApi.generateRandom("", 16); + + byte[] publicKey = sdfApi.exportEncPublicKeyECC("", 1); + byte[] encSk = sdfApi.externalEncryptECC("", publicKey, sk); + + TmkInfo info = new TmkInfo(); + info.setId(IdWorker.getId()); + info.setCreateTime(now); + info.setDeviceSerial(sdfApi.getDeviceInfo("").getDeviceSerial()); + info.setEncTmk(Hex.toHexString(encSk)); + info.setPubKey(Hex.toHexString(publicKey)); + tmkInfoMapper.insert(info); + return; + } + Device device = conned.iterator().next(); + + DeviceContext context = new DeviceContext(); + context.setManufacturer(device.getManufacturer()); + context.setManufacturerModel(device.getManufacturerModel()); + context.setServiceIp(device.getServiceIp()); + context.setServicePort(device.getServicePort()); + SdfApiAdapter sdfApi = SdfApiAdapterFactory.newInstance(context); + String dh = sdfApi.openDevice(); + String sh = sdfApi.openSession(dh); + DeviceInfo deviceInfo = sdfApi.getDeviceInfo(sh); + + byte[] sk = sdfApi.generateRandom(sh, 16); + byte[] publicKey = sdfApi.exportEncPublicKeyECC(sh, 1); + byte[] encSk = sdfApi.externalEncryptECC(sh, publicKey, sk); + + TmkInfo info = new TmkInfo(); + info.setId(IdWorker.getId()); + info.setCreateTime(now); + info.setDeviceSerial(deviceInfo.getDeviceSerial()); + info.setEncTmk(Hex.toHexString(encSk)); + info.setPubKey(Hex.toHexString(publicKey)); + tmkInfoMapper.insert(info); + + // + BcSdfApiAdaptor bcApi = new BcSdfApiAdaptor(); + byte[] bcPubK = bcApi.exportEncPublicKeyECC("", 1); + byte[] bcEncSk = sdfApi.exchangeDigitEnvelopeBaseOnECC(sh, 1, bcPubK, encSk); + + TmkInfo bcinfo = new TmkInfo(); + bcinfo.setId(IdWorker.getId()); + bcinfo.setCreateTime(now); + bcinfo.setDeviceSerial(bcApi.getDeviceInfo("").getDeviceSerial()); + bcinfo.setEncTmk(Hex.toHexString(bcEncSk)); + bcinfo.setPubKey(Hex.toHexString(bcPubK)); + tmkInfoMapper.insert(bcinfo); + sdfApi.closeSession(sh); + sdfApi.closeDevice(dh); + } + 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/service/impl/KeyInfoServiceImpl.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/KeyInfoServiceImpl.java index 7b49f7a..01e97ad 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/KeyInfoServiceImpl.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/KeyInfoServiceImpl.java @@ -282,13 +282,13 @@ public class KeyInfoServiceImpl implements KeyInfoService { record.setCheckValue(checkHash); } else { EccKey eccKey = sdfApiService.genKeyPairEcc(); - byte[] d = eccKey.getPriKey().getD(); + byte[] d = eccKey.getPriKey(); byte[] encD = sdfApiService.encryptByTMK(d); record.setKeyData(Hex.toHexString(encD)); String checkHash = Hex.toHexString(sdfApiService.hash(d)); record.setCheckValue(checkHash); - byte[] pubKeyBytes = eccKey.getPubKey().getPubKeyBytes(); + byte[] pubKeyBytes = eccKey.getPubKey(); record.setPubKey(Hex.toHexString(pubKeyBytes)); record.setPubIdx(record.getPubKey().substring(0, 8)); }