初始化主密钥

This commit is contained in:
liulu 2024-11-11 11:05:46 +08:00
parent 5dd7b9ee7e
commit 4ae46ed32d
10 changed files with 188 additions and 16 deletions

View File

@ -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<Device> {
default List<Device> selectConnedList() {
return selectList(
new LambdaQueryWrapper<Device>()
.eq(Device::getConnected, true)
);
}
}

View File

@ -17,6 +17,7 @@ public class TmkInfo {
private String deviceSerial;
private String encTmk;
private String pubKey;
private String remark;
private LocalDateTime createTime;

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -21,4 +21,7 @@ public interface DeviceService {
void update(DeviceDTO.DeviceSave update);
void delete(Long id);
void initTmk();
}

View File

@ -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<DeviceDTO.DeviceView> 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<Device> 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<Device> wrapper = new LambdaQueryWrapper<Device>()
.eq(Device::getName, name);

View File

@ -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));
}