密钥恢复优化

This commit is contained in:
waner 2026-05-11 16:52:25 +08:00
parent 54cbef1ef3
commit d1f136f8e9
10 changed files with 387 additions and 54 deletions

View File

@ -0,0 +1,61 @@
package com.cisd.tms.integration.crypto.pcie.model;
import java.util.List;
public class MasterKeyRecoveryRequest {
private byte[] oldPin;
private byte[] newPin;
private byte[] lmkComponent;
private byte[] authIkComponent;
private byte[] deviceIkComponent;
private List<RecoverUserKeyRequest> userKeyRequests;
public byte[] getOldPin() {
return oldPin;
}
public void setOldPin(byte[] oldPin) {
this.oldPin = oldPin;
}
public byte[] getNewPin() {
return newPin;
}
public void setNewPin(byte[] newPin) {
this.newPin = newPin;
}
public byte[] getLmkComponent() {
return lmkComponent;
}
public void setLmkComponent(byte[] lmkComponent) {
this.lmkComponent = lmkComponent;
}
public byte[] getAuthIkComponent() {
return authIkComponent;
}
public void setAuthIkComponent(byte[] authIkComponent) {
this.authIkComponent = authIkComponent;
}
public byte[] getDeviceIkComponent() {
return deviceIkComponent;
}
public void setDeviceIkComponent(byte[] deviceIkComponent) {
this.deviceIkComponent = deviceIkComponent;
}
public List<RecoverUserKeyRequest> getUserKeyRequests() {
return userKeyRequests;
}
public void setUserKeyRequests(List<RecoverUserKeyRequest> userKeyRequests) {
this.userKeyRequests = userKeyRequests;
}
}

View File

@ -0,0 +1,23 @@
package com.cisd.tms.integration.crypto.pcie.model;
public class MasterKeyRecoveryResult {
private byte[] lmkSeedMac;
private DeviceStatusResult deviceStatus;
public byte[] getLmkSeedMac() {
return lmkSeedMac;
}
public void setLmkSeedMac(byte[] lmkSeedMac) {
this.lmkSeedMac = lmkSeedMac;
}
public DeviceStatusResult getDeviceStatus() {
return deviceStatus;
}
public void setDeviceStatus(DeviceStatusResult deviceStatus) {
this.deviceStatus = deviceStatus;
}
}

View File

