主密钥初始化
This commit is contained in:
@@ -235,6 +235,10 @@ public interface PcieNativeLibrary extends Library {
|
||||
|
||||
int SDFE_StatusIK(Pointer hSessionHandle, int keyType, IntByReference keyState);
|
||||
|
||||
int SYD_IK_BackUp(Pointer hDeviceHandle, int keyType, int exFlag, SydIkComponent ikComponent);
|
||||
|
||||
int SYD_IK_Recover(Pointer hDeviceHandle, int keyType, int exFlag, SydIkComponent ikComponent);
|
||||
|
||||
int SDFE_GenerateUkey(Pointer hSessionHandle, byte adminIndex,
|
||||
byte[] ukeyPin, int ukeyPinLen,
|
||||
byte[] loginPin, int loginPinLen);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.cisd.tms.integration.crypto.pcie.jna;
|
||||
|
||||
import com.sun.jna.Structure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Structure.FieldOrder({"component", "mac"})
|
||||
public class SydIkComponent extends Structure {
|
||||
|
||||
public static final int COMPONENT_COUNT = 3;
|
||||
public static final int COMPONENT_LENGTH = 64;
|
||||
|
||||
public byte[] component = new byte[COMPONENT_COUNT * COMPONENT_LENGTH];
|
||||
public byte[] mac = new byte[8];
|
||||
|
||||
@Override
|
||||
protected List<String> getFieldOrder() {
|
||||
return List.of("component", "mac");
|
||||
}
|
||||
}
|
||||
+41
-3
@@ -20,6 +20,7 @@ import com.cisd.tms.integration.crypto.pcie.jna.SdfeDeviceStatus;
|
||||
import com.cisd.tms.integration.crypto.pcie.jna.SdfeKekComponent;
|
||||
import com.cisd.tms.integration.crypto.pcie.jna.SdfeLmkComponent;
|
||||
import com.cisd.tms.integration.crypto.pcie.jna.SdfeLoginState;
|
||||
import com.cisd.tms.integration.crypto.pcie.jna.SydIkComponent;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.AgreementDataAndKeyEccResult;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.ChangePrivateKeyPasswordRequest;
|
||||
@@ -199,7 +200,7 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
public byte[] initializeMasterKey(byte[] oldPin, byte[] newPin) {
|
||||
byte[] oldPinValue = requireNonEmptyBytes("oldPin", oldPin);
|
||||
byte[] newPinValue = requireNonEmptyBytes("newPin", newPin);
|
||||
|
||||
//lmk初始化包含主密钥生成、加载;内部密钥生成;用户密钥生成;返回主密钥校验值。
|
||||
try {
|
||||
return sessionTemplate.withSession("SDFE_InitializeMasterKey", (lib, deviceHandle, sessionHandle) -> {
|
||||
sessionTemplate.ensureSuccess(
|
||||
@@ -210,7 +211,14 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
sessionTemplate.ensureSuccess("SDFE_LoadLMK", lib.SDFE_LoadLMK(sessionHandle));
|
||||
sessionTemplate.ensureSuccess("SDFE_GenerateIK", lib.SDFE_GenerateIK(sessionHandle, IK_KEY_TYPE_DEVICE));
|
||||
sessionTemplate.ensureSuccess("SDFE_GenerateIK", lib.SDFE_GenerateIK(sessionHandle, IK_KEY_TYPE_AUTH));
|
||||
|
||||
sessionTemplate.ensureSuccess(
|
||||
"SDFE_GenerateKeyPair_ECC",
|
||||
lib.SDFE_GenerateKeyPair_ECC(sessionHandle, 256, 1, PcieUserKeyType.SIGN.getCode())
|
||||
);
|
||||
sessionTemplate.ensureSuccess(
|
||||
"SDFE_GenerateKeyPair_ECC",
|
||||
lib.SDFE_GenerateKeyPair_ECC(sessionHandle, 256, 1, PcieUserKeyType.ENC.getCode())
|
||||
);
|
||||
int retCode = lib.SDFE_CheckLMK(sessionHandle);
|
||||
if (retCode != 0) {
|
||||
if ((retCode & 0xFF) == SDFE_INIT_STATUS_LOW_BYTE) {
|
||||
@@ -331,7 +339,8 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
|
||||
int keyIndex = requireNonNegative("keyIndex", req.getKeyIndex());
|
||||
int keyType = requireUserKeyType(req.getKeyType());
|
||||
|
||||
//keyType: 1-加密密钥对;0-签名密钥对
|
||||
//keyIndex:[1,8]
|
||||
sessionTemplate.withSession("SDFE_GenerateKeyPair_ECC", (lib, deviceHandle, sessionHandle) -> {
|
||||
sessionTemplate.ensureSuccess(
|
||||
"SDFE_GenerateKeyPair_ECC",
|
||||
@@ -467,6 +476,7 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
public BackupDataResult backupUserKey(int keyIndex, int keyType, int outBufferSize) {
|
||||
int safeKeyIndex = requireNonNegative("keyIndex", keyIndex);
|
||||
int safeKeyType = requireUserKeyType(keyType);
|
||||
//size: 120
|
||||
int safeOutBufferSize = requirePositive("outBufferSize", outBufferSize);
|
||||
|
||||
return sessionTemplate.withSession("SDFE_BackupUserKey", (lib, deviceHandle, sessionHandle) -> {
|
||||
@@ -1679,6 +1689,30 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public BackupDataResult backupIkComponent(int keyType) {
|
||||
int safeKeyType = requireNonNegative("keyType", keyType);
|
||||
|
||||
//todo 对接真实接口
|
||||
return sessionTemplate.withSession("SYD_IK_BackUp", (lib, deviceHandle, sessionHandle) -> {
|
||||
SydIkComponent output = new SydIkComponent();
|
||||
sessionTemplate.ensureSuccess("SYD_IK_BackUp", lib.SYD_IK_BackUp(deviceHandle, safeKeyType, 1, output));
|
||||
byte[] outputBytes = toBytes(output);
|
||||
return toBackupResult("SYD_IK_BackUp", outputBytes, outputBytes.length);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recoverIkComponent(int keyType, byte[] ikComponent) {
|
||||
int safeKeyType = requireNonNegative("keyType", keyType);
|
||||
SydIkComponent input = toSydIkComponent("ikComponent", ikComponent);
|
||||
|
||||
sessionTemplate.withSession("SYD_IK_Recover", (lib, deviceHandle, sessionHandle) -> {
|
||||
sessionTemplate.ensureSuccess("SYD_IK_Recover", lib.SYD_IK_Recover(deviceHandle, safeKeyType, 1, input));
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void backupIk(int keyType) {
|
||||
int safeKeyType = requireNonNegative("keyType", keyType);
|
||||
@@ -2129,6 +2163,10 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
return toStructure(name, value, new SdfeLmkComponent(), false);
|
||||
}
|
||||
|
||||
private static SydIkComponent toSydIkComponent(String name, byte[] value) {
|
||||
return toStructure(name, value, new SydIkComponent(), false);
|
||||
}
|
||||
|
||||
private static EnvelopedKeyBlob toEnvelopedKeyBlob(String name, byte[] value) {
|
||||
return toStructure(name, value, new EnvelopedKeyBlob(), true);
|
||||
}
|
||||
|
||||
@@ -707,6 +707,18 @@ public class MockPcieCryptoService implements PcieCryptoService {
|
||||
requireNonNegative("keyType", keyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BackupDataResult backupIkComponent(int keyType) {
|
||||
requireNonNegative("keyType", keyType);
|
||||
return mockBackup(new com.cisd.tms.integration.crypto.pcie.jna.SydIkComponent().size(), keyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recoverIkComponent(int keyType, byte[] ikComponent) {
|
||||
requireNonNegative("keyType", keyType);
|
||||
requireNonEmptyBytes("ikComponent", ikComponent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void backupIk(int keyType) {
|
||||
requireNonNegative("keyType", keyType);
|
||||
|
||||
@@ -217,6 +217,10 @@ public interface PcieCryptoService {
|
||||
|
||||
void generateIk(int keyType);
|
||||
|
||||
BackupDataResult backupIkComponent(int keyType);
|
||||
|
||||
void recoverIkComponent(int keyType, byte[] ikComponent);
|
||||
|
||||
void backupIk(int keyType);
|
||||
|
||||
void recoverIk(int keyType);
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/init")
|
||||
@Tag(name = "CISD初始化任务", description = "初始化模板、预检、任务创建、执行与日志查询接口")
|
||||
@Tag(name = "CISD配置初始化和重置任务", description = "初始化和重置任务创建、执行与日志查询接口")
|
||||
public class InitController {
|
||||
|
||||
private final InitService initService;
|
||||
|
||||
@@ -162,6 +162,7 @@ public class InitService {
|
||||
}
|
||||
|
||||
String productType = resolvePresetProductType();
|
||||
//todo 验证是否已经初始化
|
||||
validateCommon(request);
|
||||
validateByProductType(productType, request);
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.cisd.tms.modules.mk.controller;
|
||||
import com.cisd.tms.common.api.ApiResponse;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyBackupMaterial;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyRecoverRequest;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyBackupPacket;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyRecoverPacketsRequest;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyStateResult;
|
||||
import com.cisd.tms.modules.mk.dto.UKeySignDTO;
|
||||
import com.cisd.tms.modules.mk.dto.UKeySignEntity;
|
||||
@@ -14,16 +16,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2026/3/4
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/v1")
|
||||
@Tag(name = "主密钥管理", description = "LMK 生成、恢复、状态查询和销毁接口")
|
||||
@@ -56,31 +56,49 @@ public class LmkController {
|
||||
return ApiResponse.success(lmkService.queryMasterKeyStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 备份全部密钥中的单份分量包。
|
||||
* 该接口需要按 uid=1、2、3 分别调用三次:
|
||||
* uid=1 返回第 1 份分量包,uid=2 返回第 2 份分量包,uid=3 返回第 3 份分量包。
|
||||
* 每份分量包中同时包含 LMK、IK_AUTH、IK_DEVICE、USER_SIGN、USER_ENC 的对应分量。
|
||||
*/
|
||||
@PostMapping("/masterKey/backup")
|
||||
@Operation(summary = "备份主密钥分量至UKey", description = "根据请求中的 UKey 身份信息生成签名,并按照 uid 作为分量索引返回对应的主密钥分量,同时返回恢复 LMK 必需的 lmkMac。uid 取值为 1、2、3。")
|
||||
@Operation(summary = "备份密钥分量至UKey", description = "根据请求中的 UKey 身份信息生成签名,并按照 uid 作为分量索引返回对应的一份全量分量包。uid 取值为 1、2、3,需调用三次分别保存到三个外部 UKey 中。返回结果中的 backupPacket 即本次应保存的分量包。")
|
||||
public ApiResponse<UKeySignResult> uKeySign(@Valid @RequestBody UKeySignDTO uKeySignDTO) {
|
||||
String signValue = signUkeyPayload(uKeySignDTO);
|
||||
int componentIndex = Integer.parseInt(uKeySignDTO.getUid());
|
||||
MasterKeyBackupMaterial material = lmkService.getBackupMaterial(componentIndex);
|
||||
MasterKeyBackupPacket packet = lmkService.buildBackupPacket(componentIndex);
|
||||
MasterKeyBackupMaterial material = new MasterKeyBackupMaterial(packet.getLmk().getComponent(), packet.getLmk().getLmkMac());
|
||||
return ApiResponse.success(UKeySignResult.builder()
|
||||
.sign(signValue)
|
||||
.component(material.getComponent())
|
||||
.lmkMac(material.getLmkMac())
|
||||
// .component(material.getComponent())
|
||||
// .lmkMac(material.getLmkMac())
|
||||
.backupPacket(packet)
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复主密钥。
|
||||
* 请求体需同时传入 lmkMac 和 3 个按顺序排列的主密钥分量字符串。
|
||||
* 第 1 个元素对应分量 1,第 2 个元素对应分量 2,第 3 个元素对应分量 3。
|
||||
* 恢复所有备份密钥。
|
||||
* 请求体需传入 componentIndex=1/2/3 的三份分量包。
|
||||
* 服务端会先执行 InitIdentify,然后依次恢复 LMK、加载 LMK、恢复 IK、恢复用户密钥。
|
||||
*/
|
||||
@PostMapping("/masterKey/recover")
|
||||
@Operation(summary = "恢复 LMK", description = "请求体需传入 8 字节校验值 lmkMac 和 3 个按顺序排列的主密钥分量字符串,列表下标 0、1、2 分别对应分量 1、2、3。服务端按 SDFE_LmkComponent 结构拼接后执行恢复并加载 LMK。")
|
||||
public ApiResponse<Void> recoverLmkEx(@Valid @RequestBody MasterKeyRecoverRequest request) {
|
||||
lmkService.recoverLmkEx(request.getLmkMac(), request.getComponents());
|
||||
@Operation(summary = "恢复全部密钥", description = "请求体需传入三份按 componentIndex 标识的分量包。三份分量包必须分别对应 componentIndex=1、2、3。服务端会依次恢复 LMK、IK 和用户密钥。")
|
||||
public ApiResponse<Void> recoverLmkEx(@Valid @RequestBody MasterKeyRecoverPacketsRequest request) {
|
||||
lmkService.recoverKeyPackets(request.getPackets());
|
||||
return ApiResponse.success();
|
||||
}
|
||||
|
||||
@GetMapping("/masterKey/sign")
|
||||
@Operation(summary = "签名测试", description = "")
|
||||
public ApiResponse<Void> signIk(@RequestParam String data) {
|
||||
String signData = lmkService.signIk(data);
|
||||
log.info("signData:{}", signData);
|
||||
lmkService.verifyIk(data, signData);
|
||||
return ApiResponse.success();
|
||||
}
|
||||
|
||||
|
||||
private String signUkeyPayload(UKeySignDTO uKeySignDTO) {
|
||||
String iPubKey = lmkService.exportIkPublicKeyHex();
|
||||
String payload;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.cisd.tms.modules.mk.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MasterKeyBackupPacket {
|
||||
|
||||
private int componentIndex;
|
||||
private MasterKeyPacketLmkPart lmk;
|
||||
private MasterKeyPacketIkPart ikAuth;
|
||||
private MasterKeyPacketIkPart ikDevice;
|
||||
private List<MasterKeyPacketUserKeyPart> userKeys = new ArrayList<>();
|
||||
|
||||
public int getComponentIndex() {
|
||||
return componentIndex;
|
||||
}
|
||||
|
||||
public void setComponentIndex(int componentIndex) {
|
||||
this.componentIndex = componentIndex;
|
||||
}
|
||||
|
||||
public MasterKeyPacketLmkPart getLmk() {
|
||||
return lmk;
|
||||
}
|
||||
|
||||
public void setLmk(MasterKeyPacketLmkPart lmk) {
|
||||
this.lmk = lmk;
|
||||
}
|
||||
|
||||
public MasterKeyPacketIkPart getIkAuth() {
|
||||
return ikAuth;
|
||||
}
|
||||
|
||||
public void setIkAuth(MasterKeyPacketIkPart ikAuth) {
|
||||
this.ikAuth = ikAuth;
|
||||
}
|
||||
|
||||
public MasterKeyPacketIkPart getIkDevice() {
|
||||
return ikDevice;
|
||||
}
|
||||
|
||||
public void setIkDevice(MasterKeyPacketIkPart ikDevice) {
|
||||
this.ikDevice = ikDevice;
|
||||
}
|
||||
|
||||
public List<MasterKeyPacketUserKeyPart> getUserKeys() {
|
||||
return userKeys;
|
||||
}
|
||||
|
||||
public void setUserKeys(List<MasterKeyPacketUserKeyPart> userKeys) {
|
||||
this.userKeys = userKeys;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.cisd.tms.modules.mk.dto;
|
||||
|
||||
public class MasterKeyPacketIkPart {
|
||||
|
||||
private int keyType;
|
||||
private String mac;
|
||||
private String component;
|
||||
|
||||
public MasterKeyPacketIkPart() {
|
||||
}
|
||||
|
||||
public MasterKeyPacketIkPart(int keyType, String mac, String component) {
|
||||
this.keyType = keyType;
|
||||
this.mac = mac;
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public int getKeyType() {
|
||||
return keyType;
|
||||
}
|
||||
|
||||
public void setKeyType(int keyType) {
|
||||
this.keyType = keyType;
|
||||
}
|
||||
|
||||
public String getMac() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
public void setMac(String mac) {
|
||||
this.mac = mac;
|
||||
}
|
||||
|
||||
public String getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
public void setComponent(String component) {
|
||||
this.component = component;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.cisd.tms.modules.mk.dto;
|
||||
|
||||
public class MasterKeyPacketLmkPart {
|
||||
|
||||
private String lmkMac;
|
||||
private String component;
|
||||
|
||||
public MasterKeyPacketLmkPart() {
|
||||
}
|
||||
|
||||
public MasterKeyPacketLmkPart(String lmkMac, String component) {
|
||||
this.lmkMac = lmkMac;
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public String getLmkMac() {
|
||||
return lmkMac;
|
||||
}
|
||||
|
||||
public void setLmkMac(String lmkMac) {
|
||||
this.lmkMac = lmkMac;
|
||||
}
|
||||
|
||||
public String getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
public void setComponent(String component) {
|
||||
this.component = component;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.cisd.tms.modules.mk.dto;
|
||||
|
||||
public class MasterKeyPacketUserKeyPart {
|
||||
|
||||
private int keyIndex;
|
||||
private int keyType;
|
||||
private String component;
|
||||
|
||||
public MasterKeyPacketUserKeyPart() {
|
||||
}
|
||||
|
||||
public MasterKeyPacketUserKeyPart(int keyIndex, int keyType, String component) {
|
||||
this.keyIndex = keyIndex;
|
||||
this.keyType = keyType;
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public int getKeyIndex() {
|
||||
return keyIndex;
|
||||
}
|
||||
|
||||
public void setKeyIndex(int keyIndex) {
|
||||
this.keyIndex = keyIndex;
|
||||
}
|
||||
|
||||
public int getKeyType() {
|
||||
return keyType;
|
||||
}
|
||||
|
||||
public void setKeyType(int keyType) {
|
||||
this.keyType = keyType;
|
||||
}
|
||||
|
||||
public String getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
public void setComponent(String component) {
|
||||
this.component = component;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.cisd.tms.modules.mk.dto;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MasterKeyRecoverPacketsRequest {
|
||||
|
||||
@NotEmpty(message = "packets must not be empty")
|
||||
@Size(min = 3, max = 3, message = "packets size must be 3")
|
||||
private List<@Valid MasterKeyBackupPacket> packets;
|
||||
|
||||
public List<MasterKeyBackupPacket> getPackets() {
|
||||
return packets;
|
||||
}
|
||||
|
||||
public void setPackets(List<MasterKeyBackupPacket> packets) {
|
||||
this.packets = packets;
|
||||
}
|
||||
}
|
||||
@@ -20,4 +20,6 @@ public class UKeySignResult {
|
||||
private String component;
|
||||
|
||||
private String lmkMac;
|
||||
|
||||
private MasterKeyBackupPacket backupPacket;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
package com.cisd.tms.modules.mk.service;
|
||||
|
||||
import com.cisd.tms.common.util.DivisionUtils;
|
||||
import com.cisd.tms.integration.crypto.pcie.Gm0018AlgorithmIds;
|
||||
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.DigestRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.EccInternalSignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.EccInternalVerifyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.RecoverUserKeyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService;
|
||||
import com.cisd.tms.modules.mk.config.MasterKeyInitProperties;
|
||||
import com.cisd.tms.modules.mk.common.LMKConstant;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyBackupPacket;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyBackupMaterial;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyPacketIkPart;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyPacketLmkPart;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyPacketUserKeyPart;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyStateResult;
|
||||
import com.cisd.tms.modules.mk.enums.IKEnums;
|
||||
import com.cisd.tms.modules.mk.enums.MasterKeyStatus;
|
||||
@@ -18,6 +25,7 @@ import org.bouncycastle.util.encoders.Hex;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
@@ -34,6 +42,12 @@ public class LmkService {
|
||||
|
||||
private static final int AUTH_SIGN_KEY_INDEX = IKEnums.KEY_TYPE_AUTH.getCode();
|
||||
private static final int LMK_MAC_BYTE_LENGTH = 8;
|
||||
private static final int IK_COMPONENT_MAC_BYTE_LENGTH = 8;
|
||||
private static final int IK_COMPONENT_DATA_LENGTH = 3 * 64;
|
||||
private static final int USER_KEY_INDEX = 1;
|
||||
private static final int USER_KEY_TYPE_SIGN = 0;
|
||||
private static final int USER_KEY_TYPE_ENC = 1;
|
||||
private static final int USER_KEY_BACKUP_BUFFER_SIZE = 120;
|
||||
private final PcieCryptoService pcieCryptoService;
|
||||
private final MasterKeyInitProperties masterKeyInitProperties;
|
||||
|
||||
@@ -74,35 +88,76 @@ public class LmkService {
|
||||
}
|
||||
|
||||
public String signIk(String rawData) {
|
||||
byte[] digest = digestForInternalSign(rawData);
|
||||
EccInternalSignRequest request = new EccInternalSignRequest();
|
||||
request.setKeyIndex(AUTH_SIGN_KEY_INDEX);
|
||||
request.setData(rawData.getBytes(StandardCharsets.UTF_8));
|
||||
request.setData(digest);
|
||||
request.setSignatureBufferSize(new EccSignature().size());
|
||||
BackupDataResult result = pcieCryptoService.eccInternalSign(request);
|
||||
return Hex.toHexString(result.getData());
|
||||
}
|
||||
|
||||
public void verifyIk(String rawData, String signatureHex) {
|
||||
byte[] digest = digestForInternalSign(rawData);
|
||||
EccInternalVerifyRequest request = new EccInternalVerifyRequest();
|
||||
request.setKeyIndex(AUTH_SIGN_KEY_INDEX);
|
||||
request.setData(rawData.getBytes(StandardCharsets.UTF_8));
|
||||
request.setData(digest);
|
||||
request.setSignature(Hex.decode(signatureHex));
|
||||
pcieCryptoService.eccInternalVerify(request);
|
||||
}
|
||||
|
||||
public MasterKeyBackupPacket buildBackupPacket(int componentIndex) {
|
||||
int index = requireComponentIndex(componentIndex);
|
||||
ParsedMasterKeyBackup lmkBackup = parseBackupMaterial();
|
||||
ParsedIkBackup authIkBackup = parseIkBackupMaterial(IKEnums.KEY_TYPE_AUTH.getCode());
|
||||
ParsedIkBackup deviceIkBackup = parseIkBackupMaterial(IKEnums.KEY_TYPE_DEVICE.getCode());
|
||||
|
||||
MasterKeyBackupPacket packet = new MasterKeyBackupPacket();
|
||||
packet.setComponentIndex(index);
|
||||
packet.setLmk(new MasterKeyPacketLmkPart(
|
||||
lmkBackup.lmkMacHex(),
|
||||
requiredComponent(lmkBackup.componentMap(), index, "lmk")
|
||||
));
|
||||
packet.setIkAuth(new MasterKeyPacketIkPart(
|
||||
IKEnums.KEY_TYPE_AUTH.getCode(),
|
||||
authIkBackup.macHex(),
|
||||
requiredComponent(authIkBackup.componentMap(), index, "ikAuth")
|
||||
));
|
||||
packet.setIkDevice(new MasterKeyPacketIkPart(
|
||||
IKEnums.KEY_TYPE_DEVICE.getCode(),
|
||||
deviceIkBackup.macHex(),
|
||||
requiredComponent(deviceIkBackup.componentMap(), index, "ikDevice")
|
||||
));
|
||||
packet.setUserKeys(List.of(
|
||||
buildUserKeyPacket(USER_KEY_INDEX, USER_KEY_TYPE_SIGN, index),
|
||||
buildUserKeyPacket(USER_KEY_INDEX, USER_KEY_TYPE_ENC, index)
|
||||
));
|
||||
return packet;
|
||||
}
|
||||
|
||||
public MasterKeyBackupMaterial getBackupMaterial(int uid) {
|
||||
ParsedMasterKeyBackup parsedBackup = parseBackupMaterial();
|
||||
String component = parsedBackup.componentMap().get(uid);
|
||||
if (component == null) {
|
||||
throw new IllegalArgumentException("invalid component index: " + uid);
|
||||
}
|
||||
return new MasterKeyBackupMaterial(component, parsedBackup.lmkMacHex());
|
||||
MasterKeyBackupPacket packet = buildBackupPacket(uid);
|
||||
return new MasterKeyBackupMaterial(packet.getLmk().getComponent(), packet.getLmk().getLmkMac());
|
||||
}
|
||||
|
||||
public String getComponent(int uid) {
|
||||
return getBackupMaterial(uid).getComponent();
|
||||
}
|
||||
|
||||
public void recoverKeyPackets(List<MasterKeyBackupPacket> packets) {
|
||||
List<MasterKeyBackupPacket> orderedPackets = sortPackets(packets);
|
||||
byte[] oldPin = decodeConfiguredPin("tms.mk.init-identify.old-pin-base64", masterKeyInitProperties.getOldPinBase64());
|
||||
byte[] newPin = decodeConfiguredPin("tms.mk.init-identify.new-pin-base64", masterKeyInitProperties.getNewPinBase64());
|
||||
|
||||
pcieCryptoService.initIdentify(oldPin, newPin);
|
||||
pcieCryptoService.recoverLmkEx(Hex.decode(composeLmkHex(orderedPackets)));
|
||||
pcieCryptoService.loadLmk();
|
||||
pcieCryptoService.recoverIkComponent(IKEnums.KEY_TYPE_AUTH.getCode(), Hex.decode(composeIkHex(orderedPackets, true)));
|
||||
pcieCryptoService.recoverIkComponent(IKEnums.KEY_TYPE_DEVICE.getCode(), Hex.decode(composeIkHex(orderedPackets, false)));
|
||||
pcieCryptoService.recoverUserKey(toRecoverUserKeyRequest(orderedPackets, USER_KEY_INDEX, USER_KEY_TYPE_SIGN));
|
||||
pcieCryptoService.recoverUserKey(toRecoverUserKeyRequest(orderedPackets, USER_KEY_INDEX, USER_KEY_TYPE_ENC));
|
||||
}
|
||||
|
||||
public void recoverLmkEx(String lmkMacHex, List<String> components) {
|
||||
byte[] oldPin = decodeConfiguredPin("tms.mk.init-identify.old-pin-base64", masterKeyInitProperties.getOldPinBase64());
|
||||
byte[] newPin = decodeConfiguredPin("tms.mk.init-identify.new-pin-base64", masterKeyInitProperties.getNewPinBase64());
|
||||
@@ -141,8 +196,48 @@ public class LmkService {
|
||||
return lmk.toString();
|
||||
}
|
||||
|
||||
private String composeLmkHex(List<MasterKeyBackupPacket> packets) {
|
||||
String lmkMac = requireConsistentLmkMac(packets);
|
||||
StringBuilder builder = new StringBuilder(lmkMac);
|
||||
for (MasterKeyBackupPacket packet : packets) {
|
||||
builder.append(packet.getLmk().getComponent());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String composeIkHex(List<MasterKeyBackupPacket> packets, boolean authKey) {
|
||||
int keyType = authKey ? IKEnums.KEY_TYPE_AUTH.getCode() : IKEnums.KEY_TYPE_DEVICE.getCode();
|
||||
String mac = requireConsistentIkMac(packets, keyType);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (MasterKeyBackupPacket packet : packets) {
|
||||
MasterKeyPacketIkPart part = authKey ? packet.getIkAuth() : packet.getIkDevice();
|
||||
if (part == null || part.getComponent() == null || part.getComponent().isBlank()) {
|
||||
throw new IllegalArgumentException((authKey ? "ikAuth" : "ikDevice") + " component missing in packet " + packet.getComponentIndex());
|
||||
}
|
||||
builder.append(part.getComponent());
|
||||
}
|
||||
builder.append(mac);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private RecoverUserKeyRequest toRecoverUserKeyRequest(List<MasterKeyBackupPacket> packets, int keyIndex, int keyType) {
|
||||
RecoverUserKeyRequest request = new RecoverUserKeyRequest();
|
||||
request.setKeyIndex(keyIndex);
|
||||
request.setKeyType(keyType);
|
||||
request.setEncryptedKey(Hex.decode(composeUserKeyHex(packets, keyIndex, keyType)));
|
||||
return request;
|
||||
}
|
||||
|
||||
private String composeUserKeyHex(List<MasterKeyBackupPacket> packets, int keyIndex, int keyType) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (MasterKeyBackupPacket packet : packets) {
|
||||
MasterKeyPacketUserKeyPart part = findUserKeyPart(packet, keyIndex, keyType);
|
||||
builder.append(part.getComponent());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private ParsedMasterKeyBackup parseBackupMaterial() {
|
||||
//todo 需要将主密钥分量、内部密钥分量一起拆分后进行备份,密码卡暂时没有导出内部密钥分量接口
|
||||
BackupDataResult backupData = pcieCryptoService.backupLmkEx();
|
||||
byte[] normalized = normalizeBackupData(backupData);
|
||||
if (normalized.length < LMK_MAC_BYTE_LENGTH) {
|
||||
@@ -158,6 +253,29 @@ public class LmkService {
|
||||
return new ParsedMasterKeyBackup(Hex.toHexString(lmkMac), componentMap);
|
||||
}
|
||||
|
||||
private ParsedIkBackup parseIkBackupMaterial(int keyType) {
|
||||
BackupDataResult backupData = pcieCryptoService.backupIkComponent(keyType);
|
||||
byte[] normalized = normalizeBackupData(backupData);
|
||||
if (normalized.length < IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH) {
|
||||
throw new IllegalStateException("backup ik data length is too short: " + normalized.length);
|
||||
}
|
||||
byte[] componentBytes = Arrays.copyOfRange(normalized, 0, IK_COMPONENT_DATA_LENGTH);
|
||||
byte[] mac = Arrays.copyOfRange(normalized, IK_COMPONENT_DATA_LENGTH, IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH);
|
||||
String[] splitComponents = DivisionUtils.equalDivision(Hex.toHexString(componentBytes), LMKConstant.COMPONENT_NUM);
|
||||
Map<Integer, String> componentMap = new HashMap<>();
|
||||
for (int i = 0; i < LMKConstant.COMPONENT_NUM; i++) {
|
||||
componentMap.put(LMKConstant.KEY_ORDER[i], splitComponents[i]);
|
||||
}
|
||||
return new ParsedIkBackup(Hex.toHexString(mac), componentMap);
|
||||
}
|
||||
|
||||
private MasterKeyPacketUserKeyPart buildUserKeyPacket(int keyIndex, int keyType, int componentIndex) {
|
||||
BackupDataResult backupData = pcieCryptoService.backupUserKey(keyIndex, keyType, USER_KEY_BACKUP_BUFFER_SIZE);
|
||||
byte[] normalized = normalizeBackupData(backupData);
|
||||
String[] components = DivisionUtils.equalDivision(Hex.toHexString(normalized), LMKConstant.COMPONENT_NUM);
|
||||
return new MasterKeyPacketUserKeyPart(keyIndex, keyType, components[componentIndex - 1]);
|
||||
}
|
||||
|
||||
private byte[] normalizeBackupData(BackupDataResult backupData) {
|
||||
byte[] data = backupData.getData();
|
||||
if (data == null || data.length == 0) {
|
||||
@@ -179,7 +297,104 @@ public class LmkService {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] digestForInternalSign(String rawData) {
|
||||
DigestRequest request = new DigestRequest();
|
||||
request.setAlgId(Gm0018AlgorithmIds.SM3);
|
||||
request.setData(rawData.getBytes(StandardCharsets.UTF_8));
|
||||
BackupDataResult result = pcieCryptoService.digest(request);
|
||||
return normalizeBackupData(result);
|
||||
}
|
||||
|
||||
private int requireComponentIndex(int componentIndex) {
|
||||
if (componentIndex < 1 || componentIndex > LMKConstant.COMPONENT_NUM) {
|
||||
throw new IllegalArgumentException("componentIndex must be 1, 2 or 3");
|
||||
}
|
||||
return componentIndex;
|
||||
}
|
||||
|
||||
private String requiredComponent(Map<Integer, String> componentMap, int componentIndex, String name) {
|
||||
String component = componentMap.get(componentIndex);
|
||||
if (component == null || component.isBlank()) {
|
||||
throw new IllegalArgumentException(name + " component missing: " + componentIndex);
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
private List<MasterKeyBackupPacket> sortPackets(List<MasterKeyBackupPacket> packets) {
|
||||
if (packets == null || packets.size() != LMKConstant.COMPONENT_NUM) {
|
||||
throw new IllegalArgumentException("packets size must be " + LMKConstant.COMPONENT_NUM);
|
||||
}
|
||||
Map<Integer, MasterKeyBackupPacket> packetMap = new HashMap<>();
|
||||
for (MasterKeyBackupPacket packet : packets) {
|
||||
if (packet == null) {
|
||||
throw new IllegalArgumentException("packet must not be null");
|
||||
}
|
||||
int componentIndex = requireComponentIndex(packet.getComponentIndex());
|
||||
if (packetMap.put(componentIndex, packet) != null) {
|
||||
throw new IllegalArgumentException("duplicate packet for componentIndex " + componentIndex);
|
||||
}
|
||||
}
|
||||
List<MasterKeyBackupPacket> ordered = new ArrayList<>();
|
||||
for (int componentIndex : LMKConstant.KEY_ORDER) {
|
||||
MasterKeyBackupPacket packet = packetMap.get(componentIndex);
|
||||
if (packet == null) {
|
||||
throw new IllegalArgumentException("packet missing for componentIndex " + componentIndex);
|
||||
}
|
||||
ordered.add(packet);
|
||||
}
|
||||
return ordered;
|
||||
}
|
||||
|
||||
private String requireConsistentLmkMac(List<MasterKeyBackupPacket> packets) {
|
||||
String expected = null;
|
||||
for (MasterKeyBackupPacket packet : packets) {
|
||||
if (packet.getLmk() == null || packet.getLmk().getLmkMac() == null || packet.getLmk().getLmkMac().isBlank()) {
|
||||
throw new IllegalArgumentException("lmk mac missing in packet " + packet.getComponentIndex());
|
||||
}
|
||||
String current = packet.getLmk().getLmkMac();
|
||||
if (expected == null) {
|
||||
expected = current;
|
||||
continue;
|
||||
}
|
||||
if (!expected.equalsIgnoreCase(current)) {
|
||||
throw new IllegalArgumentException("lmk mac is inconsistent across packets");
|
||||
}
|
||||
}
|
||||
return expected;
|
||||
}
|
||||
|
||||
private String requireConsistentIkMac(List<MasterKeyBackupPacket> packets, int keyType) {
|
||||
String expected = null;
|
||||
for (MasterKeyBackupPacket packet : packets) {
|
||||
MasterKeyPacketIkPart part = keyType == IKEnums.KEY_TYPE_AUTH.getCode() ? packet.getIkAuth() : packet.getIkDevice();
|
||||
if (part == null || part.getMac() == null || part.getMac().isBlank()) {
|
||||
throw new IllegalArgumentException("ik mac missing for keyType " + keyType);
|
||||
}
|
||||
if (expected == null) {
|
||||
expected = part.getMac();
|
||||
continue;
|
||||
}
|
||||
if (!expected.equalsIgnoreCase(part.getMac())) {
|
||||
throw new IllegalArgumentException("ik mac is inconsistent across packets for keyType " + keyType);
|
||||
}
|
||||
}
|
||||
return expected;
|
||||
}
|
||||
|
||||
private MasterKeyPacketUserKeyPart findUserKeyPart(MasterKeyBackupPacket packet, int keyIndex, int keyType) {
|
||||
if (packet.getUserKeys() == null) {
|
||||
throw new IllegalArgumentException("userKeys missing in packet " + packet.getComponentIndex());
|
||||
}
|
||||
return packet.getUserKeys().stream()
|
||||
.filter(part -> part.getKeyIndex() == keyIndex && part.getKeyType() == keyType)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("user key component missing in packet " + packet.getComponentIndex()));
|
||||
}
|
||||
|
||||
private record ParsedMasterKeyBackup(String lmkMacHex, Map<Integer, String> componentMap) {
|
||||
}
|
||||
|
||||
private record ParsedIkBackup(String macHex, Map<Integer, String> componentMap) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user