密钥恢复优化

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
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
@@ -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);
@@ -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 中恢复 LMK、IK 和用户密钥,并返回恢复后的 LMK seed MAC。
*/
MasterKeyRecoveryResult recoverMasterKeyMaterial(MasterKeyRecoveryRequest request);
//----------------------------------------IK 生命周期类接口。------------------------------------------
/**
@@ -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);
@@ -170,7 +170,7 @@ public class LmkServiceImpl implements LmkService {
}
@Override
public void recoverKeyPackets(List<MasterKeyBackupPacket> packets) {
public MasterKeyStateResult recoverKeyPackets(List<MasterKeyBackupPacket> packets) {
// 进入恢复流程后,旧的备份轮次缓存不再可信,避免和恢复后的新密钥体系混用。
clearCachedBackupRound();
// 调用方可以任意顺序传入两份包,这里统一按 packetIndex 排序并校验必须是 1、2 两包。
@@ -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