Merge remote-tracking branch 'origin/V1.00' into V1.00

This commit is contained in:
waner 2026-03-11 14:23:40 +08:00
commit 729bf61856
21 changed files with 1105 additions and 0 deletions

View File

@ -0,0 +1,21 @@
package com.cisd.tms.common.util;
/**
* 字符串工具类
*
*/
public class DivisionUtils {
public static String[] equalDivision(String s,int num){
int len = (int) Math.ceil((double) s.length() / num);
String[] array = new String[num];
int end;
for(int i = 0; i < array.length ;i++){
end = i * len + len;
if(end > s.length()){
end = s.length();
}
array[i] = s.substring(i * len,end);
}
return array;
}
}

View File

@ -0,0 +1,28 @@
package com.cisd.tms.common.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializationUtil {
public static byte[] serializationObject(Object object){
try (ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteArrayOut)){
out.writeObject(object);
return byteArrayOut.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static Object deserializationObject(byte[] object) throws IOException, ClassNotFoundException {
try(ByteArrayInputStream byteArrayIn = new ByteArrayInputStream(object);
ObjectInputStream in = new ObjectInputStream(byteArrayIn)) {
return in.readObject();
} catch (IOException | ClassNotFoundException e) {
throw e;
}
}
}

View File

@ -0,0 +1,13 @@
package com.cisd.tms.modules.mk.common;
/**
* 全局常量
*/
public interface LMKConstant {
int COMPONENT_NUM = 3;
int COMPONENT_LENGTH = 64;
int[] KEY_ORDER = {1,2,3};
int[][] COMB_LIST = new int[][]{{1,2},{1,3},{2,3}};
int LMK_ZONE_NUM = 1;
int LMK_NUM = 50;
}

View File

@ -0,0 +1,118 @@
package com.cisd.tms.modules.mk.controller;
import com.cisd.tms.common.api.ApiResponse;
import com.cisd.tms.modules.mk.dto.LMK;
import com.cisd.tms.modules.mk.dto.MasterKeyRestoreDTO;
import com.cisd.tms.modules.mk.dto.RecoveryResult;
import com.cisd.tms.modules.mk.dto.UKeySignDTO;
import com.cisd.tms.modules.mk.dto.UKeySignEntity;
import com.cisd.tms.modules.mk.dto.UKeySignResult;
import com.cisd.tms.modules.mk.enums.MasterKeyStatus;
import com.cisd.tms.modules.mk.service.LmkService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author liulu
* @since 2026/3/4
*/
@RestController
@RequestMapping("/api/v1")
public class LmkController {
@Resource
private LmkService lmkService;
@Resource
private ObjectMapper objectMapper;
/**
* 生成主密钥
* @return
*/
@PostMapping("/masterkey/generate")
public ApiResponse<LMK> generateMasterKey() {
LMK lmk = lmkService.generateLMK();
return ApiResponse.success(lmk);
}
/**
* UKey签名并获取主密钥组件
* @param uKeySignDTO
* @return
*/
@PostMapping("/masterkey/uKeySignAndKeyComponent")
public ApiResponse<UKeySignResult> signAndKeyComponent(@RequestBody UKeySignDTO uKeySignDTO) {
String iPubKey = lmkService.exportIkPublicKeyHex();
String payload;
try {
payload = objectMapper.writeValueAsString(UKeySignEntity.getInstance(uKeySignDTO, iPubKey));
} catch (JsonProcessingException e) {
throw new IllegalStateException("serialize sign payload failed", e);
}
String signValue = lmkService.signIk(payload);
int uid = Integer.parseInt(uKeySignDTO.getUid());
String components = lmkService.getComponent(uid);
return ApiResponse.success(UKeySignResult.builder().sign(signValue).extra(components).build());
}
@GetMapping("/masterKeyStatus")
public ApiResponse<MasterKeyStatus.StatusDetail> getMasterKeyStatus() {
return ApiResponse.success(lmkService.getMasterKeyStatus());
}
/**
* 恢复主密钥
* @param masterKeyRestoreDTO
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
@PostMapping("/recoveryMasterKey")
public ApiResponse<RecoveryResult> recoveryMasterKey(@RequestBody MasterKeyRestoreDTO masterKeyRestoreDTO)
throws IOException, ClassNotFoundException {
RecoveryResult result;
String mac;
try {
Collection<String> keyComponents = masterKeyRestoreDTO.getComponents().values();
List<String> keyComponentsList = new ArrayList<>(keyComponents);
mac = lmkService.recoveryLMK(keyComponentsList);
result = RecoveryResult.getInstance(false, mac);
} catch (StreamCorruptedException streamCorruptedException) {
String masterKey = lmkService.masterKeyCompose(masterKeyRestoreDTO.getComponents());
mac = lmkService.recoveryLMKAndGenIK(masterKey);
result = RecoveryResult.getInstance(true, mac);
}
return ApiResponse.success(result);
}
/**
* 分量合成恢复主密钥
* @param masterKeyRestoreDTO
* @return
*/
@PostMapping("/masterKeyRecovery")
public ApiResponse<LMK> masterKeyRecovery(@RequestBody MasterKeyRestoreDTO masterKeyRestoreDTO) {
String masterKey = lmkService.masterKeyCompose(masterKeyRestoreDTO.getComponents());
LMK lmk = lmkService.recoveryLMK1(LMK.getInstance(masterKey, masterKeyRestoreDTO));
return ApiResponse.success(lmk);
}
@GetMapping("/destroyLMKAndIK")
public ApiResponse<String> destroyLMKAndIK() {
lmkService.destroyLMKAndIK();
return ApiResponse.success("主密钥和内部密钥销毁成功!");
}
}

View File

@ -0,0 +1,13 @@
package com.cisd.tms.modules.mk.dto;
import lombok.Data;
@Data
public class Key {
private String keySerial;
private int keyLen;
private int lmkIdx;
private int lmkAlgo;
private String schema;
private String key;
}

View File

@ -0,0 +1,84 @@
package com.cisd.tms.modules.mk.dto;
import com.cisd.tms.modules.mk.common.LMKConstant;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class KeyBytesComponent implements Serializable {
private int index;
private byte[] mkComponent;
private byte[] ikAuthComponent;
private byte[] ikDeviceComponent;
public static KeyBytesComponent getInstance(int index, byte[] mk, byte[] ikAuth, byte[] ikDevice){
KeyBytesComponent component = new KeyBytesComponent();
component.setIndex(index);
component.setMkComponent(getComponent(index, mk));
component.setIkAuthComponent(getComponent(index, ikAuth));
component.setIkDeviceComponent(getComponent(index, ikDevice));
return component;
}
/* public static void main(String[] args) {
byte[] mk = new byte[]{ 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0 };
byte[] ikAuth = new byte[]{ 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,};
byte[] ikDevice = new byte[]{ 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0 };
KeyBytesComponent c1 = getInstance(1, mk, ikAuth, ikDevice);
System.out.println(JSON.toJSONString(c1));
KeyBytesComponent c2 = getInstance(2, mk, ikAuth, ikDevice);
System.out.println(JSON.toJSONString(c2));
KeyBytesComponent c3 = getInstance(3, mk, ikAuth, ikDevice);
System.out.println(JSON.toJSONString(c3));
KeyBytesComponent result = getInstance(Arrays.asList(c1,c2,c3));
System.out.println(JSON.toJSONString(result));
}*/
public static byte[] getComponent(int index, byte[] key){
int len = key.length / LMKConstant.COMPONENT_NUM;
int start = (index - 1) * len;
if(index == LMKConstant.COMPONENT_NUM){
len += key.length % LMKConstant.COMPONENT_NUM;
}
byte[] component = new byte[len];
System.arraycopy(key, start, component, 0, len);
return component;
}
public static KeyBytesComponent getInstance(List<KeyBytesComponent> keyBytesComponentList){
byte[][] mkComponents = new byte[keyBytesComponentList.size()][];
byte[][] ikAuthComponents = new byte[keyBytesComponentList.size()][];
byte[][] ikDeviceComponents = new byte[keyBytesComponentList.size()][];
for(int i = 0; i < keyBytesComponentList.size(); i++){
for(KeyBytesComponent k : keyBytesComponentList){
if(k.getIndex() == (i + 1)){
mkComponents[i] = k.getMkComponent();
ikAuthComponents[i] = k.getIkAuthComponent();
ikDeviceComponents[i] = k.getIkDeviceComponent();
}
}
}
KeyBytesComponent all = new KeyBytesComponent();
all.setMkComponent(merge(mkComponents));
all.setIkAuthComponent(merge(ikAuthComponents));
all.setIkDeviceComponent(merge(ikDeviceComponents));
return all;
}
public static byte[] merge(byte[][] arrays){
int len = 0;
for(int i = 0; i < arrays.length; i++){
len += arrays[i].length;
}
byte[] result = new byte[len];
int index = 0;
for(int i = 0; i < arrays.length; i++){
System.arraycopy(arrays[i], 0, result, index, arrays[i].length);
index += arrays[i].length;
}
return result;
}
}

View File

@ -0,0 +1,57 @@
package com.cisd.tms.modules.mk.dto;
import com.cisd.tms.modules.mk.common.LMKConstant;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class KeyComponent implements Serializable {
private Map<Integer, String> lmkComponent;
private Map<Integer, String> authKeyComponent;
private Map<Integer, String> deviceKeyComponent;
// public static KeyComponent getFromJSON(String json){
// return JSON.parseObject(json, KeyComponent.class);
// }
public static List<KeyComponent> getInstances(
Map<Integer, String> lmkComponent,Map<Integer, String> authKeyComponent,Map<Integer, String> deviceKeyComponent){
List<KeyComponent> keyComponentList = new ArrayList<>();
KeyComponent keyComponent = null;
for(int[] arr : LMKConstant.COMB_LIST){
keyComponent = new KeyComponent(new HashMap<>(),new HashMap<>(),new HashMap<>());
for(int i : arr){
keyComponent.lmkComponent.put(i,lmkComponent.get(i));
keyComponent.authKeyComponent.put(i,authKeyComponent.get(i));
keyComponent.deviceKeyComponent.put(i,deviceKeyComponent.get(i));
}
keyComponentList.add(keyComponent);
}
return keyComponentList;
}
public static void main(String[] args) {
List<KeyComponent> result = getInstances(new HashMap<Integer, String>(){{
put(1,"1");
put(2,"2");
put(3,"3");
}},new HashMap<Integer, String>(){{
put(1,"4");
put(2,"5");
put(3,"6");
}},new HashMap<Integer, String>(){{
put(1,"7");
put(2,"8");
put(3,"9");
}});
}
}

View File

@ -0,0 +1,78 @@
package com.cisd.tms.modules.mk.dto;
import lombok.Data;
/**
* 主秘钥信息实体
*/
@Data
public class LMK {
/**
* 主密钥48 字节注意这里的主密钥是完整的主密钥不是主密钥分量
*/
private String pcLmk;
/**
* 主秘钥长度
*/
private int piLmkLen;
/**
* 设备公钥132 字节
*/
private String pcDevPubkey;
/**
* 设备公钥长度
*/
private int iDevPubKeyLen;
/**
* 设备私钥68 字节
*/
private String pcDevPrikey;
/**
* 设备私钥长度
*/
private int iDevPriKeyLen;
/**
* 主秘钥校验值
*/
private String ucSessionKey;
/**
* 认证密钥对
*/
private String AuthKeyPair;
public static LMK getInstance(String masterKey, MasterKeyRestoreDTO masterKeyRestoreDTO){
LMK lmk = new LMK();
lmk.setPcLmk(masterKey);
lmk.setPiLmkLen(masterKey.length() / 2);
if (masterKeyRestoreDTO.getPcDevPubkey() == null || masterKeyRestoreDTO.getPcDevPubkey().equals("")){
lmk.setPcDevPubkey("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
lmk.setIDevPubKeyLen(132);
}else {
lmk.setPcDevPubkey(masterKeyRestoreDTO.getPcDevPubkey());
lmk.setIDevPubKeyLen(masterKeyRestoreDTO.getiDevPubKeyLen());
}
if (masterKeyRestoreDTO.getPcDevPrikey() == null || masterKeyRestoreDTO.getPcDevPrikey().equals("")){
lmk.setPcDevPrikey("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
lmk.setIDevPriKeyLen(68);
}else {
lmk.setPcDevPrikey(masterKeyRestoreDTO.getPcDevPrikey());
lmk.setIDevPriKeyLen(masterKeyRestoreDTO.getiDevPriKeyLen());
}
return lmk;
}
public static LMK getInstance(String ucSessionKey){
LMK lmk = getInstance("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",new MasterKeyRestoreDTO());
lmk.ucSessionKey = ucSessionKey;
lmk.AuthKeyPair = "";
return lmk;
}
}

View File

@ -0,0 +1,54 @@
package com.cisd.tms.modules.mk.dto;
import com.cisd.tms.modules.mk.common.LMKConstant;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Data
@AllArgsConstructor
public class LMKAndIK {
private String lmk;
private String authKey;
private String deviceKey;
public static LMKAndIK getInstance(List<KeyComponent> keyComponentList){
Map<Integer,String> lmkComponents = new HashMap<>();
Map<Integer,String> authKeyComponents = new HashMap<>();
Map<Integer,String> deviceKeyComponents = new HashMap<>();
Map<Integer,String> lmkCompParts = null;
Map<Integer,String> authKeyCompParts = null;
Map<Integer,String> deviceKeyCompParts = null;
for(KeyComponent kc : keyComponentList){
lmkCompParts = kc.getLmkComponent();
authKeyCompParts = kc.getAuthKeyComponent();
deviceKeyCompParts = kc.getDeviceKeyComponent();
for(int i : lmkCompParts.keySet()){
lmkComponents.put(i,lmkCompParts.get(i));
}
for(int i : authKeyCompParts.keySet()){
authKeyComponents.put(i,authKeyCompParts.get(i));
}
for(int i : deviceKeyCompParts.keySet()){
deviceKeyComponents.put(i,deviceKeyCompParts.get(i));
}
}
if(lmkComponents.size() < 3 || authKeyComponents.size() < 3 || deviceKeyComponents.size() < 3){
throw new IllegalArgumentException("主密钥或内部密钥分量缺失");
}
StringBuilder lmk = new StringBuilder();
StringBuilder authKey = new StringBuilder();
StringBuilder deviceKey = new StringBuilder();
for(int i = 0; i < LMKConstant.COMPONENT_NUM; i++){
lmk.append(lmkComponents.get(LMKConstant.KEY_ORDER[i]));
authKey.append(authKeyComponents.get(LMKConstant.KEY_ORDER[i]));
deviceKey.append(deviceKeyComponents.get(LMKConstant.KEY_ORDER[i]));
}
return new LMKAndIK(lmk.toString(),authKey.toString(), deviceKey.toString());
}
}

View File

@ -0,0 +1,96 @@
package com.cisd.tms.modules.mk.dto;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MasterKeyRestoreDTO {
/**
* 签名原始值及签名值
*/
private List<UKeySignVerifyDTO> uKeySignVerifyDTOList;
/**
* 设备公钥132 字节
*/
private String pcDevPubkey;
/**
* 设备公钥长度
*/
private int iDevPubKeyLen;
/**
* 设备私钥68 字节
*/
private String pcDevPrikey;
/**
* 设备私钥长度
*/
private int iDevPriKeyLen;
/**
* 认证密钥对
*/
private String keyPair;
public String getKeyPair() {
return keyPair;
}
public void setKeyPair(String keyPair) {
this.keyPair = keyPair;
}
public List<UKeySignVerifyDTO> getuKeySignVerifyDTOList() {
return uKeySignVerifyDTOList;
}
public void setuKeySignVerifyDTOList(List<UKeySignVerifyDTO> uKeySignVerifyDTOList) {
this.uKeySignVerifyDTOList = uKeySignVerifyDTOList;
}
public String getPcDevPubkey() {
return pcDevPubkey;
}
public void setPcDevPubkey(String pcDevPubkey) {
this.pcDevPubkey = pcDevPubkey;
}
public int getiDevPubKeyLen() {
return iDevPubKeyLen;
}
public void setiDevPubKeyLen(int iDevPubKeyLen) {
this.iDevPubKeyLen = iDevPubKeyLen;
}
public String getPcDevPrikey() {
return pcDevPrikey;
}
public void setPcDevPrikey(String pcDevPrikey) {
this.pcDevPrikey = pcDevPrikey;
}
public int getiDevPriKeyLen() {
return iDevPriKeyLen;
}
public void setiDevPriKeyLen(int iDevPriKeyLen) {
this.iDevPriKeyLen = iDevPriKeyLen;
}
public Map<String,String> getComponents() {
Map<String,String> componentMap = new HashMap<>();
for(UKeySignVerifyDTO uKeySignVerifyDTO : uKeySignVerifyDTOList){
if(null == uKeySignVerifyDTO.getKeyComponent()){
throw new IllegalArgumentException("UKey无主密钥分量,UID:" + uKeySignVerifyDTO.getuKeySignDTO().getUid());
}
componentMap.put(uKeySignVerifyDTO.getuKeySignDTO().getUid(),uKeySignVerifyDTO.getKeyComponent());
}
return componentMap;
}
}

View File

@ -0,0 +1,16 @@
package com.cisd.tms.modules.mk.dto;
import lombok.Data;
@Data
public class RecoveryResult {
private boolean needNewUKey;
private String mac;
public static RecoveryResult getInstance(boolean needNewUKey, String mac) {
RecoveryResult result = new RecoveryResult();
result.needNewUKey = needNewUKey;
result.mac = mac;
return result;
}
}

View File

@ -0,0 +1,82 @@
package com.cisd.tms.modules.mk.dto;
import lombok.Data;
@Data
public class UKey {
/**
* 用户 ID, 可以为空
*/
private String uid;
/**
* 角色 ID
*/
private String rid;
/**
* 设备公钥 HEX32 字节 x + 32 字节 y
*/
private String dev_pk;
/**
* U 盾公钥 HEX32 字节 x + 32 字节 y
*/
private String ukey_pk;
/**
* 前端随机数 ra
*/
private Long ra;
/**
* 缓存随机数 rb
*/
private Long rb;
/**
* 签名
*/
private String sa;
/**
* 临时结果
*/
private boolean result;
public String getAuthKey(){
return this.uid;
}
@Data
public static class AuthResult{
/**
* 认证结果true成功false失败
*/
private boolean result;
/**
* 是否当前主机操作truefalse
*/
private boolean isOperator;
/**
* 单个 U 盾重试次数
*/
private int retryNum = 3;
/**
* token用于访问验证
*/
private String token;
private AuthResult(boolean _result,boolean _isOperator){
this.isOperator = _isOperator;
this.result = _result;
}
public static AuthResult get(boolean _result,boolean _isOperator){
return new AuthResult(_result,_isOperator);
}
public AuthResult and(boolean result){
this.result = this.result && result;
return this;
}
}
}

View File

@ -0,0 +1,34 @@
package com.cisd.tms.modules.mk.dto;
import lombok.Data;
/**
* 发行UKey时前端传输的信息
*/
@Data
public class UKeySignDTO {
/**
* UKey 公钥
*/
private String pubKey;
/**
* 签名的角色
*/
private String role;
/**
* UKey 中的认证信息
*/
private String uid;
/**
* UKey 中的认证信息
*/
private String rid;
/**
* 需要处理的其他信息不参与签名这里是主密钥复制是暂时存储的分量
*/
private String extra;
}

View File

@ -0,0 +1,42 @@
package com.cisd.tms.modules.mk.dto;
import lombok.Builder;
import lombok.Data;
/**
* UKey签名实体在发行密钥时对该实体的JSON字符串进行签名
*/
@Data
@Builder
public class UKeySignEntity {
/**
* UKey公钥前端传输
*/
private String pubKey;
/**
* 认证密钥对
*/
private String authKeyPair;
/**
* 登录角色名称superadminkeyadminconfigadminauditadmin
*/
private String role;
/**
* 登录时传输
*/
private String uid;
/**
* 登录时传输
*/
private String rid;
public static UKeySignEntity getInstance(UKeySignDTO uKeySignDTO,String authKeyPair){
return UKeySignEntity.builder()
.pubKey(uKeySignDTO.getPubKey())
.authKeyPair(authKeyPair)
.role(uKeySignDTO.getRole())
.uid(uKeySignDTO.getUid())
.rid(uKeySignDTO.getRid())
.build();
}
}

View File

@ -0,0 +1,21 @@
package com.cisd.tms.modules.mk.dto;
import lombok.Builder;
import lombok.Data;
/**
* UKey发行结果
*/
@Data
@Builder
public class UKeySignResult {
/**
* 签名值
*/
private String sign;
/**
* 额外的数据比如主密钥分量
*/
private String extra;
}

View File

@ -0,0 +1,43 @@
package com.cisd.tms.modules.mk.dto;
public class UKeySignVerifyDTO {
/**
* 主密钥分量合成主密钥时使用
*/
private String keyComponent;
/**
* 签名原始数据
*/
private UKeySignDTO uKeySignDTO;
/**
* UKey 签名
*/
private String sign;
public String getKeyComponent() {
return keyComponent;
}
public void setKeyComponent(String keyComponent) {
this.keyComponent = keyComponent;
}
public UKeySignDTO getuKeySignDTO() {
return uKeySignDTO;
}
public void setuKeySignDTO(UKeySignDTO uKeySignDTO) {
this.uKeySignDTO = uKeySignDTO;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
}

View File

@ -0,0 +1,18 @@
package com.cisd.tms.modules.mk.enums;
import lombok.Getter;
@Getter
public enum IKEnums {
KEY_TYPE_DEVICE(0x00000001,"设备密钥对"),
KEY_TYPE_AUTH(0x00000002,"认证密钥对")
;
int code;
String desc;
IKEnums(int _code, String _desc){
this.code = _code;
this.desc = _desc;
}
}

View File

@ -0,0 +1,14 @@
package com.cisd.tms.modules.mk.enums;
import lombok.Getter;
@Getter
public enum LMKType {
LMK_TYPE_CUR(0x00000001),
LMK_TYPE_TMP(0x00000002)
;
final int code;
LMKType(int _code){
this.code = _code;
}
}

View File

@ -0,0 +1,6 @@
package com.cisd.tms.modules.mk.enums;
public enum LmkInitType {
GEN,
SET;
}

View File

@ -0,0 +1,46 @@
package com.cisd.tms.modules.mk.enums;
import lombok.Data;
import lombok.Getter;
public enum MasterKeyStatus {
NORMAL(0, "已生成"),
ABNORMAL(1, "未生成");
MasterKeyStatus(int code, String desc) {
this.code = code;
this.desc = desc;
}
@Getter
private final int code;
@Getter
private final String desc;
public StatusDetail getDetail() {
return new StatusDetail(this.code, this.desc);
}
public StatusDetail getDetail(String ucSessionKey) {
return new StatusDetail(this.code, this.desc, ucSessionKey);
}
@Data
public static class StatusDetail {
private int code;
private String desc;
private String ucSessionKey;
public StatusDetail(int code, String desc) {
this.code = code;
this.desc = desc;
}
public StatusDetail(int code, String desc, String ucSessionKey) {
this.code = code;
this.desc = desc;
this.ucSessionKey = ucSessionKey;
}
}
}

View File

@ -0,0 +1,221 @@
package com.cisd.tms.modules.mk.service;
import com.cisd.tms.common.util.DivisionUtils;
import com.cisd.tms.common.util.SerializationUtil;
import com.cisd.tms.integration.crypto.pcie.jna.EccRefPublicKey;
import com.cisd.tms.integration.crypto.pcie.jna.EccSignature;
import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult;
import com.cisd.tms.integration.crypto.pcie.model.EccInternalSignRequest;
import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService;
import com.cisd.tms.modules.mk.common.LMKConstant;
import com.cisd.tms.modules.mk.dto.KeyComponent;
import com.cisd.tms.modules.mk.dto.LMK;
import com.cisd.tms.modules.mk.dto.LMKAndIK;
import com.cisd.tms.modules.mk.enums.IKEnums;
import com.cisd.tms.modules.mk.enums.MasterKeyStatus;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author liulu
* @since 2026/3/5
*/
@Slf4j
@Service
public class LmkService {
// private List<KeyComponent> keyComponentList;
private List<String> keyComponentList;
private static final int AUTH_SIGN_KEY_INDEX = IKEnums.KEY_TYPE_AUTH.getCode();
@Resource
private PcieCryptoService pcieCryptoService;
/**
* 生成主秘钥
*/
public LMK generateLMK() {
// todo 生成主密钥前删除所有的对称和非对称密钥
// this.delAllKey();
//生成主密钥
pcieCryptoService.generateLmk();
//生成内部密钥
pcieCryptoService.generateIk(IKEnums.KEY_TYPE_AUTH.getCode());
pcieCryptoService.generateIk(IKEnums.KEY_TYPE_DEVICE.getCode());
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
log.error("sleep error");
}
pcieCryptoService.loadLmk();
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
log.error("sleep error");
}
backUp();
// iLmkService.generateLMKAndIK(null)
// .load()
// .backUp(0,0);
byte[] seedMac = pcieCryptoService.exportLmkSeedMac();
// LmkKey lmkKey = soLibraryAdapter.getLmkKeySession();
log.info("主密钥校验值:" + Hex.toHexString(seedMac));
return LMK.getInstance(Hex.toHexString(seedMac));
}
public void backUp() {
BackupDataResult lmkEx = pcieCryptoService.backupLmkEx(56);
String lmk = Hex.toHexString(lmkEx.getData());
// todo 获取内部密钥
BackupDataResult ikAuthEx = pcieCryptoService.backupLmkEx(56);
String authKey = Hex.toHexString(ikAuthEx.getData());
BackupDataResult ikDeviceEx = pcieCryptoService.backupLmkEx(56);
String deviceKey = Hex.toHexString(ikDeviceEx.getData());
// BackupDataResult ikAuthEx = pcieCryptoService.backupIk(IKEnums.KEY_TYPE_AUTH.getCode());
// String authKey = Hex.toHexString(ikAuthEx.getData());
// BackupDataResult ikEx = pcieCryptoService.backupIk(IKEnums.KEY_TYPE_DEVICE.getCode());
// String deviceKey = Hex.toHexString(ikEx .getData());
this.splitKey(lmk, authKey, deviceKey);
}
private void splitKey(String lmk,String authKey,String deviceKey){
//平分内部密钥和主密钥并编号
Map<Integer, String> lmkComponentMap = new HashMap<>();
Map<Integer, String> authKeyComponentMap = new HashMap<>();
Map<Integer, String> deviceKeyComponentMap = new HashMap<>();
String[] lmkComponents = DivisionUtils.equalDivision(lmk, LMKConstant.COMPONENT_NUM);
String[] authKeyComponents = DivisionUtils.equalDivision(authKey,LMKConstant.COMPONENT_NUM);
String[] deviceKeyComponents = DivisionUtils.equalDivision(deviceKey,LMKConstant.COMPONENT_NUM);
//这里内部密钥和主密钥map的key是123表示切分后按该顺序拼接
for(int i = 0; i < LMKConstant.COMPONENT_NUM; i++){
lmkComponentMap.put(LMKConstant.KEY_ORDER[i],lmkComponents[i]);
authKeyComponentMap.put(LMKConstant.KEY_ORDER[i],authKeyComponents[i]);
deviceKeyComponentMap.put(LMKConstant.KEY_ORDER[i],deviceKeyComponents[i]);
}
//组合分割后的主密钥和内部密钥
List<KeyComponent> keyComponentList = KeyComponent.getInstances(lmkComponentMap,authKeyComponentMap,deviceKeyComponentMap);
List<String> result = new ArrayList<>();
keyComponentList.forEach(k -> result.add(Base64.getEncoder().encodeToString(SerializationUtil.serializationObject(k))));
this.keyComponentList = result;
}
public String exportIkPublicKeyHex() {
int outBufferSize = new EccRefPublicKey().size();
BackupDataResult result = pcieCryptoService.exportSignPublicKeyEcc(AUTH_SIGN_KEY_INDEX, outBufferSize);
return Hex.toHexString(result.getData());
}
public String signIk(String rawData) {
EccInternalSignRequest request = new EccInternalSignRequest();
request.setKeyIndex(AUTH_SIGN_KEY_INDEX);
request.setData(rawData.getBytes(StandardCharsets.UTF_8));
request.setSignatureBufferSize(new EccSignature().size());
BackupDataResult result = pcieCryptoService.eccInternalSign(request);
return Hex.toHexString(result.getData());
}
public String getComponent(int uid) {
if (keyComponentList == null || keyComponentList.isEmpty()) {
throw new IllegalStateException("key components not initialized");
}
int index = uid - 1;
if (index < 0 || index >= keyComponentList.size()) {
throw new IllegalArgumentException("invalid component index: " + uid);
}
return keyComponentList.get(index);
}
public String masterKeyCompose(Map<String, String> componentMap) {
StringBuilder lmk = new StringBuilder();
for (int i = 0; i < LMKConstant.COMPONENT_NUM; i++) {
lmk.append(componentMap.get(String.valueOf(LMKConstant.KEY_ORDER[i])));
}
return lmk.toString();
}
public String recoveryLMK(List<String> keyComponents) throws IOException, ClassNotFoundException {
List<KeyComponent> componentList = new ArrayList<>();
for (String component : keyComponents) {
byte[] raw;
try {
raw = Base64.getDecoder().decode(component);
} catch (IllegalArgumentException e) {
StreamCorruptedException ex = new StreamCorruptedException("invalid component encoding");
ex.initCause(e);
throw ex;
}
try {
Object obj = SerializationUtil.deserializationObject(raw);
componentList.add((KeyComponent) obj);
} catch (ClassCastException e) {
StreamCorruptedException ex = new StreamCorruptedException("invalid component payload");
ex.initCause(e);
throw ex;
} catch (StreamCorruptedException e) {
throw e;
}
}
LMKAndIK lmkAndIK = LMKAndIK.getInstance(componentList);
pcieCryptoService.recoverLmkEx(Hex.decode(lmkAndIK.getLmk()));
pcieCryptoService.loadLmk();
byte[] seedMac = pcieCryptoService.exportLmkSeedMac();
return Hex.toHexString(seedMac);
}
public String recoveryLMKAndGenIK(String lmkComponentHex) {
pcieCryptoService.recoverLmkEx(Hex.decode(lmkComponentHex));
pcieCryptoService.generateIk(IKEnums.KEY_TYPE_AUTH.getCode());
pcieCryptoService.generateIk(IKEnums.KEY_TYPE_DEVICE.getCode());
pcieCryptoService.loadLmk();
byte[] seedMac = pcieCryptoService.exportLmkSeedMac();
return Hex.toHexString(seedMac);
}
public LMK recoveryLMK1(LMK lmk) {
pcieCryptoService.recoverLmkEx(Hex.decode(lmk.getPcLmk()));
pcieCryptoService.loadLmk();
byte[] seedMac = pcieCryptoService.exportLmkSeedMac();
lmk.setUcSessionKey(Hex.toHexString(seedMac));
return lmk;
}
public void destroyLMKAndIK() {
pcieCryptoService.destroyLmk();
pcieCryptoService.destroyIk(IKEnums.KEY_TYPE_AUTH.getCode());
pcieCryptoService.destroyIk(IKEnums.KEY_TYPE_DEVICE.getCode());
keyComponentList = null;
}
public MasterKeyStatus.StatusDetail getMasterKeyStatus() {
boolean ok = pcieCryptoService.checkLmk();
MasterKeyStatus status = ok ? MasterKeyStatus.NORMAL : MasterKeyStatus.ABNORMAL;
if (ok) {
String mac = Hex.toHexString(pcieCryptoService.exportLmkSeedMac());
return status.getDetail(mac);
}
return status.getDetail();
}
}