fix:主密钥拆分成两个
This commit is contained in:
parent
05546fa213
commit
f60bef7142
@ -1,8 +1,8 @@
|
|||||||
package com.cisd.tms.modules.auth.enums;
|
package com.cisd.tms.modules.auth.enums;
|
||||||
|
|
||||||
public enum RoleCode {
|
public enum RoleCode {
|
||||||
SUPER_ADMIN("SUPER_ADMIN", "超级管理员", 3),
|
SUPER_ADMIN("SUPER_ADMIN", "超级管理员", 2),
|
||||||
KEY_ADMIN("KEY_ADMIN", "密钥管理员", 2),
|
KEY_ADMIN("KEY_ADMIN", "密钥管理员", 1),
|
||||||
AUDIT_ADMIN("AUDIT_ADMIN", "审计管理员", 1),
|
AUDIT_ADMIN("AUDIT_ADMIN", "审计管理员", 1),
|
||||||
OPS_ADMIN("OPS_ADMIN", "运维管理员", 1);
|
OPS_ADMIN("OPS_ADMIN", "运维管理员", 1);
|
||||||
|
|
||||||
|
|||||||
@ -140,7 +140,6 @@ public class AuthAdminServiceImpl implements AuthAdminService {
|
|||||||
String signValue = lmkService.signIk(toIssuePayload(dto, authKeyPair));
|
String signValue = lmkService.signIk(toIssuePayload(dto, authKeyPair));
|
||||||
MasterKeyBackupPacket backupPacket = null;
|
MasterKeyBackupPacket backupPacket = null;
|
||||||
if (RoleCode.SUPER_ADMIN == targetRole) {
|
if (RoleCode.SUPER_ADMIN == targetRole) {
|
||||||
// 超级管理员需要 3 把 UKey;这里按 uid=1/2/3 取出同一轮备份中的对应分量包。
|
|
||||||
backupPacket = lmkService.buildBackupPacket(Integer.parseInt(request.getUid()));
|
backupPacket = lmkService.buildBackupPacket(Integer.parseInt(request.getUid()));
|
||||||
}
|
}
|
||||||
return UKeySignResult.builder()
|
return UKeySignResult.builder()
|
||||||
|
|||||||
@ -4,10 +4,10 @@ package com.cisd.tms.modules.mk.common;
|
|||||||
* 全局常量
|
* 全局常量
|
||||||
*/
|
*/
|
||||||
public interface LMKConstant {
|
public interface LMKConstant {
|
||||||
int COMPONENT_NUM = 3;
|
int COMPONENT_NUM = 2;
|
||||||
int COMPONENT_LENGTH = 64;
|
int COMPONENT_LENGTH = 64;
|
||||||
int[] KEY_ORDER = {1,2,3};
|
int[] KEY_ORDER = {1,2};
|
||||||
int[][] COMB_LIST = new int[][]{{1,2},{1,3},{2,3}};
|
int[][] COMB_LIST = new int[][]{{1},{2}};
|
||||||
int LMK_ZONE_NUM = 1;
|
int LMK_ZONE_NUM = 1;
|
||||||
int LMK_NUM = 50;
|
int LMK_NUM = 50;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
package com.cisd.tms.modules.mk.controller;
|
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.common.enums.ErrorCode;
|
||||||
|
import com.cisd.tms.common.exception.BizException;
|
||||||
|
import com.cisd.tms.modules.mk.dto.MasterKeyBackupPacket;
|
||||||
import com.cisd.tms.modules.mk.dto.MasterKeyRecoverRequest;
|
import com.cisd.tms.modules.mk.dto.MasterKeyRecoverRequest;
|
||||||
import com.cisd.tms.modules.mk.dto.MasterKeyRecoverPacketsRequest;
|
import com.cisd.tms.modules.mk.dto.MasterKeyRecoverPacketsRequest;
|
||||||
import com.cisd.tms.modules.mk.dto.MasterKeyStateResult;
|
import com.cisd.tms.modules.mk.dto.MasterKeyStateResult;
|
||||||
@ -14,6 +17,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
* @since 2026/3/4
|
* @since 2026/3/4
|
||||||
@ -51,13 +56,14 @@ public class LmkController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 恢复所有备份密钥。
|
* 恢复所有备份密钥。
|
||||||
* 请求体需传入 componentIndex=1/2/3 的三份分量包。
|
* 请求体需传入 packetIndex=1/2 的两份备份包。
|
||||||
* 服务端会先执行 InitIdentify,然后依次恢复 LMK、加载 LMK、恢复 IK、恢复用户密钥。
|
* 服务端会先执行 InitIdentify,然后依次恢复 LMK、加载 LMK、恢复 IK、恢复用户密钥。
|
||||||
*/
|
*/
|
||||||
@PostMapping("/masterKey/recover")
|
@PostMapping("/masterKey/recover")
|
||||||
@Operation(summary = "恢复全部密钥", description = "请求体需传入三份按 componentIndex 标识的分量包。三份分量包必须分别对应 componentIndex=1、2、3。服务端会依次恢复 LMK、IK 和用户密钥。")
|
@Operation(summary = "恢复全部密钥", description = "请求体需传入两份按 packetIndex 标识的备份包。两份备份包必须分别对应 packetIndex=1、2。服务端会依次恢复 LMK、IK 和用户密钥。")
|
||||||
@ReplayProtected
|
@ReplayProtected
|
||||||
public ApiResponse<Void> recoverLmkEx(@Valid @RequestBody MasterKeyRecoverPacketsRequest request) {
|
public ApiResponse<Void> recoverLmkEx(@Valid @RequestBody MasterKeyRecoverPacketsRequest request) {
|
||||||
|
validatePacketIndexes(request.getPackets());
|
||||||
lmkService.recoverKeyPackets(request.getPackets());
|
lmkService.recoverKeyPackets(request.getPackets());
|
||||||
return ApiResponse.success();
|
return ApiResponse.success();
|
||||||
}
|
}
|
||||||
@ -70,4 +76,15 @@ public class LmkController {
|
|||||||
lmkService.verifyIk(data, signData);
|
lmkService.verifyIk(data, signData);
|
||||||
return ApiResponse.success();
|
return ApiResponse.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validatePacketIndexes(List<MasterKeyBackupPacket> packets) {
|
||||||
|
if (packets == null || packets.size() != 2) {
|
||||||
|
throw new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "packets size must be 2");
|
||||||
|
}
|
||||||
|
boolean hasPacketOne = packets.stream().anyMatch(packet -> packet != null && packet.getPacketIndex() == 1);
|
||||||
|
boolean hasPacketTwo = packets.stream().anyMatch(packet -> packet != null && packet.getPacketIndex() == 2);
|
||||||
|
if (!hasPacketOne || !hasPacketTwo) {
|
||||||
|
throw new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "packetIndex must be 1 or 2");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,9 @@ public class LMKAndIK {
|
|||||||
deviceKeyComponents.put(i,deviceKeyCompParts.get(i));
|
deviceKeyComponents.put(i,deviceKeyCompParts.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(lmkComponents.size() < 3 || authKeyComponents.size() < 3 || deviceKeyComponents.size() < 3){
|
if(lmkComponents.size() < LMKConstant.COMPONENT_NUM
|
||||||
|
|| authKeyComponents.size() < LMKConstant.COMPONENT_NUM
|
||||||
|
|| deviceKeyComponents.size() < LMKConstant.COMPONENT_NUM){
|
||||||
throw new IllegalArgumentException("主密钥或内部密钥分量缺失");
|
throw new IllegalArgumentException("主密钥或内部密钥分量缺失");
|
||||||
}
|
}
|
||||||
StringBuilder lmk = new StringBuilder();
|
StringBuilder lmk = new StringBuilder();
|
||||||
|
|||||||
@ -1,22 +1,49 @@
|
|||||||
package com.cisd.tms.modules.mk.dto;
|
package com.cisd.tms.modules.mk.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.AssertTrue;
|
||||||
|
import jakarta.validation.constraints.Max;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MasterKeyBackupPacket {
|
public class MasterKeyBackupPacket {
|
||||||
|
|
||||||
private int componentIndex;
|
@Min(value = 1, message = "packetIndex must be 1 or 2")
|
||||||
|
@Max(value = 2, message = "packetIndex must be 1 or 2")
|
||||||
|
@JsonProperty("packetIndex")
|
||||||
|
private int packetIndex;
|
||||||
|
|
||||||
private MasterKeyPacketLmkPart lmk;
|
private MasterKeyPacketLmkPart lmk;
|
||||||
private MasterKeyPacketIkPart ikAuth;
|
private MasterKeyPacketIkPart ikAuth;
|
||||||
private MasterKeyPacketIkPart ikDevice;
|
private MasterKeyPacketIkPart ikDevice;
|
||||||
|
@Valid
|
||||||
private List<MasterKeyPacketUserKeyPart> userKeys = new ArrayList<>();
|
private List<MasterKeyPacketUserKeyPart> userKeys = new ArrayList<>();
|
||||||
|
|
||||||
public int getComponentIndex() {
|
public int getPacketIndex() {
|
||||||
return componentIndex;
|
return packetIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPacketIndex(int packetIndex) {
|
||||||
|
this.packetIndex = packetIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public int getComponentIndex() {
|
||||||
|
return packetIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public void setComponentIndex(int componentIndex) {
|
public void setComponentIndex(int componentIndex) {
|
||||||
this.componentIndex = componentIndex;
|
this.packetIndex = componentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@AssertTrue(message = "packetIndex must be 1 or 2")
|
||||||
|
public boolean isPacketIndexValid() {
|
||||||
|
return packetIndex == 1 || packetIndex == 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MasterKeyPacketLmkPart getLmk() {
|
public MasterKeyPacketLmkPart getLmk() {
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
package com.cisd.tms.modules.mk.dto;
|
package com.cisd.tms.modules.mk.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class MasterKeyPacketIkPart {
|
public class MasterKeyPacketIkPart {
|
||||||
|
|
||||||
private int keyType;
|
private int keyType;
|
||||||
private String mac;
|
private String mac;
|
||||||
private String component;
|
|
||||||
private String publicKey;
|
private String publicKey;
|
||||||
private String publicKeyMac;
|
private String publicKeyMac;
|
||||||
|
private Map<Integer, String> components = new LinkedHashMap<>();
|
||||||
|
|
||||||
public MasterKeyPacketIkPart() {
|
public MasterKeyPacketIkPart() {
|
||||||
}
|
}
|
||||||
@ -18,9 +22,17 @@ public class MasterKeyPacketIkPart {
|
|||||||
public MasterKeyPacketIkPart(int keyType, String mac, String component, String publicKey, String publicKeyMac) {
|
public MasterKeyPacketIkPart(int keyType, String mac, String component, String publicKey, String publicKeyMac) {
|
||||||
this.keyType = keyType;
|
this.keyType = keyType;
|
||||||
this.mac = mac;
|
this.mac = mac;
|
||||||
this.component = component;
|
|
||||||
this.publicKey = publicKey;
|
this.publicKey = publicKey;
|
||||||
this.publicKeyMac = publicKeyMac;
|
this.publicKeyMac = publicKeyMac;
|
||||||
|
setComponent(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MasterKeyPacketIkPart(int keyType, String mac, Map<Integer, String> components, String publicKey, String publicKeyMac) {
|
||||||
|
this.keyType = keyType;
|
||||||
|
this.mac = mac;
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
this.publicKeyMac = publicKeyMac;
|
||||||
|
setComponents(components);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getKeyType() {
|
public int getKeyType() {
|
||||||
@ -39,14 +51,6 @@ public class MasterKeyPacketIkPart {
|
|||||||
this.mac = mac;
|
this.mac = mac;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getComponent() {
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setComponent(String component) {
|
|
||||||
this.component = component;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPublicKey() {
|
public String getPublicKey() {
|
||||||
return publicKey;
|
return publicKey;
|
||||||
}
|
}
|
||||||
@ -62,4 +66,29 @@ public class MasterKeyPacketIkPart {
|
|||||||
public void setPublicKeyMac(String publicKeyMac) {
|
public void setPublicKeyMac(String publicKeyMac) {
|
||||||
this.publicKeyMac = publicKeyMac;
|
this.publicKeyMac = publicKeyMac;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<Integer, String> getComponents() {
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComponents(Map<Integer, String> components) {
|
||||||
|
this.components = components == null ? new LinkedHashMap<>() : new LinkedHashMap<>(components);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public String getComponent() {
|
||||||
|
return components.entrySet().stream()
|
||||||
|
.sorted(Map.Entry.comparingByKey())
|
||||||
|
.map(Map.Entry::getValue)
|
||||||
|
.reduce("", String::concat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public void setComponent(String component) {
|
||||||
|
LinkedHashMap<Integer, String> singleComponent = new LinkedHashMap<>();
|
||||||
|
if (component != null) {
|
||||||
|
singleComponent.put(1, component);
|
||||||
|
}
|
||||||
|
this.components = singleComponent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,25 @@
|
|||||||
package com.cisd.tms.modules.mk.dto;
|
package com.cisd.tms.modules.mk.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class MasterKeyPacketLmkPart {
|
public class MasterKeyPacketLmkPart {
|
||||||
|
|
||||||
private String lmkMac;
|
private String lmkMac;
|
||||||
private String component;
|
private Map<Integer, String> components = new LinkedHashMap<>();
|
||||||
|
|
||||||
public MasterKeyPacketLmkPart() {
|
public MasterKeyPacketLmkPart() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MasterKeyPacketLmkPart(String lmkMac, String component) {
|
public MasterKeyPacketLmkPart(String lmkMac, String component) {
|
||||||
this.lmkMac = lmkMac;
|
this.lmkMac = lmkMac;
|
||||||
this.component = component;
|
setComponent(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MasterKeyPacketLmkPart(String lmkMac, Map<Integer, String> components) {
|
||||||
|
this.lmkMac = lmkMac;
|
||||||
|
setComponents(components);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLmkMac() {
|
public String getLmkMac() {
|
||||||
@ -21,11 +30,28 @@ public class MasterKeyPacketLmkPart {
|
|||||||
this.lmkMac = lmkMac;
|
this.lmkMac = lmkMac;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getComponent() {
|
public Map<Integer, String> getComponents() {
|
||||||
return component;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setComponents(Map<Integer, String> components) {
|
||||||
|
this.components = components == null ? new LinkedHashMap<>() : new LinkedHashMap<>(components);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public String getComponent() {
|
||||||
|
return components.entrySet().stream()
|
||||||
|
.sorted(Map.Entry.comparingByKey())
|
||||||
|
.map(Map.Entry::getValue)
|
||||||
|
.reduce("", String::concat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public void setComponent(String component) {
|
public void setComponent(String component) {
|
||||||
this.component = component;
|
LinkedHashMap<Integer, String> singleComponent = new LinkedHashMap<>();
|
||||||
|
if (component != null) {
|
||||||
|
singleComponent.put(1, component);
|
||||||
|
}
|
||||||
|
this.components = singleComponent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import java.util.List;
|
|||||||
public class MasterKeyRecoverPacketsRequest {
|
public class MasterKeyRecoverPacketsRequest {
|
||||||
|
|
||||||
@NotEmpty(message = "packets must not be empty")
|
@NotEmpty(message = "packets must not be empty")
|
||||||
@Size(min = 3, max = 3, message = "packets size must be 3")
|
@Size(min = 2, max = 2, message = "packets size must be 2")
|
||||||
private List<@Valid MasterKeyBackupPacket> packets;
|
private List<@Valid MasterKeyBackupPacket> packets;
|
||||||
|
|
||||||
public List<MasterKeyBackupPacket> getPackets() {
|
public List<MasterKeyBackupPacket> getPackets() {
|
||||||
|
|||||||
@ -12,7 +12,7 @@ public class MasterKeyRecoverRequest {
|
|||||||
private String lmkMac;
|
private String lmkMac;
|
||||||
|
|
||||||
@NotEmpty(message = "components must not be empty")
|
@NotEmpty(message = "components must not be empty")
|
||||||
@Size(min = 3, max = 3, message = "components size must be 3")
|
@Size(min = 2, max = 2, message = "components size must be 2")
|
||||||
private List<@NotBlank(message = "component must not be blank") String> components;
|
private List<@NotBlank(message = "component must not be blank") String> components;
|
||||||
|
|
||||||
public String getLmkMac() {
|
public String getLmkMac() {
|
||||||
|
|||||||
@ -22,8 +22,10 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -40,6 +42,14 @@ import org.springframework.stereotype.Service;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class LmkServiceImpl implements LmkService {
|
public class LmkServiceImpl implements LmkService {
|
||||||
|
|
||||||
|
// 对外接口只暴露两份备份包:packet 1 = {1,2},packet 2 = {2,3}。
|
||||||
|
private static final int PACKET_INDEX_ONE = 1;
|
||||||
|
private static final int PACKET_INDEX_TWO = 2;
|
||||||
|
// 厂商原生的 LMK/IK 备份结构仍然固定为 3 个分量,服务内部始终按原生语义处理。
|
||||||
|
private static final int NATIVE_COMPONENT_ONE = 1;
|
||||||
|
private static final int NATIVE_COMPONENT_TWO = 2;
|
||||||
|
private static final int NATIVE_COMPONENT_THREE = 3;
|
||||||
|
private static final int NATIVE_COMPONENT_COUNT = 3;
|
||||||
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_MAC_BYTE_LENGTH = 8;
|
||||||
@ -60,7 +70,7 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MasterKeyStateResult initMasterKey() {
|
public MasterKeyStateResult initMasterKey() {
|
||||||
// 密钥体系一旦重建,之前导出的三份备份包就全部失效,必须清空当前轮次缓存。
|
// 密钥体系一旦重建,之前导出的两份备份包就全部失效,必须清空当前轮次缓存。
|
||||||
clearCachedBackupRound();
|
clearCachedBackupRound();
|
||||||
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());
|
||||||
@ -75,7 +85,6 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
public void destroyMasterKey() {
|
public void destroyMasterKey() {
|
||||||
// 销毁后也不能再继续复用上一轮备份材料。
|
// 销毁后也不能再继续复用上一轮备份材料。
|
||||||
clearCachedBackupRound();
|
clearCachedBackupRound();
|
||||||
|
|
||||||
pcieCryptoService.destroyLmk();
|
pcieCryptoService.destroyLmk();
|
||||||
pcieCryptoService.destroyIk(IKEnums.KEY_TYPE_AUTH.getCode());
|
pcieCryptoService.destroyIk(IKEnums.KEY_TYPE_AUTH.getCode());
|
||||||
pcieCryptoService.destroyIk(IKEnums.KEY_TYPE_DEVICE.getCode());
|
pcieCryptoService.destroyIk(IKEnums.KEY_TYPE_DEVICE.getCode());
|
||||||
@ -121,11 +130,13 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MasterKeyBackupPacket buildBackupPacket(int componentIndex) {
|
public MasterKeyBackupPacket buildBackupPacket(int componentIndex) {
|
||||||
int index = requireComponentIndex(componentIndex);
|
int index = requirePacketIndex(componentIndex);
|
||||||
synchronized (backupRoundLock) {
|
synchronized (backupRoundLock) {
|
||||||
CachedBackupRound round = cachedBackupRound;
|
CachedBackupRound round = cachedBackupRound;
|
||||||
if (round == null) {
|
if (round == null) {
|
||||||
// 三次发给外部 UKey 的分量必须来自同一轮导出,否则恢复 LMK 时会出现 MACERR。
|
// 两次发给外部 UKey 的分量必须来自同一轮导出,否则恢复 LMK 时会出现 MACERR。
|
||||||
|
// 这里先把设备返回的原生 LMK/IK/UserKey 备份材料全部取回并缓存在内存中,
|
||||||
|
// 随后再按 packetIndex=1/2 投影成两份外部包,确保两份包属于同一轮快照。
|
||||||
round = new CachedBackupRound(
|
round = new CachedBackupRound(
|
||||||
parseBackupMaterial(),
|
parseBackupMaterial(),
|
||||||
parseIkBackupMaterial(IKEnums.KEY_TYPE_AUTH.getCode()),
|
parseIkBackupMaterial(IKEnums.KEY_TYPE_AUTH.getCode()),
|
||||||
@ -148,7 +159,7 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
@Override
|
@Override
|
||||||
public MasterKeyBackupMaterial getBackupMaterial(int uid) {
|
public MasterKeyBackupMaterial getBackupMaterial(int uid) {
|
||||||
MasterKeyBackupPacket packet = buildBackupPacket(uid);
|
MasterKeyBackupPacket packet = buildBackupPacket(uid);
|
||||||
return new MasterKeyBackupMaterial(packet.getLmk().getComponent(), packet.getLmk().getLmkMac());
|
return new MasterKeyBackupMaterial(joinOrderedComponents(packet.getLmk().getComponents()), packet.getLmk().getLmkMac());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -160,18 +171,23 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
public void recoverKeyPackets(List<MasterKeyBackupPacket> packets) {
|
public void recoverKeyPackets(List<MasterKeyBackupPacket> packets) {
|
||||||
// 进入恢复流程后,旧的备份轮次缓存不再可信,避免和恢复后的新密钥体系混用。
|
// 进入恢复流程后,旧的备份轮次缓存不再可信,避免和恢复后的新密钥体系混用。
|
||||||
clearCachedBackupRound();
|
clearCachedBackupRound();
|
||||||
|
// 调用方可以任意顺序传入两份包,这里统一按 packetIndex 排序并校验必须是 1、2 两包。
|
||||||
List<MasterKeyBackupPacket> orderedPackets = sortPackets(packets);
|
List<MasterKeyBackupPacket> orderedPackets = sortPackets(packets);
|
||||||
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());
|
||||||
|
|
||||||
// 恢复顺序必须先 LMK、再 LoadLMK、再 IK、最后用户密钥;后面的密钥材料都依赖前面的密钥体系。
|
// 恢复顺序不能打乱:
|
||||||
|
// 1. InitIdentify 建立恢复所需的设备认证上下文
|
||||||
|
// 2. 先恢复 LMK 并 LoadLMK,后续 IK 和用户密钥都依赖 LMK 环境
|
||||||
|
// 3. 再恢复两把 IK
|
||||||
|
// 4. 最后恢复用户密钥
|
||||||
pcieCryptoService.initIdentify(oldPin, newPin);
|
pcieCryptoService.initIdentify(oldPin, newPin);
|
||||||
pcieCryptoService.recoverLmkEx(Hex.decode(composeLmkHex(orderedPackets)));
|
pcieCryptoService.recoverLmkEx(Hex.decode(composeLmkHex(orderedPackets)));
|
||||||
pcieCryptoService.loadLmk();
|
pcieCryptoService.loadLmk();
|
||||||
pcieCryptoService.recoverIkComponent(IKEnums.KEY_TYPE_AUTH.getCode(), Hex.decode(composeIkHex(orderedPackets, true)));
|
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.recoverIkComponent(IKEnums.KEY_TYPE_DEVICE.getCode(), Hex.decode(composeIkHex(orderedPackets, false)));
|
||||||
//务必先查询是否是就绪状态
|
//务必先查询是否是就绪状态
|
||||||
DeviceStatusResult result = pcieCryptoService.getDeviceStatus();;
|
DeviceStatusResult result = pcieCryptoService.getDeviceStatus();
|
||||||
log.info("device status:{}", result.getFsmState());
|
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_SIGN));
|
||||||
pcieCryptoService.recoverUserKey(toRecoverUserKeyRequest(orderedPackets, USER_KEY_INDEX, USER_KEY_TYPE_ENC));
|
pcieCryptoService.recoverUserKey(toRecoverUserKeyRequest(orderedPackets, USER_KEY_INDEX, USER_KEY_TYPE_ENC));
|
||||||
@ -219,53 +235,67 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String composeLmkHex(List<MasterKeyBackupPacket> packets) {
|
private String composeLmkHex(List<MasterKeyBackupPacket> packets) {
|
||||||
|
// 外部只传两份包,但底层 SDFE_RecoverLMK_EX 需要的是完整原生三分量结构:
|
||||||
|
// packet1 提供 {1,2},packet2 提供 {2,3},因此恢复时要重组为 1 + 2 + 3。
|
||||||
|
// 其中 component2 是两包的重叠分量,必须严格一致,否则说明两包不是同一轮导出结果。
|
||||||
String lmkMac = requireConsistentLmkMac(packets);
|
String lmkMac = requireConsistentLmkMac(packets);
|
||||||
StringBuilder builder = new StringBuilder(lmkMac);
|
MasterKeyBackupPacket packet1 = packets.get(0);
|
||||||
for (MasterKeyBackupPacket packet : packets) {
|
MasterKeyBackupPacket packet2 = packets.get(1);
|
||||||
// 恢复扩展结构时必须按 1/2/3 顺序拼回 3 个分量。
|
String component1 = requiredPacketComponent(packet1.getLmk().getComponents(), NATIVE_COMPONENT_ONE, "lmk", packet1.getPacketIndex());
|
||||||
builder.append(packet.getLmk().getComponent());
|
String component2 = requireConsistentOverlapComponent(
|
||||||
}
|
packet1.getLmk().getComponents(),
|
||||||
return builder.toString();
|
packet2.getLmk().getComponents(),
|
||||||
|
"lmk"
|
||||||
|
);
|
||||||
|
String component3 = requiredPacketComponent(packet2.getLmk().getComponents(), NATIVE_COMPONENT_THREE, "lmk", packet2.getPacketIndex());
|
||||||
|
return lmkMac + component1 + component2 + component3;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String composeIkHex(List<MasterKeyBackupPacket> packets, boolean authKey) {
|
private String composeIkHex(List<MasterKeyBackupPacket> packets, boolean authKey) {
|
||||||
|
// IK 的恢复规则与 LMK 相同:
|
||||||
|
// 外部两包只是对原生三分量的投影,真正下发给密码卡时必须重新拼回
|
||||||
|
// component1 + component2 + component3 + mac + publicKey + publicKeyMac 的完整结构。
|
||||||
int keyType = authKey ? IKEnums.KEY_TYPE_AUTH.getCode() : IKEnums.KEY_TYPE_DEVICE.getCode();
|
int keyType = authKey ? IKEnums.KEY_TYPE_AUTH.getCode() : IKEnums.KEY_TYPE_DEVICE.getCode();
|
||||||
String mac = requireConsistentIkMac(packets, keyType);
|
String mac = requireConsistentIkMac(packets, keyType);
|
||||||
String publicKey = requireConsistentIkPublicKey(packets, keyType);
|
String publicKey = requireConsistentIkPublicKey(packets, keyType);
|
||||||
String publicKeyMac = requireConsistentIkPublicKeyMac(packets, keyType);
|
String publicKeyMac = requireConsistentIkPublicKeyMac(packets, keyType);
|
||||||
StringBuilder builder = new StringBuilder();
|
MasterKeyPacketIkPart packet1Part = authKey ? packets.get(0).getIkAuth() : packets.get(0).getIkDevice();
|
||||||
for (MasterKeyBackupPacket packet : packets) {
|
MasterKeyPacketIkPart packet2Part = authKey ? packets.get(1).getIkAuth() : packets.get(1).getIkDevice();
|
||||||
MasterKeyPacketIkPart part = authKey ? packet.getIkAuth() : packet.getIkDevice();
|
String component1 = requiredPacketComponent(
|
||||||
if (part == null || part.getComponent() == null || part.getComponent().isBlank()) {
|
packet1Part == null ? null : packet1Part.getComponents(),
|
||||||
throw new IllegalArgumentException((authKey ? "ikAuth" : "ikDevice") + " component missing in packet " + packet.getComponentIndex());
|
NATIVE_COMPONENT_ONE,
|
||||||
}
|
authKey ? "ikAuth" : "ikDevice",
|
||||||
builder.append(part.getComponent());
|
packets.get(0).getPacketIndex()
|
||||||
}
|
);
|
||||||
builder.append(mac).append(publicKey).append(publicKeyMac);
|
String component2 = requireConsistentOverlapComponent(
|
||||||
return builder.toString();
|
packet1Part == null ? null : packet1Part.getComponents(),
|
||||||
|
packet2Part == null ? null : packet2Part.getComponents(),
|
||||||
|
authKey ? "ikAuth" : "ikDevice"
|
||||||
|
);
|
||||||
|
String component3 = requiredPacketComponent(
|
||||||
|
packet2Part == null ? null : packet2Part.getComponents(),
|
||||||
|
NATIVE_COMPONENT_THREE,
|
||||||
|
authKey ? "ikAuth" : "ikDevice",
|
||||||
|
packets.get(1).getPacketIndex()
|
||||||
|
);
|
||||||
|
return component1 + component2 + component3 + mac + publicKey + publicKeyMac;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RecoverUserKeyRequest toRecoverUserKeyRequest(List<MasterKeyBackupPacket> packets, int keyIndex, int keyType) {
|
private RecoverUserKeyRequest toRecoverUserKeyRequest(List<MasterKeyBackupPacket> packets, int keyIndex, int keyType) {
|
||||||
RecoverUserKeyRequest request = new RecoverUserKeyRequest();
|
RecoverUserKeyRequest request = new RecoverUserKeyRequest();
|
||||||
request.setKeyIndex(keyIndex);
|
request.setKeyIndex(keyIndex);
|
||||||
request.setKeyType(keyType);
|
request.setKeyType(keyType);
|
||||||
|
// 用户密钥不走厂商原生“三分量”模型,而是应用层把整段 blob 平分成两份包。
|
||||||
request.setEncryptedKey(Hex.decode(composeUserKeyHex(packets, keyIndex, keyType)));
|
request.setEncryptedKey(Hex.decode(composeUserKeyHex(packets, keyIndex, keyType)));
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GenerateKeyPairRequest newUserKeyRequest(int keyType) {
|
|
||||||
GenerateKeyPairRequest request = new GenerateKeyPairRequest();
|
|
||||||
request.setKeyBits(256);
|
|
||||||
request.setKeyIndex(USER_KEY_INDEX);
|
|
||||||
request.setKeyType(keyType);
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String composeUserKeyHex(List<MasterKeyBackupPacket> packets, int keyIndex, int keyType) {
|
private String composeUserKeyHex(List<MasterKeyBackupPacket> packets, int keyIndex, int keyType) {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
for (MasterKeyBackupPacket packet : packets) {
|
for (MasterKeyBackupPacket packet : packets) {
|
||||||
MasterKeyPacketUserKeyPart part = findUserKeyPart(packet, keyIndex, keyType);
|
MasterKeyPacketUserKeyPart part = findUserKeyPart(packet, keyIndex, keyType);
|
||||||
// 用户密钥没有原生三分量结构,这里是把单把备份 blob 按 1/2/3 切开后再按顺序拼回。
|
// 用户密钥没有原生两分量结构,这里只是把同一把用户密钥的备份 blob
|
||||||
|
// 按 packet 1、packet 2 的顺序重新拼回一整段加密数据。
|
||||||
builder.append(part.getComponent());
|
builder.append(part.getComponent());
|
||||||
}
|
}
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
@ -277,14 +307,11 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
if (normalized.length < LMK_MAC_BYTE_LENGTH) {
|
if (normalized.length < LMK_MAC_BYTE_LENGTH) {
|
||||||
throw new IllegalStateException("backup lmk data length is too short: " + normalized.length);
|
throw new IllegalStateException("backup lmk data length is too short: " + normalized.length);
|
||||||
}
|
}
|
||||||
|
// 厂商返回格式:LMK_MAC + component1 + component2 + component3。
|
||||||
|
// 这里先按原生结构完整解析,后续 buildPacket 时再投影成两份外部包。
|
||||||
byte[] lmkMac = Arrays.copyOfRange(normalized, 0, LMK_MAC_BYTE_LENGTH);
|
byte[] lmkMac = Arrays.copyOfRange(normalized, 0, LMK_MAC_BYTE_LENGTH);
|
||||||
byte[] componentBytes = Arrays.copyOfRange(normalized, LMK_MAC_BYTE_LENGTH, normalized.length);
|
byte[] componentBytes = Arrays.copyOfRange(normalized, LMK_MAC_BYTE_LENGTH, normalized.length);
|
||||||
String[] splitComponents = DivisionUtils.equalDivision(Hex.toHexString(componentBytes), LMKConstant.COMPONENT_NUM);
|
return new ParsedMasterKeyBackup(Hex.toHexString(lmkMac), parseNativeComponentMap(componentBytes, "lmk"));
|
||||||
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 ParsedMasterKeyBackup(Hex.toHexString(lmkMac), componentMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParsedIkBackup parseIkBackupMaterial(int keyType) {
|
private ParsedIkBackup parseIkBackupMaterial(int keyType) {
|
||||||
@ -293,6 +320,8 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
if (normalized.length < IK_COMPONENT_TOTAL_BYTE_LENGTH) {
|
if (normalized.length < IK_COMPONENT_TOTAL_BYTE_LENGTH) {
|
||||||
throw new IllegalStateException("backup ik data length is too short: " + normalized.length);
|
throw new IllegalStateException("backup ik data length is too short: " + normalized.length);
|
||||||
}
|
}
|
||||||
|
// 厂商返回格式:component1 + component2 + component3 + mac + publicKey + publicKeyMac。
|
||||||
|
// 与 LMK 一样,先解析成原生三分量,再由外层决定如何投影到两份包中。
|
||||||
byte[] componentBytes = Arrays.copyOfRange(normalized, 0, IK_COMPONENT_DATA_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);
|
byte[] mac = Arrays.copyOfRange(normalized, IK_COMPONENT_DATA_LENGTH, IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH);
|
||||||
byte[] publicKey = Arrays.copyOfRange(
|
byte[] publicKey = Arrays.copyOfRange(
|
||||||
@ -305,21 +334,23 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH + IK_PUBLIC_KEY_BYTE_LENGTH,
|
IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH + IK_PUBLIC_KEY_BYTE_LENGTH,
|
||||||
IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH + IK_PUBLIC_KEY_BYTE_LENGTH + IK_PUBLIC_KEY_MAC_BYTE_LENGTH
|
IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH + IK_PUBLIC_KEY_BYTE_LENGTH + IK_PUBLIC_KEY_MAC_BYTE_LENGTH
|
||||||
);
|
);
|
||||||
String[] splitComponents = DivisionUtils.equalDivision(Hex.toHexString(componentBytes), LMKConstant.COMPONENT_NUM);
|
return new ParsedIkBackup(
|
||||||
Map<Integer, String> componentMap = new HashMap<>();
|
Hex.toHexString(mac),
|
||||||
for (int i = 0; i < LMKConstant.COMPONENT_NUM; i++) {
|
parseNativeComponentMap(componentBytes, "ik"),
|
||||||
componentMap.put(LMKConstant.KEY_ORDER[i], splitComponents[i]);
|
Hex.toHexString(publicKey),
|
||||||
}
|
Hex.toHexString(publicKeyMac)
|
||||||
return new ParsedIkBackup(Hex.toHexString(mac), componentMap, Hex.toHexString(publicKey), Hex.toHexString(publicKeyMac));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParsedUserKeyBackup parseUserKeyBackup(int keyIndex, int keyType) {
|
private ParsedUserKeyBackup parseUserKeyBackup(int keyIndex, int keyType) {
|
||||||
BackupDataResult backupData = pcieCryptoService.backupUserKey(keyIndex, keyType, USER_KEY_BACKUP_BUFFER_SIZE);
|
BackupDataResult backupData = pcieCryptoService.backupUserKey(keyIndex, keyType, USER_KEY_BACKUP_BUFFER_SIZE);
|
||||||
byte[] normalized = normalizeBackupData(backupData);
|
byte[] normalized = normalizeBackupData(backupData);
|
||||||
|
// 用户密钥没有厂商原生三分量结构,这里沿用应用层约定,
|
||||||
|
// 直接把整段 HEX 平分成两份,分别放入 packet 1、packet 2。
|
||||||
String[] components = DivisionUtils.equalDivision(Hex.toHexString(normalized), LMKConstant.COMPONENT_NUM);
|
String[] components = DivisionUtils.equalDivision(Hex.toHexString(normalized), LMKConstant.COMPONENT_NUM);
|
||||||
Map<Integer, String> componentMap = new HashMap<>();
|
Map<Integer, String> componentMap = new LinkedHashMap<>();
|
||||||
for (int i = 0; i < LMKConstant.COMPONENT_NUM; i++) {
|
for (int i = 0; i < LMKConstant.COMPONENT_NUM; i++) {
|
||||||
componentMap.put(LMKConstant.KEY_ORDER[i], components[i]);
|
componentMap.put(i + 1, components[i]);
|
||||||
}
|
}
|
||||||
return new ParsedUserKeyBackup(keyIndex, keyType, componentMap);
|
return new ParsedUserKeyBackup(keyIndex, keyType, componentMap);
|
||||||
}
|
}
|
||||||
@ -353,10 +384,25 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
return normalizeBackupData(result);
|
return normalizeBackupData(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int requireComponentIndex(int componentIndex) {
|
private Map<Integer, String> parseNativeComponentMap(byte[] componentBytes, String name) {
|
||||||
if (componentIndex < 1 || componentIndex > LMKConstant.COMPONENT_NUM) {
|
if (componentBytes.length % NATIVE_COMPONENT_COUNT != 0) {
|
||||||
throw new IllegalArgumentException("componentIndex must be 1, 2 or 3");
|
throw new IllegalStateException(name + " native component bytes length is invalid: " + componentBytes.length);
|
||||||
}
|
}
|
||||||
|
// 原生分量总长度必须能被 3 整除;每一段等长,依次映射为 1/2/3 号分量。
|
||||||
|
int componentLength = componentBytes.length / NATIVE_COMPONENT_COUNT;
|
||||||
|
Map<Integer, String> componentMap = new LinkedHashMap<>();
|
||||||
|
for (int index = 0; index < NATIVE_COMPONENT_COUNT; index++) {
|
||||||
|
int start = index * componentLength;
|
||||||
|
componentMap.put(index + 1, Hex.toHexString(Arrays.copyOfRange(componentBytes, start, start + componentLength)));
|
||||||
|
}
|
||||||
|
return componentMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int requirePacketIndex(int componentIndex) {
|
||||||
|
if (componentIndex < PACKET_INDEX_ONE || componentIndex > PACKET_INDEX_TWO) {
|
||||||
|
throw new IllegalArgumentException("packetIndex must be 1 or 2");
|
||||||
|
}
|
||||||
|
// 这里校验的是“外部包编号”,不是原生分量编号。
|
||||||
return componentIndex;
|
return componentIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,6 +414,38 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String requiredPacketComponent(Map<Integer, String> componentMap, int componentIndex, String name, int packetIndex) {
|
||||||
|
if (componentMap == null) {
|
||||||
|
throw new IllegalArgumentException(name + " component missing in packet " + packetIndex);
|
||||||
|
}
|
||||||
|
String component = componentMap.get(componentIndex);
|
||||||
|
if (component == null || component.isBlank()) {
|
||||||
|
throw new IllegalArgumentException(name + " component " + componentIndex + " missing in packet " + packetIndex);
|
||||||
|
}
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String requireConsistentOverlapComponent(Map<Integer, String> packet1Components, Map<Integer, String> packet2Components, String name) {
|
||||||
|
// 两份外部包的 component2 是同一段原生分量,必须一致;
|
||||||
|
// 一旦不一致,通常说明两份包不是同一轮导出结果,继续恢复会得到错误密钥。
|
||||||
|
String packet1Overlap = requiredPacketComponent(packet1Components, NATIVE_COMPONENT_TWO, name, PACKET_INDEX_ONE);
|
||||||
|
String packet2Overlap = requiredPacketComponent(packet2Components, NATIVE_COMPONENT_TWO, name, PACKET_INDEX_TWO);
|
||||||
|
if (!packet1Overlap.equals(packet2Overlap)) {
|
||||||
|
throw new IllegalArgumentException(name + " component 2 is inconsistent");
|
||||||
|
}
|
||||||
|
return packet1Overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String joinOrderedComponents(Map<Integer, String> components) {
|
||||||
|
if (components == null || components.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return components.entrySet().stream()
|
||||||
|
.sorted(Map.Entry.comparingByKey())
|
||||||
|
.map(Map.Entry::getValue)
|
||||||
|
.reduce("", String::concat);
|
||||||
|
}
|
||||||
|
|
||||||
private String requireConsistentLmkMac(List<MasterKeyBackupPacket> packets) {
|
private String requireConsistentLmkMac(List<MasterKeyBackupPacket> packets) {
|
||||||
if (packets == null || packets.size() != LMKConstant.COMPONENT_NUM) {
|
if (packets == null || packets.size() != LMKConstant.COMPONENT_NUM) {
|
||||||
throw new IllegalArgumentException("packets size must be " + LMKConstant.COMPONENT_NUM);
|
throw new IllegalArgumentException("packets size must be " + LMKConstant.COMPONENT_NUM);
|
||||||
@ -446,7 +524,7 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
return packet.getUserKeys().stream()
|
return packet.getUserKeys().stream()
|
||||||
.filter(item -> item.getKeyIndex() == keyIndex && item.getKeyType() == keyType)
|
.filter(item -> item.getKeyIndex() == keyIndex && item.getKeyType() == keyType)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> new IllegalArgumentException("user key component missing in packet " + packet.getComponentIndex()));
|
.orElseThrow(() -> new IllegalArgumentException("user key component missing in packet " + packet.getPacketIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MasterKeyBackupPacket> sortPackets(List<MasterKeyBackupPacket> packets) {
|
private List<MasterKeyBackupPacket> sortPackets(List<MasterKeyBackupPacket> packets) {
|
||||||
@ -454,11 +532,12 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
throw new IllegalArgumentException("packets size must be " + LMKConstant.COMPONENT_NUM);
|
throw new IllegalArgumentException("packets size must be " + LMKConstant.COMPONENT_NUM);
|
||||||
}
|
}
|
||||||
List<MasterKeyBackupPacket> sorted = new ArrayList<>(packets);
|
List<MasterKeyBackupPacket> sorted = new ArrayList<>(packets);
|
||||||
sorted.sort(java.util.Comparator.comparingInt(MasterKeyBackupPacket::getComponentIndex));
|
sorted.sort(Comparator.comparingInt(MasterKeyBackupPacket::getPacketIndex));
|
||||||
|
// 当前外部契约固定就是两包,并且必须严格是 packet 1、packet 2。
|
||||||
for (int index = 0; index < sorted.size(); index++) {
|
for (int index = 0; index < sorted.size(); index++) {
|
||||||
int expected = index + 1;
|
int expected = index + 1;
|
||||||
if (sorted.get(index).getComponentIndex() != expected) {
|
if (sorted.get(index).getPacketIndex() != expected) {
|
||||||
throw new IllegalArgumentException("packet componentIndex must be 1,2,3");
|
throw new IllegalArgumentException("packetIndex must be 1,2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sorted;
|
return sorted;
|
||||||
@ -503,23 +582,26 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MasterKeyBackupPacket buildPacket(int componentIndex) {
|
private MasterKeyBackupPacket buildPacket(int componentIndex) {
|
||||||
|
// 这里做的是“原生三分量 -> 外部两包”的投影:
|
||||||
|
// packet 1 暴露 {1,2},packet 2 暴露 {2,3}。
|
||||||
|
// 这样外部只需要保存两份包,但恢复时仍然能够拼回完整 1/2/3。
|
||||||
MasterKeyBackupPacket packet = new MasterKeyBackupPacket();
|
MasterKeyBackupPacket packet = new MasterKeyBackupPacket();
|
||||||
packet.setComponentIndex(componentIndex);
|
packet.setPacketIndex(componentIndex);
|
||||||
packet.setLmk(new MasterKeyPacketLmkPart(
|
packet.setLmk(new MasterKeyPacketLmkPart(
|
||||||
lmkBackup.lmkMacHex(),
|
lmkBackup.lmkMacHex(),
|
||||||
requiredComponent(lmkBackup.componentMap(), componentIndex, "lmk")
|
packetComponentMap(lmkBackup.componentMap(), componentIndex, "lmk")
|
||||||
));
|
));
|
||||||
packet.setIkAuth(new MasterKeyPacketIkPart(
|
packet.setIkAuth(new MasterKeyPacketIkPart(
|
||||||
IKEnums.KEY_TYPE_AUTH.getCode(),
|
IKEnums.KEY_TYPE_AUTH.getCode(),
|
||||||
authIkBackup.macHex(),
|
authIkBackup.macHex(),
|
||||||
requiredComponent(authIkBackup.componentMap(), componentIndex, "ikAuth"),
|
packetComponentMap(authIkBackup.componentMap(), componentIndex, "ikAuth"),
|
||||||
authIkBackup.publicKeyHex(),
|
authIkBackup.publicKeyHex(),
|
||||||
authIkBackup.publicKeyMacHex()
|
authIkBackup.publicKeyMacHex()
|
||||||
));
|
));
|
||||||
packet.setIkDevice(new MasterKeyPacketIkPart(
|
packet.setIkDevice(new MasterKeyPacketIkPart(
|
||||||
IKEnums.KEY_TYPE_DEVICE.getCode(),
|
IKEnums.KEY_TYPE_DEVICE.getCode(),
|
||||||
deviceIkBackup.macHex(),
|
deviceIkBackup.macHex(),
|
||||||
requiredComponent(deviceIkBackup.componentMap(), componentIndex, "ikDevice"),
|
packetComponentMap(deviceIkBackup.componentMap(), componentIndex, "ikDevice"),
|
||||||
deviceIkBackup.publicKeyHex(),
|
deviceIkBackup.publicKeyHex(),
|
||||||
deviceIkBackup.publicKeyMacHex()
|
deviceIkBackup.publicKeyMacHex()
|
||||||
));
|
));
|
||||||
@ -538,6 +620,20 @@ public class LmkServiceImpl implements LmkService {
|
|||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<Integer, String> packetComponentMap(Map<Integer, String> nativeComponents, int packetIndex, String name) {
|
||||||
|
LinkedHashMap<Integer, String> packetComponents = new LinkedHashMap<>();
|
||||||
|
if (packetIndex == PACKET_INDEX_ONE) {
|
||||||
|
// 第一包取原生分量 1、2。
|
||||||
|
packetComponents.put(NATIVE_COMPONENT_ONE, requiredComponent(nativeComponents, NATIVE_COMPONENT_ONE, name));
|
||||||
|
packetComponents.put(NATIVE_COMPONENT_TWO, requiredComponent(nativeComponents, NATIVE_COMPONENT_TWO, name));
|
||||||
|
return packetComponents;
|
||||||
|
}
|
||||||
|
// 第二包取原生分量 2、3;其中 2 是与第一包重叠的校验锚点。
|
||||||
|
packetComponents.put(NATIVE_COMPONENT_TWO, requiredComponent(nativeComponents, NATIVE_COMPONENT_TWO, name));
|
||||||
|
packetComponents.put(NATIVE_COMPONENT_THREE, requiredComponent(nativeComponents, NATIVE_COMPONENT_THREE, name));
|
||||||
|
return packetComponents;
|
||||||
|
}
|
||||||
|
|
||||||
private void markServed(int componentIndex) {
|
private void markServed(int componentIndex) {
|
||||||
servedIndices.add(componentIndex);
|
servedIndices.add(componentIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -271,7 +271,7 @@ class AuthControllerTest {
|
|||||||
AuthService authService = Mockito.mock(AuthService.class);
|
AuthService authService = Mockito.mock(AuthService.class);
|
||||||
AuthAdminService authAdminService = Mockito.mock(AuthAdminService.class);
|
AuthAdminService authAdminService = Mockito.mock(AuthAdminService.class);
|
||||||
MasterKeyBackupPacket packet = new MasterKeyBackupPacket();
|
MasterKeyBackupPacket packet = new MasterKeyBackupPacket();
|
||||||
packet.setComponentIndex(1);
|
packet.setPacketIndex(1);
|
||||||
UKeySignResult response = UKeySignResult.builder().sign("ISSUE-SIGN-001").backupPacket(packet).build();
|
UKeySignResult response = UKeySignResult.builder().sign("ISSUE-SIGN-001").backupPacket(packet).build();
|
||||||
Mockito.when(authAdminService.issueUkeyBindingSign(
|
Mockito.when(authAdminService.issueUkeyBindingSign(
|
||||||
ArgumentMatchers.eq("KEY_ADMIN"),
|
ArgumentMatchers.eq("KEY_ADMIN"),
|
||||||
@ -300,6 +300,6 @@ class AuthControllerTest {
|
|||||||
"""))
|
"""))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(containsString("\"sign\":\"ISSUE-SIGN-001\"")))
|
.andExpect(content().string(containsString("\"sign\":\"ISSUE-SIGN-001\"")))
|
||||||
.andExpect(content().string(containsString("\"componentIndex\":1")));
|
.andExpect(content().string(containsString("\"packetIndex\":1")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,8 +9,8 @@ class AuthDomainModelTest {
|
|||||||
@Test
|
@Test
|
||||||
void shouldExposeOnlyFourFixedRoleAccountsWithExpectedUkeyCounts() {
|
void shouldExposeOnlyFourFixedRoleAccountsWithExpectedUkeyCounts() {
|
||||||
Assertions.assertEquals(4, com.cisd.tms.modules.auth.enums.RoleCode.values().length);
|
Assertions.assertEquals(4, com.cisd.tms.modules.auth.enums.RoleCode.values().length);
|
||||||
Assertions.assertEquals(3, com.cisd.tms.modules.auth.enums.RoleCode.SUPER_ADMIN.getRequiredUkeyCount());
|
Assertions.assertEquals(2, com.cisd.tms.modules.auth.enums.RoleCode.SUPER_ADMIN.getRequiredUkeyCount());
|
||||||
Assertions.assertEquals(2, com.cisd.tms.modules.auth.enums.RoleCode.KEY_ADMIN.getRequiredUkeyCount());
|
Assertions.assertEquals(1, com.cisd.tms.modules.auth.enums.RoleCode.KEY_ADMIN.getRequiredUkeyCount());
|
||||||
Assertions.assertEquals(1, com.cisd.tms.modules.auth.enums.RoleCode.AUDIT_ADMIN.getRequiredUkeyCount());
|
Assertions.assertEquals(1, com.cisd.tms.modules.auth.enums.RoleCode.AUDIT_ADMIN.getRequiredUkeyCount());
|
||||||
Assertions.assertEquals(1, com.cisd.tms.modules.auth.enums.RoleCode.OPS_ADMIN.getRequiredUkeyCount());
|
Assertions.assertEquals(1, com.cisd.tms.modules.auth.enums.RoleCode.OPS_ADMIN.getRequiredUkeyCount());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,6 @@ class AuthServiceTest {
|
|||||||
InMemoryRoleUkeyBindingRepository ukeyBindings = new InMemoryRoleUkeyBindingRepository();
|
InMemoryRoleUkeyBindingRepository ukeyBindings = new InMemoryRoleUkeyBindingRepository();
|
||||||
roleAccounts.save(activeRole(RoleCode.KEY_ADMIN, "HASH:12345678:SALT-K", "SALT-K", 0, false));
|
roleAccounts.save(activeRole(RoleCode.KEY_ADMIN, "HASH:12345678:SALT-K", "SALT-K", 0, false));
|
||||||
ukeyBindings.save(activeBinding(RoleCode.KEY_ADMIN, 1, "UK-1"));
|
ukeyBindings.save(activeBinding(RoleCode.KEY_ADMIN, 1, "UK-1"));
|
||||||
ukeyBindings.save(activeBinding(RoleCode.KEY_ADMIN, 2, "UK-2"));
|
|
||||||
|
|
||||||
AuthService service = newAuthService(
|
AuthService service = newAuthService(
|
||||||
roleAccounts,
|
roleAccounts,
|
||||||
@ -97,7 +96,7 @@ class AuthServiceTest {
|
|||||||
LoginRequest request = new LoginRequest();
|
LoginRequest request = new LoginRequest();
|
||||||
request.setRoleCode(RoleCode.KEY_ADMIN.getCode());
|
request.setRoleCode(RoleCode.KEY_ADMIN.getCode());
|
||||||
request.setPassword("12345678");
|
request.setPassword("12345678");
|
||||||
request.setUkeySerials(List.of("UK-1", "UK-2"));
|
request.setUkeySerials(List.of("UK-1"));
|
||||||
|
|
||||||
LoginResponse response = service.login(request);
|
LoginResponse response = service.login(request);
|
||||||
|
|
||||||
@ -164,7 +163,6 @@ class AuthServiceTest {
|
|||||||
roleAccounts.save(activeRole(RoleCode.SUPER_ADMIN, "HASH:12345678:SALT-S", "SALT-S", 0, false));
|
roleAccounts.save(activeRole(RoleCode.SUPER_ADMIN, "HASH:12345678:SALT-S", "SALT-S", 0, false));
|
||||||
ukeyBindings.save(activeBinding(RoleCode.SUPER_ADMIN, 1, "UK-1"));
|
ukeyBindings.save(activeBinding(RoleCode.SUPER_ADMIN, 1, "UK-1"));
|
||||||
ukeyBindings.save(activeBinding(RoleCode.SUPER_ADMIN, 2, "UK-2"));
|
ukeyBindings.save(activeBinding(RoleCode.SUPER_ADMIN, 2, "UK-2"));
|
||||||
ukeyBindings.save(activeBinding(RoleCode.SUPER_ADMIN, 3, "UK-3"));
|
|
||||||
|
|
||||||
AuthService service = newAuthService(
|
AuthService service = newAuthService(
|
||||||
roleAccounts,
|
roleAccounts,
|
||||||
@ -177,7 +175,7 @@ class AuthServiceTest {
|
|||||||
LoginRequest request = new LoginRequest();
|
LoginRequest request = new LoginRequest();
|
||||||
request.setRoleCode(RoleCode.SUPER_ADMIN.getCode());
|
request.setRoleCode(RoleCode.SUPER_ADMIN.getCode());
|
||||||
request.setPassword("12345678");
|
request.setPassword("12345678");
|
||||||
request.setUkeySerials(List.of("UK-1", "UK-2"));
|
request.setUkeySerials(List.of("UK-1"));
|
||||||
|
|
||||||
BizException exception = Assertions.assertThrows(BizException.class, () -> service.login(request));
|
BizException exception = Assertions.assertThrows(BizException.class, () -> service.login(request));
|
||||||
|
|
||||||
@ -256,7 +254,7 @@ class AuthServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
void shouldIssueRoleScopedRandomsForUkeyLogin() {
|
void shouldIssueRoleScopedRandomsForUkeyLogin() {
|
||||||
UkeyLoginRandomService randomService = org.mockito.Mockito.mock(UkeyLoginRandomService.class);
|
UkeyLoginRandomService randomService = org.mockito.Mockito.mock(UkeyLoginRandomService.class);
|
||||||
org.mockito.Mockito.when(randomService.issue(RoleCode.SUPER_ADMIN.getCode(), 3)).thenReturn(List.of("RB-1", "RB-2", "RB-3"));
|
org.mockito.Mockito.when(randomService.issue(RoleCode.SUPER_ADMIN.getCode(), 2)).thenReturn(List.of("RB-1", "RB-2"));
|
||||||
|
|
||||||
AuthService service = new AuthServiceImpl(
|
AuthService service = new AuthServiceImpl(
|
||||||
new InMemoryRoleAccountRepository(),
|
new InMemoryRoleAccountRepository(),
|
||||||
@ -281,7 +279,7 @@ class AuthServiceTest {
|
|||||||
UkeyLoginRandomResponse response = service.issueUkeyLoginRandoms(request);
|
UkeyLoginRandomResponse response = service.issueUkeyLoginRandoms(request);
|
||||||
|
|
||||||
Assertions.assertEquals(RoleCode.SUPER_ADMIN.getCode(), response.getRoleCode());
|
Assertions.assertEquals(RoleCode.SUPER_ADMIN.getCode(), response.getRoleCode());
|
||||||
Assertions.assertEquals(List.of("RB-1", "RB-2", "RB-3"), response.getRandoms());
|
Assertions.assertEquals(List.of("RB-1", "RB-2"), response.getRandoms());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -367,14 +365,13 @@ class AuthServiceTest {
|
|||||||
InMemoryRoleUkeyBindingRepository ukeyBindings = new InMemoryRoleUkeyBindingRepository();
|
InMemoryRoleUkeyBindingRepository ukeyBindings = new InMemoryRoleUkeyBindingRepository();
|
||||||
roleAccounts.save(activeRole(RoleCode.KEY_ADMIN, "HASH:12345678:SALT-K", "SALT-K", 0, false));
|
roleAccounts.save(activeRole(RoleCode.KEY_ADMIN, "HASH:12345678:SALT-K", "SALT-K", 0, false));
|
||||||
ukeyBindings.save(activeBinding(RoleCode.KEY_ADMIN, 1, "UK-1", "PUB-1", "4", "4"));
|
ukeyBindings.save(activeBinding(RoleCode.KEY_ADMIN, 1, "UK-1", "PUB-1", "4", "4"));
|
||||||
ukeyBindings.save(activeBinding(RoleCode.KEY_ADMIN, 2, "UK-2", "PUB-2", "5", "5"));
|
|
||||||
|
|
||||||
LmkService lmkService = org.mockito.Mockito.mock(LmkService.class);
|
LmkService lmkService = org.mockito.Mockito.mock(LmkService.class);
|
||||||
UkeyLoginRandomService randomService = org.mockito.Mockito.mock(UkeyLoginRandomService.class);
|
UkeyLoginRandomService randomService = org.mockito.Mockito.mock(UkeyLoginRandomService.class);
|
||||||
CompatUkeyVerifier verifier = org.mockito.Mockito.mock(CompatUkeyVerifier.class);
|
CompatUkeyVerifier verifier = org.mockito.Mockito.mock(CompatUkeyVerifier.class);
|
||||||
org.mockito.Mockito.when(lmkService.getMasterKeyStatus()).thenReturn(MasterKeyStatus.NORMAL.getDetail("MAC-001"));
|
org.mockito.Mockito.when(lmkService.getMasterKeyStatus()).thenReturn(MasterKeyStatus.NORMAL.getDetail("MAC-001"));
|
||||||
org.mockito.Mockito.when(lmkService.exportIkPublicKeyHex()).thenReturn("IK-PUB-001");
|
org.mockito.Mockito.when(lmkService.exportIkPublicKeyHex()).thenReturn("IK-PUB-001");
|
||||||
org.mockito.Mockito.when(randomService.issue(RoleCode.KEY_ADMIN.getCode(), 2)).thenReturn(List.of("RB-1", "RB-2"));
|
org.mockito.Mockito.when(randomService.issue(RoleCode.KEY_ADMIN.getCode(), 1)).thenReturn(List.of("RB-1"));
|
||||||
|
|
||||||
AuthService service = new AuthServiceImpl(
|
AuthService service = new AuthServiceImpl(
|
||||||
roleAccounts,
|
roleAccounts,
|
||||||
@ -401,25 +398,19 @@ class AuthServiceTest {
|
|||||||
request.setRoleCode(RoleCode.KEY_ADMIN.getCode());
|
request.setRoleCode(RoleCode.KEY_ADMIN.getCode());
|
||||||
request.setPassword("12345678");
|
request.setPassword("12345678");
|
||||||
request.setUkeyProofs(List.of(
|
request.setUkeyProofs(List.of(
|
||||||
proof("PUB-1", "4", "4", "RB-1", "ISSUE-1", "LOGIN-DATA-1", "LOGIN-SIGN-1"),
|
proof("PUB-1", "4", "4", "RB-1", "ISSUE-1", "LOGIN-DATA-1", "LOGIN-SIGN-1")
|
||||||
proof("PUB-2", "5", "5", "RB-2", "ISSUE-2", "LOGIN-DATA-2", "LOGIN-SIGN-2")
|
|
||||||
));
|
));
|
||||||
|
|
||||||
LoginResponse response = service.ukeyLogin(request);
|
LoginResponse response = service.ukeyLogin(request);
|
||||||
|
|
||||||
Assertions.assertEquals("token-full-ukey-002", response.getToken());
|
Assertions.assertEquals("token-full-ukey-002", response.getToken());
|
||||||
Assertions.assertEquals(AuthLevel.FULL.name(), response.getAuthLevel());
|
Assertions.assertEquals(AuthLevel.FULL.name(), response.getAuthLevel());
|
||||||
org.mockito.Mockito.verify(randomService).assertIssued(RoleCode.KEY_ADMIN.getCode(), List.of("RB-1", "RB-2"));
|
org.mockito.Mockito.verify(randomService).assertIssued(RoleCode.KEY_ADMIN.getCode(), List.of("RB-1"));
|
||||||
org.mockito.Mockito.verify(verifier).verifyIssuedBinding(
|
org.mockito.Mockito.verify(verifier).verifyIssuedBinding(
|
||||||
"{\"pubKey\":\"PUB-1\",\"authKeyPair\":\"IK-PUB-001\",\"role\":\"KEY_ADMIN\",\"uid\":\"4\",\"rid\":\"4\"}",
|
"{\"pubKey\":\"PUB-1\",\"authKeyPair\":\"IK-PUB-001\",\"role\":\"KEY_ADMIN\",\"uid\":\"4\",\"rid\":\"4\"}",
|
||||||
"ISSUE-1"
|
"ISSUE-1"
|
||||||
);
|
);
|
||||||
org.mockito.Mockito.verify(verifier).verifyIssuedBinding(
|
|
||||||
"{\"pubKey\":\"PUB-2\",\"authKeyPair\":\"IK-PUB-001\",\"role\":\"KEY_ADMIN\",\"uid\":\"5\",\"rid\":\"5\"}",
|
|
||||||
"ISSUE-2"
|
|
||||||
);
|
|
||||||
org.mockito.Mockito.verify(verifier).verifyLoginSignature("PUB-1", "LOGIN-DATA-1", "LOGIN-SIGN-1");
|
org.mockito.Mockito.verify(verifier).verifyLoginSignature("PUB-1", "LOGIN-DATA-1", "LOGIN-SIGN-1");
|
||||||
org.mockito.Mockito.verify(verifier).verifyLoginSignature("PUB-2", "LOGIN-DATA-2", "LOGIN-SIGN-2");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RoleAccountEntity activeRole(
|
private static RoleAccountEntity activeRole(
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
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.Gm0018AlgorithmIds;
|
||||||
import com.cisd.tms.integration.crypto.pcie.PcieUserKeyType;
|
|
||||||
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.SdfeIkComponent;
|
import com.cisd.tms.integration.crypto.pcie.jna.SdfeIkComponent;
|
||||||
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.DigestRequest;
|
||||||
|
import com.cisd.tms.integration.crypto.pcie.model.DeviceStatusResult;
|
||||||
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.GenerateKeyPairRequest;
|
|
||||||
import com.cisd.tms.integration.crypto.pcie.model.IkSignRequest;
|
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.IkVerifyRequest;
|
||||||
import com.cisd.tms.integration.crypto.pcie.model.RecoverUserKeyRequest;
|
import com.cisd.tms.integration.crypto.pcie.model.RecoverUserKeyRequest;
|
||||||
@ -20,8 +19,13 @@ import com.cisd.tms.modules.mk.dto.MasterKeyPacketLmkPart;
|
|||||||
import com.cisd.tms.modules.mk.dto.MasterKeyPacketUserKeyPart;
|
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.impl.LmkServiceImpl;
|
import com.cisd.tms.modules.mk.service.impl.LmkServiceImpl;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
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.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
@ -64,7 +68,7 @@ class LmkServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldDestroyGeneratedUserKeysAndIksBeforeDestroyingLmk() {
|
void shouldDestroyMasterKeyInOriginalOrder() {
|
||||||
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 LmkServiceImpl(pcieCryptoService, properties);
|
LmkService service = new LmkServiceImpl(pcieCryptoService, properties);
|
||||||
@ -72,10 +76,10 @@ class LmkServiceTest {
|
|||||||
service.destroyMasterKey();
|
service.destroyMasterKey();
|
||||||
|
|
||||||
InOrder inOrder = Mockito.inOrder(pcieCryptoService);
|
InOrder inOrder = Mockito.inOrder(pcieCryptoService);
|
||||||
inOrder.verify(pcieCryptoService).deleteUserKey(1);
|
inOrder.verify(pcieCryptoService).destroyLmk();
|
||||||
inOrder.verify(pcieCryptoService).destroyIk(2);
|
inOrder.verify(pcieCryptoService).destroyIk(2);
|
||||||
inOrder.verify(pcieCryptoService).destroyIk(1);
|
inOrder.verify(pcieCryptoService).destroyIk(1);
|
||||||
inOrder.verify(pcieCryptoService).destroyLmk();
|
inOrder.verify(pcieCryptoService).deleteUserKey(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -127,7 +131,7 @@ class LmkServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldBuildBackupPacketForSingleComponentIndex() {
|
void shouldBuildBackupPacketForPacketContract() throws Exception {
|
||||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||||
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
||||||
BackupDataResult lmkBackup = new BackupDataResult();
|
BackupDataResult lmkBackup = new BackupDataResult();
|
||||||
@ -159,43 +163,32 @@ class LmkServiceTest {
|
|||||||
LmkService service = new LmkServiceImpl(pcieCryptoService, properties);
|
LmkService service = new LmkServiceImpl(pcieCryptoService, properties);
|
||||||
|
|
||||||
MasterKeyBackupPacket packet = service.buildBackupPacket(2);
|
MasterKeyBackupPacket packet = service.buildBackupPacket(2);
|
||||||
|
int componentBytesLength = 3 * 64;
|
||||||
|
int macOffset = componentBytesLength;
|
||||||
|
int publicKeyOffset = macOffset + 8;
|
||||||
|
int publicKeyEnd = publicKeyOffset + new EccRefPublicKey().size();
|
||||||
|
int publicKeyMacEnd = publicKeyEnd + 8;
|
||||||
|
|
||||||
Assertions.assertEquals(2, packet.getComponentIndex());
|
JsonNode expectedPacket = expectedPacketContract(
|
||||||
Assertions.assertEquals("1112131415161718", packet.getLmk().getLmkMac());
|
2,
|
||||||
Assertions.assertEquals("05060708", packet.getLmk().getComponent());
|
"1112131415161718",
|
||||||
Assertions.assertEquals(2, packet.getIkAuth().getKeyType());
|
hexRange(ikAuthBackup.getData(), macOffset, publicKeyOffset),
|
||||||
Assertions.assertEquals(
|
hexRange(ikAuthBackup.getData(), publicKeyOffset, publicKeyEnd),
|
||||||
org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikAuthBackup.getData(), 64, 128)),
|
hexRange(ikAuthBackup.getData(), publicKeyEnd, publicKeyMacEnd),
|
||||||
packet.getIkAuth().getComponent()
|
packetComponents("2", "05060708", "3", "090a0b0c"),
|
||||||
|
hexRange(ikDeviceBackup.getData(), macOffset, publicKeyOffset),
|
||||||
|
hexRange(ikDeviceBackup.getData(), publicKeyOffset, publicKeyEnd),
|
||||||
|
hexRange(ikDeviceBackup.getData(), publicKeyEnd, publicKeyMacEnd),
|
||||||
|
packetComponents("2", hexRange(ikAuthBackup.getData(), 64, 128), "3", hexRange(ikAuthBackup.getData(), 128, 192)),
|
||||||
|
packetComponents("2", hexRange(ikDeviceBackup.getData(), 64, 128), "3", hexRange(ikDeviceBackup.getData(), 128, 192)),
|
||||||
|
"6768696a6b6c",
|
||||||
|
"7778797a3132"
|
||||||
);
|
);
|
||||||
Assertions.assertEquals(
|
Assertions.assertEquals(expectedPacket, new ObjectMapper().valueToTree(packet));
|
||||||
org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikAuthBackup.getData(), 200, 332)),
|
|
||||||
packet.getIkAuth().getPublicKey()
|
|
||||||
);
|
|
||||||
Assertions.assertEquals(
|
|
||||||
org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikAuthBackup.getData(), 332, 340)),
|
|
||||||
packet.getIkAuth().getPublicKeyMac()
|
|
||||||
);
|
|
||||||
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(
|
|
||||||
org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikDeviceBackup.getData(), 200, 332)),
|
|
||||||
packet.getIkDevice().getPublicKey()
|
|
||||||
);
|
|
||||||
Assertions.assertEquals(
|
|
||||||
org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikDeviceBackup.getData(), 332, 340)),
|
|
||||||
packet.getIkDevice().getPublicKeyMac()
|
|
||||||
);
|
|
||||||
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 shouldReuseSingleBackupRoundAcrossThreePacketBuilds() {
|
void shouldReuseSingleBackupRoundAcrossTwoPacketBuilds() throws Exception {
|
||||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||||
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
||||||
|
|
||||||
@ -254,14 +247,46 @@ class LmkServiceTest {
|
|||||||
|
|
||||||
MasterKeyBackupPacket packet1 = service.buildBackupPacket(1);
|
MasterKeyBackupPacket packet1 = service.buildBackupPacket(1);
|
||||||
MasterKeyBackupPacket packet2 = service.buildBackupPacket(2);
|
MasterKeyBackupPacket packet2 = service.buildBackupPacket(2);
|
||||||
MasterKeyBackupPacket packet3 = service.buildBackupPacket(3);
|
int componentBytesLength = 3 * 64;
|
||||||
|
int macOffset = componentBytesLength;
|
||||||
|
int publicKeyOffset = macOffset + 8;
|
||||||
|
int publicKeyEnd = publicKeyOffset + new EccRefPublicKey().size();
|
||||||
|
int publicKeyMacEnd = publicKeyEnd + 8;
|
||||||
|
|
||||||
Assertions.assertEquals("01020304", packet1.getLmk().getComponent());
|
JsonNode expectedPacket1 = expectedPacketContract(
|
||||||
Assertions.assertEquals("05060708", packet2.getLmk().getComponent());
|
1,
|
||||||
Assertions.assertEquals("090a0b0c", packet3.getLmk().getComponent());
|
"1112131415161718",
|
||||||
Assertions.assertEquals("61626364", packet1.getUserKeys().get(0).getComponent());
|
hexRange(ikAuthRound1.getData(), macOffset, publicKeyOffset),
|
||||||
Assertions.assertEquals("65666768", packet2.getUserKeys().get(0).getComponent());
|
hexRange(ikAuthRound1.getData(), publicKeyOffset, publicKeyEnd),
|
||||||
Assertions.assertEquals("696a6b6c", packet3.getUserKeys().get(0).getComponent());
|
hexRange(ikAuthRound1.getData(), publicKeyEnd, publicKeyMacEnd),
|
||||||
|
packetComponents("1", "01020304", "2", "05060708"),
|
||||||
|
hexRange(ikDeviceRound1.getData(), macOffset, publicKeyOffset),
|
||||||
|
hexRange(ikDeviceRound1.getData(), publicKeyOffset, publicKeyEnd),
|
||||||
|
hexRange(ikDeviceRound1.getData(), publicKeyEnd, publicKeyMacEnd),
|
||||||
|
packetComponents("1", hexRange(ikAuthRound1.getData(), 0, 64), "2", hexRange(ikAuthRound1.getData(), 64, 128)),
|
||||||
|
packetComponents("1", hexRange(ikDeviceRound1.getData(), 0, 64), "2", hexRange(ikDeviceRound1.getData(), 64, 128)),
|
||||||
|
"616263646566",
|
||||||
|
"717273747576"
|
||||||
|
);
|
||||||
|
JsonNode expectedPacket2 = expectedPacketContract(
|
||||||
|
2,
|
||||||
|
"1112131415161718",
|
||||||
|
hexRange(ikAuthRound1.getData(), macOffset, publicKeyOffset),
|
||||||
|
hexRange(ikAuthRound1.getData(), publicKeyOffset, publicKeyEnd),
|
||||||
|
hexRange(ikAuthRound1.getData(), publicKeyEnd, publicKeyMacEnd),
|
||||||
|
packetComponents("2", "05060708", "3", "090a0b0c"),
|
||||||
|
hexRange(ikDeviceRound1.getData(), macOffset, publicKeyOffset),
|
||||||
|
hexRange(ikDeviceRound1.getData(), publicKeyOffset, publicKeyEnd),
|
||||||
|
hexRange(ikDeviceRound1.getData(), publicKeyEnd, publicKeyMacEnd),
|
||||||
|
packetComponents("2", hexRange(ikAuthRound1.getData(), 64, 128), "3", hexRange(ikAuthRound1.getData(), 128, 192)),
|
||||||
|
packetComponents("2", hexRange(ikDeviceRound1.getData(), 64, 128), "3", hexRange(ikDeviceRound1.getData(), 128, 192)),
|
||||||
|
"6768696a6b6c",
|
||||||
|
"7778797a3132"
|
||||||
|
);
|
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
Assertions.assertEquals(expectedPacket1, mapper.valueToTree(packet1));
|
||||||
|
Assertions.assertEquals(expectedPacket2, mapper.valueToTree(packet2));
|
||||||
|
|
||||||
Mockito.verify(pcieCryptoService).backupLmkEx();
|
Mockito.verify(pcieCryptoService).backupLmkEx();
|
||||||
Mockito.verify(pcieCryptoService).backupIkComponent(2);
|
Mockito.verify(pcieCryptoService).backupIkComponent(2);
|
||||||
@ -274,59 +299,30 @@ class LmkServiceTest {
|
|||||||
void shouldRecoverAllKeyPacketsInOrder() {
|
void shouldRecoverAllKeyPacketsInOrder() {
|
||||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||||
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE=");
|
||||||
|
DeviceStatusResult deviceStatus = new DeviceStatusResult();
|
||||||
|
deviceStatus.setFsmState(0);
|
||||||
|
Mockito.when(pcieCryptoService.getDeviceStatus()).thenReturn(deviceStatus);
|
||||||
LmkService service = new LmkServiceImpl(pcieCryptoService, properties);
|
LmkService service = new LmkServiceImpl(pcieCryptoService, properties);
|
||||||
|
|
||||||
MasterKeyBackupPacket packet1 = new MasterKeyBackupPacket();
|
MasterKeyBackupPacket packet1 = recoverPacketFixture(1);
|
||||||
packet1.setComponentIndex(1);
|
MasterKeyBackupPacket packet2 = recoverPacketFixture(2);
|
||||||
packet1.setLmk(new MasterKeyPacketLmkPart("1112131415161718", "0102"));
|
|
||||||
packet1.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1112", "31323334", "4142434445464748"));
|
|
||||||
packet1.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2122", "51525354", "6162636465666768"));
|
|
||||||
packet1.setUserKeys(List.of(
|
|
||||||
new MasterKeyPacketUserKeyPart(1, 0, "0102"),
|
|
||||||
new MasterKeyPacketUserKeyPart(1, 1, "1112")
|
|
||||||
));
|
|
||||||
|
|
||||||
MasterKeyBackupPacket packet2 = new MasterKeyBackupPacket();
|
service.recoverKeyPackets(List.of(packet1, packet2));
|
||||||
packet2.setComponentIndex(2);
|
|
||||||
packet2.setLmk(new MasterKeyPacketLmkPart("1112131415161718", "0304"));
|
|
||||||
packet2.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1314", "31323334", "4142434445464748"));
|
|
||||||
packet2.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2324", "51525354", "6162636465666768"));
|
|
||||||
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", "31323334", "4142434445464748"));
|
|
||||||
packet3.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2526", "51525354", "6162636465666768"));
|
|
||||||
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[]> lmkCaptor = ArgumentCaptor.forClass(byte[].class);
|
ArgumentCaptor<byte[]> lmkCaptor = ArgumentCaptor.forClass(byte[].class);
|
||||||
ArgumentCaptor<byte[]> ikAuthCaptor = ArgumentCaptor.forClass(byte[].class);
|
ArgumentCaptor<byte[]> ikAuthCaptor = ArgumentCaptor.forClass(byte[].class);
|
||||||
ArgumentCaptor<byte[]> ikDeviceCaptor = ArgumentCaptor.forClass(byte[].class);
|
ArgumentCaptor<byte[]> ikDeviceCaptor = ArgumentCaptor.forClass(byte[].class);
|
||||||
ArgumentCaptor<GenerateKeyPairRequest> generateSignCaptor = ArgumentCaptor.forClass(GenerateKeyPairRequest.class);
|
ArgumentCaptor<RecoverUserKeyRequest> recoverCaptor = ArgumentCaptor.forClass(RecoverUserKeyRequest.class);
|
||||||
ArgumentCaptor<RecoverUserKeyRequest> recoverSignCaptor = ArgumentCaptor.forClass(RecoverUserKeyRequest.class);
|
|
||||||
ArgumentCaptor<GenerateKeyPairRequest> generateEncCaptor = ArgumentCaptor.forClass(GenerateKeyPairRequest.class);
|
|
||||||
ArgumentCaptor<RecoverUserKeyRequest> recoverEncCaptor = 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(lmkCaptor.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(2), ikAuthCaptor.capture());
|
||||||
inOrder.verify(pcieCryptoService).recoverIkComponent(Mockito.eq(1), ikDeviceCaptor.capture());
|
inOrder.verify(pcieCryptoService).recoverIkComponent(Mockito.eq(1), ikDeviceCaptor.capture());
|
||||||
inOrder.verify(pcieCryptoService).generateKeyPairEcc(generateSignCaptor.capture());
|
inOrder.verify(pcieCryptoService).getDeviceStatus();
|
||||||
inOrder.verify(pcieCryptoService).recoverUserKey(recoverSignCaptor.capture());
|
inOrder.verify(pcieCryptoService, Mockito.times(2)).recoverUserKey(recoverCaptor.capture());
|
||||||
inOrder.verify(pcieCryptoService).generateKeyPairEcc(generateEncCaptor.capture());
|
|
||||||
inOrder.verify(pcieCryptoService).recoverUserKey(recoverEncCaptor.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[] {
|
||||||
@ -335,14 +331,8 @@ class LmkServiceTest {
|
|||||||
}, lmkCaptor.getValue());
|
}, lmkCaptor.getValue());
|
||||||
Assertions.assertArrayEquals(hex("1112131415162122232425262728313233344142434445464748"), ikAuthCaptor.getValue());
|
Assertions.assertArrayEquals(hex("1112131415162122232425262728313233344142434445464748"), ikAuthCaptor.getValue());
|
||||||
Assertions.assertArrayEquals(hex("2122232425263132333435363738515253546162636465666768"), ikDeviceCaptor.getValue());
|
Assertions.assertArrayEquals(hex("2122232425263132333435363738515253546162636465666768"), ikDeviceCaptor.getValue());
|
||||||
Assertions.assertEquals(256, generateSignCaptor.getValue().getKeyBits());
|
Assertions.assertArrayEquals(hex("010203040506"), recoverCaptor.getAllValues().get(0).getEncryptedKey());
|
||||||
Assertions.assertEquals(1, generateSignCaptor.getValue().getKeyIndex());
|
Assertions.assertArrayEquals(hex("111213141516"), recoverCaptor.getAllValues().get(1).getEncryptedKey());
|
||||||
Assertions.assertEquals(PcieUserKeyType.SIGN.getCode(), generateSignCaptor.getValue().getKeyType());
|
|
||||||
Assertions.assertEquals(256, generateEncCaptor.getValue().getKeyBits());
|
|
||||||
Assertions.assertEquals(1, generateEncCaptor.getValue().getKeyIndex());
|
|
||||||
Assertions.assertEquals(PcieUserKeyType.ENC.getCode(), generateEncCaptor.getValue().getKeyType());
|
|
||||||
Assertions.assertArrayEquals(hex("010203040506"), recoverSignCaptor.getValue().getEncryptedKey());
|
|
||||||
Assertions.assertArrayEquals(hex("111213141516"), recoverEncCaptor.getValue().getEncryptedKey());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -427,4 +417,91 @@ class LmkServiceTest {
|
|||||||
private static byte[] hex(String value) {
|
private static byte[] hex(String value) {
|
||||||
return org.bouncycastle.util.encoders.Hex.decode(value);
|
return org.bouncycastle.util.encoders.Hex.decode(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String hexRange(byte[] data, int start, int end) {
|
||||||
|
return org.bouncycastle.util.encoders.Hex.toHexString(Arrays.copyOfRange(data, start, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MasterKeyBackupPacket recoverPacketFixture(int packetIndex) {
|
||||||
|
MasterKeyBackupPacket packet = new MasterKeyBackupPacket();
|
||||||
|
if (packetIndex == 1) {
|
||||||
|
packet.setPacketIndex(1);
|
||||||
|
packet.setLmk(new MasterKeyPacketLmkPart("1112131415161718", Map.of(1, "0102", 2, "0304")));
|
||||||
|
packet.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", Map.of(1, "1112", 2, "1314"), "31323334", "4142434445464748"));
|
||||||
|
packet.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", Map.of(1, "2122", 2, "2324"), "51525354", "6162636465666768"));
|
||||||
|
packet.setUserKeys(List.of(
|
||||||
|
new MasterKeyPacketUserKeyPart(1, 0, "010203"),
|
||||||
|
new MasterKeyPacketUserKeyPart(1, 1, "111213")
|
||||||
|
));
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
packet.setPacketIndex(2);
|
||||||
|
packet.setLmk(new MasterKeyPacketLmkPart("1112131415161718", Map.of(2, "0304", 3, "0506")));
|
||||||
|
packet.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", Map.of(2, "1314", 3, "1516"), "31323334", "4142434445464748"));
|
||||||
|
packet.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", Map.of(2, "2324", 3, "2526"), "51525354", "6162636465666768"));
|
||||||
|
packet.setUserKeys(List.of(
|
||||||
|
new MasterKeyPacketUserKeyPart(1, 0, "040506"),
|
||||||
|
new MasterKeyPacketUserKeyPart(1, 1, "141516")
|
||||||
|
));
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JsonNode expectedPacketContract(
|
||||||
|
int packetIndex,
|
||||||
|
String lmkMac,
|
||||||
|
String ikAuthMac,
|
||||||
|
String ikAuthPublicKey,
|
||||||
|
String ikAuthPublicKeyMac,
|
||||||
|
Map<String, String> lmkComponents,
|
||||||
|
String ikDeviceMac,
|
||||||
|
String ikDevicePublicKey,
|
||||||
|
String ikDevicePublicKeyMac,
|
||||||
|
Map<String, String> ikAuthComponents,
|
||||||
|
Map<String, String> ikDeviceComponents,
|
||||||
|
String signUserKeyComponent,
|
||||||
|
String encUserKeyComponent
|
||||||
|
) {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
com.fasterxml.jackson.databind.node.ObjectNode root = mapper.createObjectNode();
|
||||||
|
root.put("packetIndex", packetIndex);
|
||||||
|
|
||||||
|
com.fasterxml.jackson.databind.node.ObjectNode lmk = root.putObject("lmk");
|
||||||
|
lmk.put("lmkMac", lmkMac);
|
||||||
|
lmk.set("components", mapper.valueToTree(lmkComponents));
|
||||||
|
|
||||||
|
com.fasterxml.jackson.databind.node.ObjectNode ikAuth = root.putObject("ikAuth");
|
||||||
|
ikAuth.put("keyType", 2);
|
||||||
|
ikAuth.put("mac", ikAuthMac);
|
||||||
|
ikAuth.put("publicKey", ikAuthPublicKey);
|
||||||
|
ikAuth.put("publicKeyMac", ikAuthPublicKeyMac);
|
||||||
|
ikAuth.set("components", mapper.valueToTree(ikAuthComponents));
|
||||||
|
|
||||||
|
com.fasterxml.jackson.databind.node.ObjectNode ikDevice = root.putObject("ikDevice");
|
||||||
|
ikDevice.put("keyType", 1);
|
||||||
|
ikDevice.put("mac", ikDeviceMac);
|
||||||
|
ikDevice.put("publicKey", ikDevicePublicKey);
|
||||||
|
ikDevice.put("publicKeyMac", ikDevicePublicKeyMac);
|
||||||
|
ikDevice.set("components", mapper.valueToTree(ikDeviceComponents));
|
||||||
|
|
||||||
|
com.fasterxml.jackson.databind.node.ArrayNode userKeys = root.putArray("userKeys");
|
||||||
|
userKeys.add(userKeyContract(1, 0, signUserKeyComponent));
|
||||||
|
userKeys.add(userKeyContract(1, 1, encUserKeyComponent));
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static com.fasterxml.jackson.databind.node.ObjectNode userKeyContract(int keyIndex, int keyType, String component) {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
com.fasterxml.jackson.databind.node.ObjectNode node = mapper.createObjectNode();
|
||||||
|
node.put("keyIndex", keyIndex);
|
||||||
|
node.put("keyType", keyType);
|
||||||
|
node.put("component", component);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, String> packetComponents(String firstIndex, String firstValue, String secondIndex, String secondValue) {
|
||||||
|
Map<String, String> components = new LinkedHashMap<>();
|
||||||
|
components.put(firstIndex, firstValue);
|
||||||
|
components.put(secondIndex, secondValue);
|
||||||
|
return components;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user