主密钥初始化

This commit is contained in:
waner
2026-03-30 16:23:56 +08:00
parent fbe23b8ecb
commit 7a7503c35e
17 changed files with 753 additions and 57 deletions
@@ -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");
}
}
@@ -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) {
}
}