@ -12,6 +12,7 @@ import com.sun.jna.ptr.PointerByReference;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
public class JnaPcieCryptoService implements PcieCryptoService {
@ -177,16 +178,7 @@ public class JnaPcieCryptoService implements PcieCryptoService {
@Override
public DeviceStatusResult getDeviceStatus() {
return sessionTemplate.withSession("SDFE_DeviceStatusGet", (lib, deviceHandle, sessionHandle) -> {
SdfeDeviceStatus status = new SdfeDeviceStatus();
sessionTemplate.ensureSuccess("SDFE_DeviceStatusGet", lib.SDFE_DeviceStatusGet(sessionHandle, status));
status.read();
int size = status.size();
DeviceStatusResult result = new DeviceStatusResult();
result.setLength(size);
result.setStatusData(status.getPointer().getByteArray(0, size));
PcieDeviceStatusFormatter.enrich(result, status);
return result;
return readDeviceStatus(lib, sessionHandle);
});
}
@ -1928,6 +1920,57 @@ public class JnaPcieCryptoService implements PcieCryptoService {
});
}
@Override
public MasterKeyRecoveryResult recoverMasterKeyMaterial(MasterKeyRecoveryRequest request) {
MasterKeyRecoveryRequest req = requireRequest("request", request);
byte[] oldPin = requireNonEmptyBytes("oldPin", req.getOldPin());
byte[] newPin = requireNonEmptyBytes("newPin", req.getNewPin());
SdfeLmkComponent lmkComponent = toSdfeLmkComponent("lmkComponent", req.getLmkComponent());
SdfeIkComponent authIkComponent = toSdfeIkComponent("authIkComponent", req.getAuthIkComponent());
SdfeIkComponent deviceIkComponent = toSdfeIkComponent("deviceIkComponent", req.getDeviceIkComponent());
List<RecoverUserKeyRequest> userKeyRequests = requireUserKeyRequests(req.getUserKeyRequests());
try {
return sessionTemplate.withSession("SDFE_RecoverMasterKeyMaterial", (lib, deviceHandle, sessionHandle) -> {
sessionTemplate.ensureSuccess(
"SDFE_InitIdentify",
lib.SDFE_InitIdentify(sessionHandle, oldPin, oldPin.length, newPin, newPin.length)
);
sessionTemplate.ensureSuccess("SDFE_RecoverLMK_EX", lib.SDFE_RecoverLMK_EX(sessionHandle, lmkComponent));
sessionTemplate.ensureSuccess("SDFE_LoadLMK", lib.SDFE_LoadLMK(sessionHandle));
sessionTemplate.ensureSuccess(
"SDFE_RecoverIK_EX",
lib.SDFE_RecoverIK_EX(sessionHandle, IK_KEY_TYPE_AUTH, authIkComponent)
);
sessionTemplate.ensureSuccess(
"SDFE_RecoverIK_EX",
lib.SDFE_RecoverIK_EX(sessionHandle, IK_KEY_TYPE_DEVICE, deviceIkComponent)
);
DeviceStatusResult deviceStatus = readDeviceStatus(lib, sessionHandle);
for (RecoverUserKeyRequest userKeyRequest : userKeyRequests) {
recoverUserKeyInCurrentSession(lib, sessionHandle, userKeyRequest);
}
sessionTemplate.ensureSuccess("SDFE_CheckLMK", lib.SDFE_CheckLMK(sessionHandle));
byte[] mac = new byte[LMK_SEED_MAC_LENGTH];
sessionTemplate.ensureSuccess("SDFE_ExportLMKSeedMAC", lib.SDFE_ExportLMKSeedMAC(sessionHandle, mac));
MasterKeyRecoveryResult result = new MasterKeyRecoveryResult();
result.setDeviceStatus(deviceStatus);
result.setLmkSeedMac(Arrays.copyOf(mac, mac.length));
return result;
});
} finally {
wipe(oldPin);
wipe(newPin);
wipe(req.getLmkComponent());
wipe(req.getAuthIkComponent());
wipe(req.getDeviceIkComponent());
for (RecoverUserKeyRequest userKeyRequest : userKeyRequests) {
wipe(userKeyRequest.getEncryptedKey());
}
}
}
@Override
public void generateIk(int keyType) {
int safeKeyType = requireNonNegative("keyType", keyType);
@ -2057,6 +2100,54 @@ public class JnaPcieCryptoService implements PcieCryptoService {
});
}
private DeviceStatusResult readDeviceStatus(PcieNativeLibrary lib, Pointer sessionHandle) {
SdfeDeviceStatus status = new SdfeDeviceStatus();
sessionTemplate.ensureSuccess("SDFE_DeviceStatusGet", lib.SDFE_DeviceStatusGet(sessionHandle, status));
status.read();
int size = status.size();
DeviceStatusResult result = new DeviceStatusResult();
result.setLength(size);
result.setStatusData(status.getPointer().getByteArray(0, size));
PcieDeviceStatusFormatter.enrich(result, status);
return result;
}
private static List<RecoverUserKeyRequest> requireUserKeyRequests(List<RecoverUserKeyRequest> requests) {
if (requests == null || requests.isEmpty()) {
throw new IllegalArgumentException("userKeyRequests must not be empty");
}
for (RecoverUserKeyRequest request : requests) {
RecoverUserKeyRequest req = requireRequest("userKeyRequest", request);
requireNonNegative("keyIndex", req.getKeyIndex());
requireUserKeyType(req.getKeyType());
requireNonEmptyBytes("encryptedKey", req.getEncryptedKey());
int storeFlag = req.getStoreFlag();
if (storeFlag != 0 && storeFlag != 1) {
throw new IllegalArgumentException("storeFlag必须为0或1");
}
}
return List.copyOf(requests);
}
private void recoverUserKeyInCurrentSession(
PcieNativeLibrary lib,
Pointer sessionHandle,
RecoverUserKeyRequest request
) {
sessionTemplate.ensureSuccess(
"SDFE_RecoverUserKey",
lib.SDFE_RecoverUserKey(
sessionHandle,
request.getKeyIndex(),
request.getKeyType(),
request.getEncryptedKey(),
request.getEncryptedKey().length,
(byte) request.getStoreFlag()
)
);
}
@FunctionalInterface
private interface KeyHandleCallback<T> {
T apply(Pointer keyHandle);

View File

@ -63,6 +63,8 @@ import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest;
import com.cisd.tms.integration.crypto.pcie.model.KekComponentRequest;
import com.cisd.tms.integration.crypto.pcie.model.KeyStatusResult;
import com.cisd.tms.integration.crypto.pcie.model.MacCalcRequest;
import com.cisd.tms.integration.crypto.pcie.model.MasterKeyRecoveryRequest;
import com.cisd.tms.integration.crypto.pcie.model.MasterKeyRecoveryResult;
import com.cisd.tms.integration.crypto.pcie.model.PrivateKeyAccessRequest;
import com.cisd.tms.integration.crypto.pcie.model.RecoverKekRequest;
import com.cisd.tms.integration.crypto.pcie.model.RecoverUserKeyRequest;
@ -904,6 +906,28 @@ public class MockPcieCryptoService implements PcieCryptoService {
requireNonEmptyBytes("lmkComponent", lmkComponent);
}
@Override
public MasterKeyRecoveryResult recoverMasterKeyMaterial(MasterKeyRecoveryRequest request) {
MasterKeyRecoveryRequest req = requireRequest("request", request);
initIdentify(req.getOldPin(), req.getNewPin());
recoverLmkEx(req.getLmkComponent());
loadLmk();
recoverIkComponent(2, req.getAuthIkComponent());
recoverIkComponent(1, req.getDeviceIkComponent());
if (req.getUserKeyRequests() == null || req.getUserKeyRequests().isEmpty()) {
throw new IllegalArgumentException("userKeyRequests must not be empty");
}
req.getUserKeyRequests().forEach(this::recoverUserKey);
if (!checkLmk()) {
throw new IllegalStateException("主密钥恢复后校验失败");
}
MasterKeyRecoveryResult result = new MasterKeyRecoveryResult();
result.setDeviceStatus(getDeviceStatus());
result.setLmkSeedMac(exportLmkSeedMac());
return result;
}
@Override
public void generateIk(int keyType) {
requireNonNegative("keyType", keyType);

View File

@ -53,6 +53,8 @@ import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest;
import com.cisd.tms.integration.crypto.pcie.model.KekComponentRequest;
import com.cisd.tms.integration.crypto.pcie.model.KeyStatusResult;
import com.cisd.tms.integration.crypto.pcie.model.MacCalcRequest;
import com.cisd.tms.integration.crypto.pcie.model.MasterKeyRecoveryRequest;
import com.cisd.tms.integration.crypto.pcie.model.MasterKeyRecoveryResult;
import com.cisd.tms.integration.crypto.pcie.model.PrivateKeyAccessRequest;
import com.cisd.tms.integration.crypto.pcie.model.RecoverKekRequest;
import com.cisd.tms.integration.crypto.pcie.model.RecoverUserKeyRequest;
@ -564,6 +566,11 @@ public interface PcieCryptoService {
*/
void recoverLmkEx(byte[] lmkComponent);
/**
* 在单个设备 session 中恢复 LMKIK 和用户密钥并返回恢复后的 LMK seed MAC
*/
MasterKeyRecoveryResult recoverMasterKeyMaterial(MasterKeyRecoveryRequest request);
//----------------------------------------IK 生命周期类接口------------------------------------------
/**

View File

@ -27,7 +27,7 @@ public interface LmkService {
String getComponent(int uid);
void recoverKeyPackets(List<MasterKeyBackupPacket> packets);
MasterKeyStateResult recoverKeyPackets(List<MasterKeyBackupPacket> packets);
void recoverLmkEx(String lmkMacHex, List<String> components);

View File

@ -170,7 +170,7 @@ public class LmkServiceImpl implements LmkService {
}
@Override
public void recoverKeyPackets(List<MasterKeyBackupPacket> packets) {
public MasterKeyStateResult recoverKeyPackets(List<MasterKeyBackupPacket> packets) {
// 进入恢复流程后旧的备份轮次缓存不再可信避免和恢复后的新密钥体系混用
clearCachedBackupRound();
// 调用方可以任意顺序传入两份包这里统一按 packetIndex 排序并校验必须是 12 两包
@ -178,21 +178,25 @@ public class LmkServiceImpl implements LmkService {
byte[] oldPin = decodeConfiguredPin("tms.mk.init-identify.old-pin-base64", masterKeyInitProperties.getOldPinBase64());
byte[] newPin = decodeConfiguredPin("tms.mk.init-identify.new-pin-base64", masterKeyInitProperties.getNewPinBase64());
// 恢复顺序不能打乱
// 1. InitIdentify 建立恢复所需的设备认证上下文
// 2. 先恢复 LMK LoadLMK后续 IK 和用户密钥都依赖 LMK 环境
// 3. 再恢复两把 IK
// 4. 最后恢复用户密钥
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)));
//务必先查询是否是就绪状态
DeviceStatusResult result = pcieCryptoService.getDeviceStatus();
log.info("device status:{}", result.getFsmState());
pcieCryptoService.recoverUserKey(toRecoverUserKeyRequest(orderedPackets, USER_KEY_INDEX, USER_KEY_TYPE_SIGN));
pcieCryptoService.recoverUserKey(toRecoverUserKeyRequest(orderedPackets, USER_KEY_INDEX, USER_KEY_TYPE_ENC));
MasterKeyRecoveryRequest recoveryRequest = new MasterKeyRecoveryRequest();
recoveryRequest.setOldPin(oldPin);
recoveryRequest.setNewPin(newPin);
recoveryRequest.setLmkComponent(Hex.decode(composeLmkHex(orderedPackets)));
recoveryRequest.setAuthIkComponent(Hex.decode(composeIkHex(orderedPackets, true)));
recoveryRequest.setDeviceIkComponent(Hex.decode(composeIkHex(orderedPackets, false)));
recoveryRequest.setUserKeyRequests(List.of(
toRecoverUserKeyRequest(orderedPackets, USER_KEY_INDEX, USER_KEY_TYPE_SIGN),
toRecoverUserKeyRequest(orderedPackets, USER_KEY_INDEX, USER_KEY_TYPE_ENC)
));
MasterKeyRecoveryResult recoveryResult = pcieCryptoService.recoverMasterKeyMaterial(recoveryRequest);
DeviceStatusResult deviceStatus = recoveryResult.getDeviceStatus();
if (deviceStatus != null) {
log.info("device status:{}", deviceStatus.getFsmState());
}
MasterKeyStateResult result = new MasterKeyStateResult();
result.setStatus(true);
result.setSeedMac(Hex.toHexString(recoveryResult.getLmkSeedMac()));
return result;
}
@Override

View File

@ -7,7 +7,9 @@ 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.PcieNativeLibrary;
import com.cisd.tms.integration.crypto.pcie.jna.SdfFirmwareInfo;
import com.cisd.tms.integration.crypto.pcie.jna.SdfeDeviceStatus;
import com.cisd.tms.integration.crypto.pcie.jna.SdfeIkComponent;
import com.cisd.tms.integration.crypto.pcie.jna.SdfeLmkComponent;
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.EccInternalDecryptRequest;
@ -23,6 +25,9 @@ import com.cisd.tms.integration.crypto.pcie.model.EccSessionKeyEncryptResult;
import com.cisd.tms.integration.crypto.pcie.model.FirmwareInfoResult;
import com.cisd.tms.integration.crypto.pcie.model.IkSignRequest;
import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest;
import com.cisd.tms.integration.crypto.pcie.model.MasterKeyRecoveryRequest;
import com.cisd.tms.integration.crypto.pcie.model.MasterKeyRecoveryResult;
import com.cisd.tms.integration.crypto.pcie.model.RecoverUserKeyRequest;
import com.cisd.tms.integration.crypto.pcie.model.SymmetricCryptoRequest;
import com.cisd.tms.integration.crypto.pcie.model.PrivateKeyAccessRequest;
import com.cisd.tms.integration.crypto.pcie.model.UserKeyDecryptRequest;
@ -33,6 +38,7 @@ import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@ -134,6 +140,72 @@ class JnaPcieCryptoServiceTest {
Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_RecoverIK_EX"), Mockito.any());
}
@Test
void shouldRecoverMasterKeyMaterialWithinSingleSessionAndReturnSeedMac() {
PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class);
CryptoCardProperties properties = new CryptoCardProperties();
JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties);
Pointer session = Pointer.createConstant(2);
byte[] seedMac = new byte[] {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18};
MasterKeyRecoveryRequest request = new MasterKeyRecoveryRequest();
request.setOldPin("12345678".getBytes(StandardCharsets.UTF_8));
request.setNewPin("87654321".getBytes(StandardCharsets.UTF_8));
request.setLmkComponent(filledBytes(new SdfeLmkComponent().size(), 0x21));
request.setAuthIkComponent(filledBytes(new SdfeIkComponent().size(), 0x31));
request.setDeviceIkComponent(filledBytes(new SdfeIkComponent().size(), 0x41));
RecoverUserKeyRequest signKey = new RecoverUserKeyRequest();
signKey.setKeyIndex(1);
signKey.setKeyType(0);
signKey.setEncryptedKey(new byte[] {0x01, 0x02, 0x03});
RecoverUserKeyRequest encKey = new RecoverUserKeyRequest();
encKey.setKeyIndex(1);
encKey.setKeyType(1);
encKey.setEncryptedKey(new byte[] {0x11, 0x12, 0x13});
request.setUserKeyRequests(List.of(signKey, encKey));
AtomicReference<PcieNativeLibrary> libRef = new AtomicReference<>();
Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_RecoverMasterKeyMaterial"), Mockito.any()))
.thenAnswer(invocation -> {
@SuppressWarnings("unchecked")
PcieSessionTemplate.SessionCallback<MasterKeyRecoveryResult> callback =
(PcieSessionTemplate.SessionCallback<MasterKeyRecoveryResult>) invocation.getArgument(1);
PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class);
libRef.set(lib);
Mockito.when(lib.SDFE_InitIdentify(Mockito.eq(session), Mockito.any(), Mockito.anyInt(), Mockito.any(), Mockito.anyInt())).thenReturn(0);
Mockito.when(lib.SDFE_RecoverLMK_EX(Mockito.eq(session), Mockito.any(SdfeLmkComponent.class))).thenReturn(0);
Mockito.when(lib.SDFE_LoadLMK(Mockito.eq(session))).thenReturn(0);
Mockito.when(lib.SDFE_RecoverIK_EX(Mockito.eq(session), Mockito.eq(2), Mockito.any(SdfeIkComponent.class))).thenReturn(0);
Mockito.when(lib.SDFE_RecoverIK_EX(Mockito.eq(session), Mockito.eq(1), Mockito.any(SdfeIkComponent.class))).thenReturn(0);
Mockito.when(lib.SDFE_DeviceStatusGet(Mockito.eq(session), Mockito.any(SdfeDeviceStatus.class))).thenReturn(0);
Mockito.when(lib.SDFE_RecoverUserKey(Mockito.eq(session), Mockito.eq(1), Mockito.anyInt(), Mockito.any(), Mockito.anyInt(), Mockito.anyByte())).thenReturn(0);
Mockito.when(lib.SDFE_CheckLMK(Mockito.eq(session))).thenReturn(0);
Mockito.when(lib.SDFE_ExportLMKSeedMAC(Mockito.eq(session), Mockito.any())).thenAnswer(exportInvocation -> {
byte[] out = exportInvocation.getArgument(1);
System.arraycopy(seedMac, 0, out, 0, seedMac.length);
return 0;
});
return callback.apply(lib, Pointer.createConstant(1), session);
});
MasterKeyRecoveryResult result = service.recoverMasterKeyMaterial(request);
Assertions.assertArrayEquals(seedMac, result.getLmkSeedMac());
Assertions.assertNotNull(result.getDeviceStatus());
Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_RecoverMasterKeyMaterial"), Mockito.any());
PcieNativeLibrary lib = libRef.get();
InOrder inOrder = Mockito.inOrder(lib);
inOrder.verify(lib).SDFE_InitIdentify(Mockito.eq(session), Mockito.any(), Mockito.anyInt(), Mockito.any(), Mockito.anyInt());
inOrder.verify(lib).SDFE_RecoverLMK_EX(Mockito.eq(session), Mockito.any(SdfeLmkComponent.class));
inOrder.verify(lib).SDFE_LoadLMK(Mockito.eq(session));
inOrder.verify(lib).SDFE_RecoverIK_EX(Mockito.eq(session), Mockito.eq(2), Mockito.any(SdfeIkComponent.class));
inOrder.verify(lib).SDFE_RecoverIK_EX(Mockito.eq(session), Mockito.eq(1), Mockito.any(SdfeIkComponent.class));
inOrder.verify(lib).SDFE_DeviceStatusGet(Mockito.eq(session), Mockito.any(SdfeDeviceStatus.class));
inOrder.verify(lib, Mockito.times(2)).SDFE_RecoverUserKey(Mockito.eq(session), Mockito.eq(1), Mockito.anyInt(), Mockito.any(), Mockito.anyInt(), Mockito.anyByte());
inOrder.verify(lib).SDFE_CheckLMK(Mockito.eq(session));
inOrder.verify(lib).SDFE_ExportLMKSeedMAC(Mockito.eq(session), Mockito.any());
}
@Test
void shouldExportIkPublicKeyViaSdfeExportIkPublicKey() {
PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class);
@ -875,4 +947,10 @@ class JnaPcieCryptoServiceTest {
Assertions.assertArrayEquals(new byte[] {0x21, 0x22, 0x23}, verifyCaptor.getValue().getData());
Assertions.assertArrayEquals(new byte[] {0x31, 0x32}, verifyCaptor.getValue().getSignature());
}
private static byte[] filledBytes(int length, int value) {
byte[] bytes = new byte[length];
Arrays.fill(bytes, (byte) value);
return bytes;
}
}

View File

@ -1,6 +1,7 @@
package com.cisd.tms.modules.mk.controller;
import com.cisd.tms.common.exception.GlobalExceptionHandler;
import com.cisd.tms.modules.mk.dto.MasterKeyStateResult;
import com.cisd.tms.modules.mk.service.LmkService;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@ -14,6 +15,50 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
class LmkControllerTest {
@Test
void shouldReturnRecoveredMasterKeySeedMac() throws Exception {
LmkService lmkService = Mockito.mock(LmkService.class);
MasterKeyStateResult result = new MasterKeyStateResult();
result.setStatus(true);
result.setSeedMac("1112131415161718");
Mockito.when(lmkService.recoverKeyPackets(Mockito.any())).thenReturn(result);
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new LmkController(lmkService))
.setControllerAdvice(new GlobalExceptionHandler())
.build();
mockMvc.perform(post("/api/v1/masterKey/recover")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"packets": [
{
"packetIndex": 1,
"lmk": {
"lmkMac": "1112131415161718",
"components": {
"1": "010203040506",
"2": "0708090a0b0c"
}
}
},
{
"packetIndex": 2,
"lmk": {
"lmkMac": "1112131415161718",
"components": {
"2": "0708090a0b0c",
"3": "131415161718"
}
}
}
]
}
"""))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.status").value(true))
.andExpect(jsonPath("$.data.seedMac").value("1112131415161718"));
}
@Test
void shouldRejectRecoverPacketsWithPacketIndexesOtherThanOneAndTwo() throws Exception {
LmkService lmkService = Mockito.mock(LmkService.class);

View File

@ -10,6 +10,8 @@ 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.IkSignRequest;
import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest;
import com.cisd.tms.integration.crypto.pcie.model.MasterKeyRecoveryRequest;
import com.cisd.tms.integration.crypto.pcie.model.MasterKeyRecoveryResult;
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;
@ -68,7 +70,7 @@ class LmkServiceTest {
}
@Test
void shouldDestroyMasterKeyInOriginalOrder() {
void shouldDestroyMasterKeyAfterDeletingUserKey() {
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
LmkService service = new LmkServiceImpl(pcieCryptoService, properties);
@ -76,10 +78,10 @@ class LmkServiceTest {
service.destroyMasterKey();
InOrder inOrder = Mockito.inOrder(pcieCryptoService);
inOrder.verify(pcieCryptoService).deleteUserKey(1);
inOrder.verify(pcieCryptoService).destroyLmk();
inOrder.verify(pcieCryptoService).destroyIk(2);
inOrder.verify(pcieCryptoService).destroyIk(1);
inOrder.verify(pcieCryptoService).deleteUserKey(1);
}
@Test
@ -299,40 +301,38 @@ class LmkServiceTest {
void shouldRecoverAllKeyPacketsInOrder() {
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
DeviceStatusResult deviceStatus = new DeviceStatusResult();
deviceStatus.setFsmState(0);
Mockito.when(pcieCryptoService.getDeviceStatus()).thenReturn(deviceStatus);
MasterKeyRecoveryResult recoveryResult = new MasterKeyRecoveryResult();
recoveryResult.setLmkSeedMac(hex("1112131415161718"));
recoveryResult.setDeviceStatus(new DeviceStatusResult());
Mockito.when(pcieCryptoService.recoverMasterKeyMaterial(Mockito.any())).thenReturn(recoveryResult);
LmkService service = new LmkServiceImpl(pcieCryptoService, properties);
MasterKeyBackupPacket packet1 = recoverPacketFixture(1);
MasterKeyBackupPacket packet2 = recoverPacketFixture(2);
service.recoverKeyPackets(List.of(packet1, packet2));
MasterKeyStateResult result = service.recoverKeyPackets(List.of(packet1, packet2));
ArgumentCaptor<byte[]> oldPinCaptor = ArgumentCaptor.forClass(byte[].class);
ArgumentCaptor<byte[]> newPinCaptor = 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> recoverCaptor = ArgumentCaptor.forClass(RecoverUserKeyRequest.class);
InOrder inOrder = Mockito.inOrder(pcieCryptoService);
inOrder.verify(pcieCryptoService).initIdentify(oldPinCaptor.capture(), newPinCaptor.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).getDeviceStatus();
inOrder.verify(pcieCryptoService, Mockito.times(2)).recoverUserKey(recoverCaptor.capture());
Assertions.assertArrayEquals("12345678".getBytes(StandardCharsets.UTF_8), oldPinCaptor.getValue());
Assertions.assertArrayEquals("87654321".getBytes(StandardCharsets.UTF_8), newPinCaptor.getValue());
ArgumentCaptor<MasterKeyRecoveryRequest> requestCaptor = ArgumentCaptor.forClass(MasterKeyRecoveryRequest.class);
Mockito.verify(pcieCryptoService).recoverMasterKeyMaterial(requestCaptor.capture());
MasterKeyRecoveryRequest recoveryRequest = requestCaptor.getValue();
Assertions.assertArrayEquals("12345678".getBytes(StandardCharsets.UTF_8), recoveryRequest.getOldPin());
Assertions.assertArrayEquals("87654321".getBytes(StandardCharsets.UTF_8), recoveryRequest.getNewPin());
Assertions.assertArrayEquals(new byte[] {
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06
}, lmkCaptor.getValue());
Assertions.assertArrayEquals(hex("1112131415162122232425262728313233344142434445464748"), ikAuthCaptor.getValue());
Assertions.assertArrayEquals(hex("2122232425263132333435363738515253546162636465666768"), ikDeviceCaptor.getValue());
Assertions.assertArrayEquals(hex("010203040506"), recoverCaptor.getAllValues().get(0).getEncryptedKey());
Assertions.assertArrayEquals(hex("111213141516"), recoverCaptor.getAllValues().get(1).getEncryptedKey());
}, recoveryRequest.getLmkComponent());
Assertions.assertArrayEquals(hex("1112131415162122232425262728313233344142434445464748"), recoveryRequest.getAuthIkComponent());
Assertions.assertArrayEquals(hex("2122232425263132333435363738515253546162636465666768"), recoveryRequest.getDeviceIkComponent());
Assertions.assertEquals(2, recoveryRequest.getUserKeyRequests().size());
Assertions.assertArrayEquals(hex("010203040506"), recoveryRequest.getUserKeyRequests().get(0).getEncryptedKey());
Assertions.assertArrayEquals(hex("111213141516"), recoveryRequest.getUserKeyRequests().get(1).getEncryptedKey());
Assertions.assertTrue(result.isStatus());
Assertions.assertEquals("1112131415161718", result.getSeedMac());
Mockito.verify(pcieCryptoService, Mockito.never()).initIdentify(Mockito.any(), Mockito.any());
Mockito.verify(pcieCryptoService, Mockito.never()).recoverLmkEx(Mockito.any());
Mockito.verify(pcieCryptoService, Mockito.never()).loadLmk();
Mockito.verify(pcieCryptoService, Mockito.never()).recoverIkComponent(Mockito.anyInt(), Mockito.any());
Mockito.verify(pcieCryptoService, Mockito.never()).recoverUserKey(Mockito.any());
}
@Test