主密钥初始化
This commit is contained in:
parent
fbe23b8ecb
commit
7a7503c35e
@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
package com.cisd.tms.modules.mk.controller;
|
||||
|
||||
import com.cisd.tms.common.exception.GlobalExceptionHandler;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyBackupMaterial;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyBackupPacket;
|
||||
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.service.LmkService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@ -26,8 +29,16 @@ class LmkControllerTest {
|
||||
LmkService lmkService = Mockito.mock(LmkService.class);
|
||||
Mockito.when(lmkService.exportIkPublicKeyHex()).thenReturn("IK-PUB-001");
|
||||
Mockito.when(lmkService.signIk(ArgumentMatchers.anyString())).thenReturn("SIGN-001");
|
||||
Mockito.when(lmkService.getBackupMaterial(2))
|
||||
.thenReturn(new MasterKeyBackupMaterial("COMP-002", "LMK-MAC-001"));
|
||||
MasterKeyBackupPacket packet = new MasterKeyBackupPacket();
|
||||
packet.setComponentIndex(2);
|
||||
packet.setLmk(new MasterKeyPacketLmkPart("LMK-MAC-001", "LMK-COMP-002"));
|
||||
packet.setIkAuth(new MasterKeyPacketIkPart(2, "IK-AUTH-MAC-001", "IK-AUTH-COMP-002"));
|
||||
packet.setIkDevice(new MasterKeyPacketIkPart(1, "IK-DEVICE-MAC-001", "IK-DEVICE-COMP-002"));
|
||||
packet.setUserKeys(java.util.List.of(
|
||||
new MasterKeyPacketUserKeyPart(1, 0, "USER-SIGN-COMP-002"),
|
||||
new MasterKeyPacketUserKeyPart(1, 1, "USER-ENC-COMP-002")
|
||||
));
|
||||
Mockito.when(lmkService.buildBackupPacket(2)).thenReturn(packet);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new LmkController(lmkService, new ObjectMapper()))
|
||||
.setControllerAdvice(new GlobalExceptionHandler())
|
||||
@ -46,15 +57,21 @@ class LmkControllerTest {
|
||||
"""))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString("\"sign\":\"SIGN-001\"")))
|
||||
.andExpect(content().string(containsString("\"component\":\"COMP-002\"")))
|
||||
.andExpect(content().string(containsString("\"lmkMac\":\"LMK-MAC-001\"")));
|
||||
.andExpect(content().string(containsString("\"componentIndex\":2")))
|
||||
.andExpect(content().string(containsString("\"lmkMac\":\"LMK-MAC-001\"")))
|
||||
.andExpect(content().string(containsString("\"component\":\"LMK-COMP-002\"")))
|
||||
.andExpect(content().string(containsString("\"ikAuth\"")))
|
||||
.andExpect(content().string(containsString("\"ikDevice\"")))
|
||||
.andExpect(content().string(containsString("\"userKeys\"")))
|
||||
.andExpect(content().string(containsString("\"USER-SIGN-COMP-002\"")))
|
||||
.andExpect(content().string(containsString("\"USER-ENC-COMP-002\"")));
|
||||
|
||||
Mockito.verify(lmkService).signIk(eq("{\"pubKey\":\"PUB-001\",\"authKeyPair\":\"IK-PUB-001\",\"role\":\"superadmin\",\"uid\":\"2\",\"rid\":\"RID-001\"}"));
|
||||
Mockito.verify(lmkService).getBackupMaterial(2);
|
||||
Mockito.verify(lmkService).buildBackupPacket(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRecoverLmkExUsingLmkMacAndOrderedComponents() throws Exception {
|
||||
void shouldRecoverKeyPacketsUsingOrderedPackets() throws Exception {
|
||||
LmkService lmkService = Mockito.mock(LmkService.class);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new LmkController(lmkService, new ObjectMapper()))
|
||||
@ -65,17 +82,41 @@ class LmkControllerTest {
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("""
|
||||
{
|
||||
"lmkMac": "a1a2a3a4a5a6a7a8",
|
||||
"components": [
|
||||
"0102",
|
||||
"0304",
|
||||
"0506"
|
||||
"packets": [
|
||||
{
|
||||
"componentIndex": 1,
|
||||
"lmk": {
|
||||
"lmkMac": "a1a2a3a4a5a6a7a8",
|
||||
"component": "0102"
|
||||
},
|
||||
"ikAuth": {
|
||||
"mac": "1111111111111111",
|
||||
"component": "0304"
|
||||
},
|
||||
"ikDevice": {
|
||||
"mac": "2222222222222222",
|
||||
"component": "0506"
|
||||
},
|
||||
"userKeys": [
|
||||
{
|
||||
"keyIndex": 1,
|
||||
"keyType": 0,
|
||||
"component": "0708"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"componentIndex": 2
|
||||
},
|
||||
{
|
||||
"componentIndex": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
"""))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
Mockito.verify(lmkService).recoverLmkEx(eq("a1a2a3a4a5a6a7a8"), eq(java.util.List.of("0102", "0304", "0506")));
|
||||
Mockito.verify(lmkService).recoverKeyPackets(ArgumentMatchers.argThat(packets -> packets != null && packets.size() == 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -1,16 +1,24 @@
|
||||
package com.cisd.tms.modules.mk.service;
|
||||
|
||||
import com.cisd.tms.integration.crypto.pcie.Gm0018AlgorithmIds;
|
||||
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.dto.MasterKeyBackupMaterial;
|
||||
import com.cisd.tms.modules.mk.dto.MasterKeyBackupPacket;
|
||||
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 java.util.List;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
class LmkServiceTest {
|
||||
@ -79,48 +87,181 @@ class LmkServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnIndexedMasterKeyComponentAndMacFromBackupBlob() {
|
||||
void shouldBuildBackupPacketForSingleComponentIndex() {
|
||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
||||
BackupDataResult backup = new BackupDataResult();
|
||||
backup.setLength(20);
|
||||
backup.setData(new byte[] {
|
||||
BackupDataResult lmkBackup = new BackupDataResult();
|
||||
lmkBackup.setLength(20);
|
||||
lmkBackup.setData(new byte[] {
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x01, 0x02, 0x03, 0x04,
|
||||
0x05, 0x06, 0x07, 0x08,
|
||||
0x09, 0x0A, 0x0B, 0x0C
|
||||
});
|
||||
Mockito.when(pcieCryptoService.backupLmkEx()).thenReturn(backup);
|
||||
BackupDataResult ikAuthBackup = new BackupDataResult();
|
||||
ikAuthBackup.setLength(200);
|
||||
ikAuthBackup.setData(sequentialBytes(200, 0x21));
|
||||
BackupDataResult ikDeviceBackup = new BackupDataResult();
|
||||
ikDeviceBackup.setLength(200);
|
||||
ikDeviceBackup.setData(sequentialBytes(200, 0x41));
|
||||
BackupDataResult userSignBackup = new BackupDataResult();
|
||||
userSignBackup.setLength(12);
|
||||
userSignBackup.setData(new byte[] {0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C});
|
||||
BackupDataResult userEncBackup = new BackupDataResult();
|
||||
userEncBackup.setLength(12);
|
||||
userEncBackup.setData(new byte[] {0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x31, 0x32});
|
||||
Mockito.when(pcieCryptoService.backupLmkEx()).thenReturn(lmkBackup);
|
||||
Mockito.when(pcieCryptoService.backupIkComponent(2)).thenReturn(ikAuthBackup);
|
||||
Mockito.when(pcieCryptoService.backupIkComponent(1)).thenReturn(ikDeviceBackup);
|
||||
Mockito.when(pcieCryptoService.backupUserKey(1, 0, 120)).thenReturn(userSignBackup);
|
||||
Mockito.when(pcieCryptoService.backupUserKey(1, 1, 120)).thenReturn(userEncBackup);
|
||||
|
||||
LmkService service = new LmkService(pcieCryptoService, properties);
|
||||
|
||||
MasterKeyBackupMaterial material = service.getBackupMaterial(2);
|
||||
MasterKeyBackupPacket packet = service.buildBackupPacket(2);
|
||||
|
||||
Assertions.assertEquals("05060708", material.getComponent());
|
||||
Assertions.assertEquals("1112131415161718", material.getLmkMac());
|
||||
Assertions.assertEquals(2, packet.getComponentIndex());
|
||||
Assertions.assertEquals("1112131415161718", packet.getLmk().getLmkMac());
|
||||
Assertions.assertEquals("05060708", packet.getLmk().getComponent());
|
||||
Assertions.assertEquals(2, packet.getIkAuth().getKeyType());
|
||||
Assertions.assertEquals(
|
||||
org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikAuthBackup.getData(), 64, 128)),
|
||||
packet.getIkAuth().getComponent()
|
||||
);
|
||||
Assertions.assertEquals(1, packet.getIkDevice().getKeyType());
|
||||
Assertions.assertEquals(
|
||||
org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikDeviceBackup.getData(), 64, 128)),
|
||||
packet.getIkDevice().getComponent()
|
||||
);
|
||||
Assertions.assertEquals(2, packet.getUserKeys().size());
|
||||
Assertions.assertEquals("65666768", packet.getUserKeys().get(0).getComponent());
|
||||
Assertions.assertEquals("75767778", packet.getUserKeys().get(1).getComponent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInitIdentifyBeforeRecoverLmkExAndLoadIt() {
|
||||
void shouldRecoverAllKeyPacketsInOrder() {
|
||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
||||
LmkService service = new LmkService(pcieCryptoService, properties);
|
||||
|
||||
service.recoverLmkEx("1112131415161718", List.of("0102", "0304", "0506"));
|
||||
MasterKeyBackupPacket packet1 = new MasterKeyBackupPacket();
|
||||
packet1.setComponentIndex(1);
|
||||
packet1.setLmk(new MasterKeyPacketLmkPart("1112131415161718", "0102"));
|
||||
packet1.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1112"));
|
||||
packet1.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2122"));
|
||||
packet1.setUserKeys(List.of(
|
||||
new MasterKeyPacketUserKeyPart(1, 0, "0102"),
|
||||
new MasterKeyPacketUserKeyPart(1, 1, "1112")
|
||||
));
|
||||
|
||||
MasterKeyBackupPacket packet2 = new MasterKeyBackupPacket();
|
||||
packet2.setComponentIndex(2);
|
||||
packet2.setLmk(new MasterKeyPacketLmkPart("1112131415161718", "0304"));
|
||||
packet2.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1314"));
|
||||
packet2.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2324"));
|
||||
packet2.setUserKeys(List.of(
|
||||
new MasterKeyPacketUserKeyPart(1, 0, "0304"),
|
||||
new MasterKeyPacketUserKeyPart(1, 1, "1314")
|
||||
));
|
||||
|
||||
MasterKeyBackupPacket packet3 = new MasterKeyBackupPacket();
|
||||
packet3.setComponentIndex(3);
|
||||
packet3.setLmk(new MasterKeyPacketLmkPart("1112131415161718", "0506"));
|
||||
packet3.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1516"));
|
||||
packet3.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2526"));
|
||||
packet3.setUserKeys(List.of(
|
||||
new MasterKeyPacketUserKeyPart(1, 0, "0506"),
|
||||
new MasterKeyPacketUserKeyPart(1, 1, "1516")
|
||||
));
|
||||
|
||||
service.recoverKeyPackets(List.of(packet1, packet2, packet3));
|
||||
|
||||
ArgumentCaptor<byte[]> oldPinCaptor = ArgumentCaptor.forClass(byte[].class);
|
||||
ArgumentCaptor<byte[]> newPinCaptor = ArgumentCaptor.forClass(byte[].class);
|
||||
ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class);
|
||||
ArgumentCaptor<byte[]> lmkCaptor = ArgumentCaptor.forClass(byte[].class);
|
||||
ArgumentCaptor<byte[]> ikAuthCaptor = ArgumentCaptor.forClass(byte[].class);
|
||||
ArgumentCaptor<byte[]> ikDeviceCaptor = ArgumentCaptor.forClass(byte[].class);
|
||||
ArgumentCaptor<RecoverUserKeyRequest> userKeyCaptor = ArgumentCaptor.forClass(RecoverUserKeyRequest.class);
|
||||
InOrder inOrder = Mockito.inOrder(pcieCryptoService);
|
||||
inOrder.verify(pcieCryptoService).initIdentify(oldPinCaptor.capture(), newPinCaptor.capture());
|
||||
inOrder.verify(pcieCryptoService).recoverLmkEx(captor.capture());
|
||||
inOrder.verify(pcieCryptoService).recoverLmkEx(lmkCaptor.capture());
|
||||
inOrder.verify(pcieCryptoService).loadLmk();
|
||||
inOrder.verify(pcieCryptoService).recoverIkComponent(Mockito.eq(2), ikAuthCaptor.capture());
|
||||
inOrder.verify(pcieCryptoService).recoverIkComponent(Mockito.eq(1), ikDeviceCaptor.capture());
|
||||
inOrder.verify(pcieCryptoService, Mockito.times(2)).recoverUserKey(userKeyCaptor.capture());
|
||||
Assertions.assertArrayEquals("12345678".getBytes(StandardCharsets.UTF_8), oldPinCaptor.getValue());
|
||||
Assertions.assertArrayEquals("87654321".getBytes(StandardCharsets.UTF_8), newPinCaptor.getValue());
|
||||
Assertions.assertArrayEquals(new byte[] {
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06
|
||||
}, captor.getValue());
|
||||
}, lmkCaptor.getValue());
|
||||
Assertions.assertArrayEquals(hex("1112131415162122232425262728"), ikAuthCaptor.getValue());
|
||||
Assertions.assertArrayEquals(hex("2122232425263132333435363738"), ikDeviceCaptor.getValue());
|
||||
Assertions.assertEquals(2, userKeyCaptor.getAllValues().size());
|
||||
Assertions.assertArrayEquals(hex("010203040506"), userKeyCaptor.getAllValues().get(0).getEncryptedKey());
|
||||
Assertions.assertArrayEquals(hex("111213141516"), userKeyCaptor.getAllValues().get(1).getEncryptedKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHashRawDataBeforeInternalSign() {
|
||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
||||
BackupDataResult digestResult = new BackupDataResult();
|
||||
digestResult.setLength(32);
|
||||
digestResult.setData(new byte[] {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20
|
||||
});
|
||||
BackupDataResult signResult = new BackupDataResult();
|
||||
signResult.setLength(2);
|
||||
signResult.setData(new byte[] {(byte) 0xAA, (byte) 0xBB});
|
||||
Mockito.when(pcieCryptoService.digest(Mockito.any())).thenReturn(digestResult);
|
||||
Mockito.when(pcieCryptoService.eccInternalSign(Mockito.any())).thenReturn(signResult);
|
||||
|
||||
LmkService service = new LmkService(pcieCryptoService, properties);
|
||||
|
||||
String signatureHex = service.signIk("1223");
|
||||
|
||||
Assertions.assertEquals("aabb", signatureHex);
|
||||
ArgumentCaptor<DigestRequest> digestCaptor = ArgumentCaptor.forClass(DigestRequest.class);
|
||||
ArgumentCaptor<EccInternalSignRequest> signCaptor = ArgumentCaptor.forClass(EccInternalSignRequest.class);
|
||||
InOrder inOrder = Mockito.inOrder(pcieCryptoService);
|
||||
inOrder.verify(pcieCryptoService).digest(digestCaptor.capture());
|
||||
inOrder.verify(pcieCryptoService).eccInternalSign(signCaptor.capture());
|
||||
Assertions.assertEquals(Gm0018AlgorithmIds.SM3, digestCaptor.getValue().getAlgId());
|
||||
Assertions.assertArrayEquals("1223".getBytes(StandardCharsets.UTF_8), digestCaptor.getValue().getData());
|
||||
Assertions.assertArrayEquals(digestResult.getData(), signCaptor.getValue().getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHashRawDataBeforeInternalVerify() {
|
||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
||||
BackupDataResult digestResult = new BackupDataResult();
|
||||
digestResult.setLength(32);
|
||||
digestResult.setData(new byte[] {
|
||||
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
|
||||
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
||||
0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40
|
||||
});
|
||||
Mockito.when(pcieCryptoService.digest(Mockito.any())).thenReturn(digestResult);
|
||||
|
||||
LmkService service = new LmkService(pcieCryptoService, properties);
|
||||
|
||||
service.verifyIk("1223", "aabb");
|
||||
|
||||
ArgumentCaptor<DigestRequest> digestCaptor = ArgumentCaptor.forClass(DigestRequest.class);
|
||||
ArgumentCaptor<EccInternalVerifyRequest> verifyCaptor = ArgumentCaptor.forClass(EccInternalVerifyRequest.class);
|
||||
InOrder inOrder = Mockito.inOrder(pcieCryptoService);
|
||||
inOrder.verify(pcieCryptoService).digest(digestCaptor.capture());
|
||||
inOrder.verify(pcieCryptoService).eccInternalVerify(verifyCaptor.capture());
|
||||
Assertions.assertEquals(Gm0018AlgorithmIds.SM3, digestCaptor.getValue().getAlgId());
|
||||
Assertions.assertArrayEquals("1223".getBytes(StandardCharsets.UTF_8), digestCaptor.getValue().getData());
|
||||
Assertions.assertArrayEquals(digestResult.getData(), verifyCaptor.getValue().getData());
|
||||
Assertions.assertArrayEquals(new byte[] {(byte) 0xAA, (byte) 0xBB}, verifyCaptor.getValue().getSignature());
|
||||
}
|
||||
|
||||
private static MasterKeyInitProperties configuredPins(String oldPinBase64, String newPinBase64) {
|
||||
@ -129,4 +270,16 @@ class LmkServiceTest {
|
||||
properties.setNewPinBase64(newPinBase64);
|
||||
return properties;
|
||||
}
|
||||
|
||||
private static byte[] sequentialBytes(int length, int start) {
|
||||
byte[] result = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
result[i] = (byte) (start + i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static byte[] hex(String value) {
|
||||
return org.bouncycastle.util.encoders.Hex.decode(value);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user