主密钥初始化
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 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,
|
int SDFE_GenerateUkey(Pointer hSessionHandle, byte adminIndex,
|
||||||
byte[] ukeyPin, int ukeyPinLen,
|
byte[] ukeyPin, int ukeyPinLen,
|
||||||
byte[] loginPin, int loginPinLen);
|
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.SdfeKekComponent;
|
||||||
import com.cisd.tms.integration.crypto.pcie.jna.SdfeLmkComponent;
|
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.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.AgreementDataAndKeyEccResult;
|
||||||
import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult;
|
import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult;
|
||||||
import com.cisd.tms.integration.crypto.pcie.model.ChangePrivateKeyPasswordRequest;
|
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) {
|
public byte[] initializeMasterKey(byte[] oldPin, byte[] newPin) {
|
||||||
byte[] oldPinValue = requireNonEmptyBytes("oldPin", oldPin);
|
byte[] oldPinValue = requireNonEmptyBytes("oldPin", oldPin);
|
||||||
byte[] newPinValue = requireNonEmptyBytes("newPin", newPin);
|
byte[] newPinValue = requireNonEmptyBytes("newPin", newPin);
|
||||||
|
//lmk初始化包含主密钥生成、加载;内部密钥生成;用户密钥生成;返回主密钥校验值。
|
||||||
try {
|
try {
|
||||||
return sessionTemplate.withSession("SDFE_InitializeMasterKey", (lib, deviceHandle, sessionHandle) -> {
|
return sessionTemplate.withSession("SDFE_InitializeMasterKey", (lib, deviceHandle, sessionHandle) -> {
|
||||||
sessionTemplate.ensureSuccess(
|
sessionTemplate.ensureSuccess(
|
||||||
@ -210,7 +211,14 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
|||||||
sessionTemplate.ensureSuccess("SDFE_LoadLMK", lib.SDFE_LoadLMK(sessionHandle));
|
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_DEVICE));
|
||||||
sessionTemplate.ensureSuccess("SDFE_GenerateIK", lib.SDFE_GenerateIK(sessionHandle, IK_KEY_TYPE_AUTH));
|
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);
|
int retCode = lib.SDFE_CheckLMK(sessionHandle);
|
||||||
if (retCode != 0) {
|
if (retCode != 0) {
|
||||||
if ((retCode & 0xFF) == SDFE_INIT_STATUS_LOW_BYTE) {
|
if ((retCode & 0xFF) == SDFE_INIT_STATUS_LOW_BYTE) {
|
||||||
@ -331,7 +339,8 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
|||||||
|
|
||||||
int keyIndex = requireNonNegative("keyIndex", req.getKeyIndex());
|
int keyIndex = requireNonNegative("keyIndex", req.getKeyIndex());
|
||||||
int keyType = requireUserKeyType(req.getKeyType());
|
int keyType = requireUserKeyType(req.getKeyType());
|
||||||
|
//keyType: 1-加密密钥对;0-签名密钥对
|
||||||
|
//keyIndex:[1,8]
|
||||||
sessionTemplate.withSession("SDFE_GenerateKeyPair_ECC", (lib, deviceHandle, sessionHandle) -> {
|
sessionTemplate.withSession("SDFE_GenerateKeyPair_ECC", (lib, deviceHandle, sessionHandle) -> {
|
||||||
sessionTemplate.ensureSuccess(
|
sessionTemplate.ensureSuccess(
|
||||||
"SDFE_GenerateKeyPair_ECC",
|
"SDFE_GenerateKeyPair_ECC",
|
||||||
@ -467,6 +476,7 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
|||||||
public BackupDataResult backupUserKey(int keyIndex, int keyType, int outBufferSize) {
|
public BackupDataResult backupUserKey(int keyIndex, int keyType, int outBufferSize) {
|
||||||
int safeKeyIndex = requireNonNegative("keyIndex", keyIndex);
|
int safeKeyIndex = requireNonNegative("keyIndex", keyIndex);
|
||||||
int safeKeyType = requireUserKeyType(keyType);
|
int safeKeyType = requireUserKeyType(keyType);
|
||||||
|
//size: 120
|
||||||
int safeOutBufferSize = requirePositive("outBufferSize", outBufferSize);
|
int safeOutBufferSize = requirePositive("outBufferSize", outBufferSize);
|
||||||
|
|
||||||
return sessionTemplate.withSession("SDFE_BackupUserKey", (lib, deviceHandle, sessionHandle) -> {
|
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
|
@Override
|
||||||
public void backupIk(int keyType) {
|
public void backupIk(int keyType) {
|
||||||
int safeKeyType = requireNonNegative("keyType", keyType);
|
int safeKeyType = requireNonNegative("keyType", keyType);
|
||||||
@ -2129,6 +2163,10 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
|||||||
return toStructure(name, value, new SdfeLmkComponent(), false);
|
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) {
|
private static EnvelopedKeyBlob toEnvelopedKeyBlob(String name, byte[] value) {
|
||||||
return toStructure(name, value, new EnvelopedKeyBlob(), true);
|
return toStructure(name, value, new EnvelopedKeyBlob(), true);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -707,6 +707,18 @@ public class MockPcieCryptoService implements PcieCryptoService {
|
|||||||
requireNonNegative("keyType", keyType);
|
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
|
@Override
|
||||||
public void backupIk(int keyType) {
|
public void backupIk(int keyType) {
|
||||||
requireNonNegative("keyType", keyType);
|
requireNonNegative("keyType", keyType);
|
||||||
|
|||||||
@ -217,6 +217,10 @@ public interface PcieCryptoService {
|
|||||||
|
|
||||||
void generateIk(int keyType);
|
void generateIk(int keyType);
|
||||||
|
|
||||||
|
BackupDataResult backupIkComponent(int keyType);
|
||||||
|
|
||||||
|
void recoverIkComponent(int keyType, byte[] ikComponent);
|
||||||
|
|
||||||
void backupIk(int keyType);
|
void backupIk(int keyType);
|
||||||
|
|
||||||
void recoverIk(int keyType);
|
void recoverIk(int keyType);
|
||||||
|
|||||||
@ -28,7 +28,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/init")
|
@RequestMapping("/api/v1/init")
|
||||||
@Tag(name = "CISD初始化任务", description = "初始化模板、预检、任务创建、执行与日志查询接口")
|
@Tag(name = "CISD配置初始化和重置任务", description = "初始化和重置任务创建、执行与日志查询接口")
|
||||||
public class InitController {
|
public class InitController {
|
||||||
|
|
||||||
private final InitService initService;
|
private final InitService initService;
|
||||||
|
|||||||
@ -162,6 +162,7 @@ public class InitService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String productType = resolvePresetProductType();
|
String productType = resolvePresetProductType();
|
||||||
|
//todo 验证是否已经初始化
|
||||||
validateCommon(request);
|
validateCommon(request);
|
||||||
validateByProductType(productType, 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.common.api.ApiResponse;
|
||||||
import com.cisd.tms.modules.mk.dto.MasterKeyBackupMaterial;
|
import com.cisd.tms.modules.mk.dto.MasterKeyBackupMaterial;
|
||||||
import com.cisd.tms.modules.mk.dto.MasterKeyRecoverRequest;
|
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.MasterKeyStateResult;
|
||||||
import com.cisd.tms.modules.mk.dto.UKeySignDTO;
|
import com.cisd.tms.modules.mk.dto.UKeySignDTO;
|
||||||
import com.cisd.tms.modules.mk.dto.UKeySignEntity;
|
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.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
* @since 2026/3/4
|
* @since 2026/3/4
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1")
|
@RequestMapping("/api/v1")
|
||||||
@Tag(name = "主密钥管理", description = "LMK 生成、恢复、状态查询和销毁接口")
|
@Tag(name = "主密钥管理", description = "LMK 生成、恢复、状态查询和销毁接口")
|
||||||
@ -56,31 +56,49 @@ public class LmkController {
|
|||||||
return ApiResponse.success(lmkService.queryMasterKeyStatus());
|
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")
|
@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) {
|
public ApiResponse<UKeySignResult> uKeySign(@Valid @RequestBody UKeySignDTO uKeySignDTO) {
|
||||||
String signValue = signUkeyPayload(uKeySignDTO);
|
String signValue = signUkeyPayload(uKeySignDTO);
|
||||||
int componentIndex = Integer.parseInt(uKeySignDTO.getUid());
|
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()
|
return ApiResponse.success(UKeySignResult.builder()
|
||||||
.sign(signValue)
|
.sign(signValue)
|
||||||
.component(material.getComponent())
|
// .component(material.getComponent())
|
||||||
.lmkMac(material.getLmkMac())
|
// .lmkMac(material.getLmkMac())
|
||||||
|
.backupPacket(packet)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 恢复主密钥。
|
* 恢复所有备份密钥。
|
||||||
* 请求体需同时传入 lmkMac 和 3 个按顺序排列的主密钥分量字符串。
|
* 请求体需传入 componentIndex=1/2/3 的三份分量包。
|
||||||
* 第 1 个元素对应分量 1,第 2 个元素对应分量 2,第 3 个元素对应分量 3。
|
* 服务端会先执行 InitIdentify,然后依次恢复 LMK、加载 LMK、恢复 IK、恢复用户密钥。
|
||||||
*/
|
*/
|
||||||
@PostMapping("/masterKey/recover")
|
@PostMapping("/masterKey/recover")
|
||||||
@Operation(summary = "恢复 LMK", description = "请求体需传入 8 字节校验值 lmkMac 和 3 个按顺序排列的主密钥分量字符串,列表下标 0、1、2 分别对应分量 1、2、3。服务端按 SDFE_LmkComponent 结构拼接后执行恢复并加载 LMK。")
|
@Operation(summary = "恢复全部密钥", description = "请求体需传入三份按 componentIndex 标识的分量包。三份分量包必须分别对应 componentIndex=1、2、3。服务端会依次恢复 LMK、IK 和用户密钥。")
|
||||||
public ApiResponse<Void> recoverLmkEx(@Valid @RequestBody MasterKeyRecoverRequest request) {
|
public ApiResponse<Void> recoverLmkEx(@Valid @RequestBody MasterKeyRecoverPacketsRequest request) {
|
||||||
lmkService.recoverLmkEx(request.getLmkMac(), request.getComponents());
|
lmkService.recoverKeyPackets(request.getPackets());
|
||||||
return ApiResponse.success();
|
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) {
|
private String signUkeyPayload(UKeySignDTO uKeySignDTO) {
|
||||||
String iPubKey = lmkService.exportIkPublicKeyHex();
|
String iPubKey = lmkService.exportIkPublicKeyHex();
|
||||||
String payload;
|
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 component;
|
||||||
|
|
||||||
private String lmkMac;
|
private String lmkMac;
|
||||||
|
|
||||||
|
private MasterKeyBackupPacket backupPacket;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,22 @@
|
|||||||
package com.cisd.tms.modules.mk.service;
|
package com.cisd.tms.modules.mk.service;
|
||||||
|
|
||||||
import com.cisd.tms.common.util.DivisionUtils;
|
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.EccRefPublicKey;
|
||||||
import com.cisd.tms.integration.crypto.pcie.jna.EccSignature;
|
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.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.EccInternalSignRequest;
|
||||||
import com.cisd.tms.integration.crypto.pcie.model.EccInternalVerifyRequest;
|
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.integration.crypto.pcie.service.PcieCryptoService;
|
||||||
import com.cisd.tms.modules.mk.config.MasterKeyInitProperties;
|
import com.cisd.tms.modules.mk.config.MasterKeyInitProperties;
|
||||||
import com.cisd.tms.modules.mk.common.LMKConstant;
|
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.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.dto.MasterKeyStateResult;
|
||||||
import com.cisd.tms.modules.mk.enums.IKEnums;
|
import com.cisd.tms.modules.mk.enums.IKEnums;
|
||||||
import com.cisd.tms.modules.mk.enums.MasterKeyStatus;
|
import com.cisd.tms.modules.mk.enums.MasterKeyStatus;
|
||||||
@ -18,6 +25,7 @@ import org.bouncycastle.util.encoders.Hex;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.HashMap;
|
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 AUTH_SIGN_KEY_INDEX = IKEnums.KEY_TYPE_AUTH.getCode();
|
||||||
private static final int LMK_MAC_BYTE_LENGTH = 8;
|
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 PcieCryptoService pcieCryptoService;
|
||||||
private final MasterKeyInitProperties masterKeyInitProperties;
|
private final MasterKeyInitProperties masterKeyInitProperties;
|
||||||
|
|
||||||
@ -74,35 +88,76 @@ public class LmkService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String signIk(String rawData) {
|
public String signIk(String rawData) {
|
||||||
|
byte[] digest = digestForInternalSign(rawData);
|
||||||
EccInternalSignRequest request = new EccInternalSignRequest();
|
EccInternalSignRequest request = new EccInternalSignRequest();
|
||||||
request.setKeyIndex(AUTH_SIGN_KEY_INDEX);
|
request.setKeyIndex(AUTH_SIGN_KEY_INDEX);
|
||||||
request.setData(rawData.getBytes(StandardCharsets.UTF_8));
|
request.setData(digest);
|
||||||
request.setSignatureBufferSize(new EccSignature().size());
|
request.setSignatureBufferSize(new EccSignature().size());
|
||||||
BackupDataResult result = pcieCryptoService.eccInternalSign(request);
|
BackupDataResult result = pcieCryptoService.eccInternalSign(request);
|
||||||
return Hex.toHexString(result.getData());
|
return Hex.toHexString(result.getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void verifyIk(String rawData, String signatureHex) {
|
public void verifyIk(String rawData, String signatureHex) {
|
||||||
|
byte[] digest = digestForInternalSign(rawData);
|
||||||
EccInternalVerifyRequest request = new EccInternalVerifyRequest();
|
EccInternalVerifyRequest request = new EccInternalVerifyRequest();
|
||||||
request.setKeyIndex(AUTH_SIGN_KEY_INDEX);
|
request.setKeyIndex(AUTH_SIGN_KEY_INDEX);
|
||||||
request.setData(rawData.getBytes(StandardCharsets.UTF_8));
|
request.setData(digest);
|
||||||
request.setSignature(Hex.decode(signatureHex));
|
request.setSignature(Hex.decode(signatureHex));
|
||||||
pcieCryptoService.eccInternalVerify(request);
|
pcieCryptoService.eccInternalVerify(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MasterKeyBackupMaterial getBackupMaterial(int uid) {
|
public MasterKeyBackupPacket buildBackupPacket(int componentIndex) {
|
||||||
ParsedMasterKeyBackup parsedBackup = parseBackupMaterial();
|
int index = requireComponentIndex(componentIndex);
|
||||||
String component = parsedBackup.componentMap().get(uid);
|
ParsedMasterKeyBackup lmkBackup = parseBackupMaterial();
|
||||||
if (component == null) {
|
ParsedIkBackup authIkBackup = parseIkBackupMaterial(IKEnums.KEY_TYPE_AUTH.getCode());
|
||||||
throw new IllegalArgumentException("invalid component index: " + uid);
|
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;
|
||||||
}
|
}
|
||||||
return new MasterKeyBackupMaterial(component, parsedBackup.lmkMacHex());
|
|
||||||
|
public MasterKeyBackupMaterial getBackupMaterial(int uid) {
|
||||||
|
MasterKeyBackupPacket packet = buildBackupPacket(uid);
|
||||||
|
return new MasterKeyBackupMaterial(packet.getLmk().getComponent(), packet.getLmk().getLmkMac());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getComponent(int uid) {
|
public String getComponent(int uid) {
|
||||||
return getBackupMaterial(uid).getComponent();
|
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) {
|
public void recoverLmkEx(String lmkMacHex, List<String> components) {
|
||||||
byte[] oldPin = decodeConfiguredPin("tms.mk.init-identify.old-pin-base64", masterKeyInitProperties.getOldPinBase64());
|
byte[] oldPin = decodeConfiguredPin("tms.mk.init-identify.old-pin-base64", masterKeyInitProperties.getOldPinBase64());
|
||||||
byte[] newPin = decodeConfiguredPin("tms.mk.init-identify.new-pin-base64", masterKeyInitProperties.getNewPinBase64());
|
byte[] newPin = decodeConfiguredPin("tms.mk.init-identify.new-pin-base64", masterKeyInitProperties.getNewPinBase64());
|
||||||
@ -141,8 +196,48 @@ public class LmkService {
|
|||||||
return lmk.toString();
|
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() {
|
private ParsedMasterKeyBackup parseBackupMaterial() {
|
||||||
//todo 需要将主密钥分量、内部密钥分量一起拆分后进行备份,密码卡暂时没有导出内部密钥分量接口
|
|
||||||
BackupDataResult backupData = pcieCryptoService.backupLmkEx();
|
BackupDataResult backupData = pcieCryptoService.backupLmkEx();
|
||||||
byte[] normalized = normalizeBackupData(backupData);
|
byte[] normalized = normalizeBackupData(backupData);
|
||||||
if (normalized.length < LMK_MAC_BYTE_LENGTH) {
|
if (normalized.length < LMK_MAC_BYTE_LENGTH) {
|
||||||
@ -158,6 +253,29 @@ public class LmkService {
|
|||||||
return new ParsedMasterKeyBackup(Hex.toHexString(lmkMac), componentMap);
|
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) {
|
private byte[] normalizeBackupData(BackupDataResult backupData) {
|
||||||
byte[] data = backupData.getData();
|
byte[] data = backupData.getData();
|
||||||
if (data == null || data.length == 0) {
|
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 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;
|
package com.cisd.tms.modules.mk.controller;
|
||||||
|
|
||||||
import com.cisd.tms.common.exception.GlobalExceptionHandler;
|
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.dto.MasterKeyStateResult;
|
||||||
import com.cisd.tms.modules.mk.service.LmkService;
|
import com.cisd.tms.modules.mk.service.LmkService;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
@ -26,8 +29,16 @@ class LmkControllerTest {
|
|||||||
LmkService lmkService = Mockito.mock(LmkService.class);
|
LmkService lmkService = Mockito.mock(LmkService.class);
|
||||||
Mockito.when(lmkService.exportIkPublicKeyHex()).thenReturn("IK-PUB-001");
|
Mockito.when(lmkService.exportIkPublicKeyHex()).thenReturn("IK-PUB-001");
|
||||||
Mockito.when(lmkService.signIk(ArgumentMatchers.anyString())).thenReturn("SIGN-001");
|
Mockito.when(lmkService.signIk(ArgumentMatchers.anyString())).thenReturn("SIGN-001");
|
||||||
Mockito.when(lmkService.getBackupMaterial(2))
|
MasterKeyBackupPacket packet = new MasterKeyBackupPacket();
|
||||||
.thenReturn(new MasterKeyBackupMaterial("COMP-002", "LMK-MAC-001"));
|
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()))
|
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new LmkController(lmkService, new ObjectMapper()))
|
||||||
.setControllerAdvice(new GlobalExceptionHandler())
|
.setControllerAdvice(new GlobalExceptionHandler())
|
||||||
@ -46,15 +57,21 @@ class LmkControllerTest {
|
|||||||
"""))
|
"""))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(containsString("\"sign\":\"SIGN-001\"")))
|
.andExpect(content().string(containsString("\"sign\":\"SIGN-001\"")))
|
||||||
.andExpect(content().string(containsString("\"component\":\"COMP-002\"")))
|
.andExpect(content().string(containsString("\"componentIndex\":2")))
|
||||||
.andExpect(content().string(containsString("\"lmkMac\":\"LMK-MAC-001\"")));
|
.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).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
|
@Test
|
||||||
void shouldRecoverLmkExUsingLmkMacAndOrderedComponents() throws Exception {
|
void shouldRecoverKeyPacketsUsingOrderedPackets() throws Exception {
|
||||||
LmkService lmkService = Mockito.mock(LmkService.class);
|
LmkService lmkService = Mockito.mock(LmkService.class);
|
||||||
|
|
||||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new LmkController(lmkService, new ObjectMapper()))
|
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new LmkController(lmkService, new ObjectMapper()))
|
||||||
@ -65,17 +82,41 @@ class LmkControllerTest {
|
|||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.content("""
|
.content("""
|
||||||
{
|
{
|
||||||
|
"packets": [
|
||||||
|
{
|
||||||
|
"componentIndex": 1,
|
||||||
|
"lmk": {
|
||||||
"lmkMac": "a1a2a3a4a5a6a7a8",
|
"lmkMac": "a1a2a3a4a5a6a7a8",
|
||||||
"components": [
|
"component": "0102"
|
||||||
"0102",
|
},
|
||||||
"0304",
|
"ikAuth": {
|
||||||
"0506"
|
"mac": "1111111111111111",
|
||||||
|
"component": "0304"
|
||||||
|
},
|
||||||
|
"ikDevice": {
|
||||||
|
"mac": "2222222222222222",
|
||||||
|
"component": "0506"
|
||||||
|
},
|
||||||
|
"userKeys": [
|
||||||
|
{
|
||||||
|
"keyIndex": 1,
|
||||||
|
"keyType": 0,
|
||||||
|
"component": "0708"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentIndex": 3
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
.andExpect(status().isOk());
|
.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
|
@Test
|
||||||
|
|||||||
@ -1,16 +1,24 @@
|
|||||||
package com.cisd.tms.modules.mk.service;
|
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.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.integration.crypto.pcie.service.PcieCryptoService;
|
||||||
import com.cisd.tms.modules.mk.config.MasterKeyInitProperties;
|
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 com.cisd.tms.modules.mk.dto.MasterKeyStateResult;
|
||||||
import java.util.List;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.InOrder;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InOrder;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
class LmkServiceTest {
|
class LmkServiceTest {
|
||||||
@ -79,48 +87,181 @@ class LmkServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldReturnIndexedMasterKeyComponentAndMacFromBackupBlob() {
|
void shouldBuildBackupPacketForSingleComponentIndex() {
|
||||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||||
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
||||||
BackupDataResult backup = new BackupDataResult();
|
BackupDataResult lmkBackup = new BackupDataResult();
|
||||||
backup.setLength(20);
|
lmkBackup.setLength(20);
|
||||||
backup.setData(new byte[] {
|
lmkBackup.setData(new byte[] {
|
||||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||||
0x01, 0x02, 0x03, 0x04,
|
0x01, 0x02, 0x03, 0x04,
|
||||||
0x05, 0x06, 0x07, 0x08,
|
0x05, 0x06, 0x07, 0x08,
|
||||||
0x09, 0x0A, 0x0B, 0x0C
|
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);
|
LmkService service = new LmkService(pcieCryptoService, properties);
|
||||||
|
|
||||||
MasterKeyBackupMaterial material = service.getBackupMaterial(2);
|
MasterKeyBackupPacket packet = service.buildBackupPacket(2);
|
||||||
|
|
||||||
Assertions.assertEquals("05060708", material.getComponent());
|
Assertions.assertEquals(2, packet.getComponentIndex());
|
||||||
Assertions.assertEquals("1112131415161718", material.getLmkMac());
|
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
|
@Test
|
||||||
void shouldInitIdentifyBeforeRecoverLmkExAndLoadIt() {
|
void shouldRecoverAllKeyPacketsInOrder() {
|
||||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||||
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
||||||
LmkService service = new LmkService(pcieCryptoService, properties);
|
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[]> oldPinCaptor = ArgumentCaptor.forClass(byte[].class);
|
||||||
ArgumentCaptor<byte[]> newPinCaptor = 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 inOrder = Mockito.inOrder(pcieCryptoService);
|
||||||
inOrder.verify(pcieCryptoService).initIdentify(oldPinCaptor.capture(), newPinCaptor.capture());
|
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).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("12345678".getBytes(StandardCharsets.UTF_8), oldPinCaptor.getValue());
|
||||||
Assertions.assertArrayEquals("87654321".getBytes(StandardCharsets.UTF_8), newPinCaptor.getValue());
|
Assertions.assertArrayEquals("87654321".getBytes(StandardCharsets.UTF_8), newPinCaptor.getValue());
|
||||||
Assertions.assertArrayEquals(new byte[] {
|
Assertions.assertArrayEquals(new byte[] {
|
||||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06
|
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) {
|
private static MasterKeyInitProperties configuredPins(String oldPinBase64, String newPinBase64) {
|
||||||
@ -129,4 +270,16 @@ class LmkServiceTest {
|
|||||||
properties.setNewPinBase64(newPinBase64);
|
properties.setNewPinBase64(newPinBase64);
|
||||||
return properties;
|
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