diff --git a/pom.xml b/pom.xml index d85b796..ef7d946 100644 --- a/pom.xml +++ b/pom.xml @@ -115,6 +115,13 @@ commons-csv 1.10.0 + + + com.sunyard.cisd + device-fingerprint-tool + 1.0.0 + + diff --git a/src/main/java/com/cisd/tms/modules/device/controller/NetworkConfigController.java b/src/main/java/com/cisd/tms/modules/device/controller/NetworkConfigController.java index f0fae4c..e0d2964 100644 --- a/src/main/java/com/cisd/tms/modules/device/controller/NetworkConfigController.java +++ b/src/main/java/com/cisd/tms/modules/device/controller/NetworkConfigController.java @@ -29,7 +29,6 @@ public class NetworkConfigController { @Operation(summary = "获取所有网卡名", description = "获取系统中所有网卡名称") @GetMapping("/card/eth-names") - @AuditedOperation(module = ModuleCode.DEVICE, action = ActionType.CREATE, summary = "获取所有网卡名") public ApiResponse> getEthDeviceNames() { return ApiResponse.success(networkConfigService.getEthDeviceNames()); } diff --git a/src/main/java/com/cisd/tms/modules/mk/config/MasterKeyActivateProperties.java b/src/main/java/com/cisd/tms/modules/mk/config/MasterKeyActivateProperties.java new file mode 100644 index 0000000..e14a10a --- /dev/null +++ b/src/main/java/com/cisd/tms/modules/mk/config/MasterKeyActivateProperties.java @@ -0,0 +1,15 @@ +package com.cisd.tms.modules.mk.config; + + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "tms.mk.activate") +public class MasterKeyActivateProperties { + + //todo 后续添加到配置文件 + private String activateUrl = "http://127.0.0.1:8080/device/activate"; + + public String getActivateUrl() { return activateUrl; } + + public void setActivateUrl(String activateUrl) { this.activateUrl = activateUrl; } +} diff --git a/src/main/java/com/cisd/tms/modules/mk/controller/LmkController.java b/src/main/java/com/cisd/tms/modules/mk/controller/LmkController.java index 1c5f996..2231373 100644 --- a/src/main/java/com/cisd/tms/modules/mk/controller/LmkController.java +++ b/src/main/java/com/cisd/tms/modules/mk/controller/LmkController.java @@ -6,12 +6,9 @@ import com.cisd.tms.common.exception.BizException; import com.cisd.tms.modules.auth.enums.AuthLevel; import com.cisd.tms.modules.auth.enums.RoleCode; import com.cisd.tms.modules.auth.security.RequireInternalAuth; -import com.cisd.tms.modules.mk.dto.MasterKeyBackupPacket; -import com.cisd.tms.modules.mk.dto.MasterKeyRecoverRequest; -import com.cisd.tms.modules.mk.dto.MasterKeyRecoverPacketsRequest; -import com.cisd.tms.modules.mk.dto.MasterKeyStateResult; -import com.cisd.tms.modules.mk.enums.MasterKeyStatus; +import com.cisd.tms.modules.mk.dto.*; import com.cisd.tms.modules.mk.service.LmkService; +import com.cisd.tms.modules.mk.service.MasterKeyActivateService; import com.cisd.tms.security.internal.ReplayProtected; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -34,6 +31,7 @@ import java.util.List; public class LmkController { private final LmkService lmkService; + private final MasterKeyActivateService masterKeyActivateService; @PostMapping("/masterKey/init") @Operation(summary = "初始化主密钥", description = "执行密码卡初始化识别、主密钥生成加载、内部密钥生成,并返回主密钥状态与校验值。") @@ -70,6 +68,21 @@ public class LmkController { return ApiResponse.success(); } + + @PostMapping("/masterKey/activate") + @Operation(summary = "设备激活") + public ApiResponse Activate(@RequestBody MasterKeyActivateRequest masterKeyActivateRequest) { + masterKeyActivateService.activate(masterKeyActivateRequest); + return ApiResponse.success(); + } + + + @GetMapping("/masterKey/activate/info") + @Operation(summary = "查询设备激活信息", description = "返回设备型号、设备名称、设备序列号、设备版本、设备状态、异常原因。") + public ApiResponse getMasterKeyActivateInfo() { + return ApiResponse.success(masterKeyActivateService.getMasterKeyActivateInfo()); + } + private void validatePacketIndexes(List packets) { if (packets == null || packets.size() != 2) { throw new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "packets数量必须为2"); diff --git a/src/main/java/com/cisd/tms/modules/mk/dto/MasterKeyActivateInfoResponse.java b/src/main/java/com/cisd/tms/modules/mk/dto/MasterKeyActivateInfoResponse.java new file mode 100644 index 0000000..2896b27 --- /dev/null +++ b/src/main/java/com/cisd/tms/modules/mk/dto/MasterKeyActivateInfoResponse.java @@ -0,0 +1,22 @@ +package com.cisd.tms.modules.mk.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "设备激活信息响应") +public class MasterKeyActivateInfoResponse { + + @Schema(description = "设备型号", example = "SYD7108") + private String deviceModel; + @Schema(description = "设备名称", example = "跨境支付终端一体机") + private String deviceName; + @Schema(description = "设备版本", example = "1.0.0") + private String version; + @Schema(description = "设备序列号", example = "1234567890ABCDEF") + private String serialNumber; + @Schema(description = "设备状态:normal/abnormal", example = "normal") + private String deviceStatus; + @Schema(description = "异常原因") + private String exceptionMessage; +} diff --git a/src/main/java/com/cisd/tms/modules/mk/dto/MasterKeyActivateRequest.java b/src/main/java/com/cisd/tms/modules/mk/dto/MasterKeyActivateRequest.java new file mode 100644 index 0000000..0047f01 --- /dev/null +++ b/src/main/java/com/cisd/tms/modules/mk/dto/MasterKeyActivateRequest.java @@ -0,0 +1,16 @@ +package com.cisd.tms.modules.mk.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "设备激活请求") +public class MasterKeyActivateRequest { + + @Schema(description = "使用者ID", example = "1234567") + private String userId; + @Schema(description = "身份凭证", example = "1234567") + private String credential; + @Schema(description = "设备激活码", example = "1234567") + private String activationCode; +} diff --git a/src/main/java/com/cisd/tms/modules/mk/entity/MasterKeyActivateEntity.java b/src/main/java/com/cisd/tms/modules/mk/entity/MasterKeyActivateEntity.java new file mode 100644 index 0000000..65c4739 --- /dev/null +++ b/src/main/java/com/cisd/tms/modules/mk/entity/MasterKeyActivateEntity.java @@ -0,0 +1,26 @@ +package com.cisd.tms.modules.mk.entity; + + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@TableName("tms_master_key_activate") +public class MasterKeyActivateEntity { + + private Long id; + + private Boolean everInitialized; + + private Boolean activationStatus; + + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; +} diff --git a/src/main/java/com/cisd/tms/modules/mk/mapper/MasterKeyActivateMapper.java b/src/main/java/com/cisd/tms/modules/mk/mapper/MasterKeyActivateMapper.java new file mode 100644 index 0000000..1b1ec12 --- /dev/null +++ b/src/main/java/com/cisd/tms/modules/mk/mapper/MasterKeyActivateMapper.java @@ -0,0 +1,9 @@ +package com.cisd.tms.modules.mk.mapper; + +import com.cisd.tms.infrastructure.persistence.mapper.BaseMapperX; +import com.cisd.tms.modules.mk.entity.MasterKeyActivateEntity; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MasterKeyActivateMapper extends BaseMapperX { +} diff --git a/src/main/java/com/cisd/tms/modules/mk/repository/MasterKeyActivateRepository.java b/src/main/java/com/cisd/tms/modules/mk/repository/MasterKeyActivateRepository.java new file mode 100644 index 0000000..5fafbdd --- /dev/null +++ b/src/main/java/com/cisd/tms/modules/mk/repository/MasterKeyActivateRepository.java @@ -0,0 +1,10 @@ +package com.cisd.tms.modules.mk.repository; + +import com.cisd.tms.modules.mk.entity.MasterKeyActivateEntity; + +import java.util.Optional; + +public interface MasterKeyActivateRepository { + Optional find(); + void update(MasterKeyActivateEntity masterKeyActivateEntity); +} diff --git a/src/main/java/com/cisd/tms/modules/mk/repository/impl/MasterKeyActivateRepositoryImpl.java b/src/main/java/com/cisd/tms/modules/mk/repository/impl/MasterKeyActivateRepositoryImpl.java new file mode 100644 index 0000000..46116b6 --- /dev/null +++ b/src/main/java/com/cisd/tms/modules/mk/repository/impl/MasterKeyActivateRepositoryImpl.java @@ -0,0 +1,53 @@ +package com.cisd.tms.modules.mk.repository.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.cisd.tms.modules.mk.entity.MasterKeyActivateEntity; +import com.cisd.tms.modules.mk.mapper.MasterKeyActivateMapper; +import com.cisd.tms.modules.mk.repository.MasterKeyActivateRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public class MasterKeyActivateRepositoryImpl implements MasterKeyActivateRepository { + + private final MasterKeyActivateMapper masterKeyActivateMapper; + public MasterKeyActivateRepositoryImpl(MasterKeyActivateMapper masterKeyActivateMapper) { + this.masterKeyActivateMapper = masterKeyActivateMapper; + } + + @Override + public Optional find() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + + wrapper.last("LIMIT 1"); + + MasterKeyActivateEntity entity = masterKeyActivateMapper.selectOne(wrapper); + return Optional.ofNullable(entity); + } + + @Override + public void update(MasterKeyActivateEntity masterKeyActivateEntity) { +// LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); +// +// wrapper.last("LIMIT 1"); +// +// MasterKeyActivateEntity entity = masterKeyActivateMapper.selectOne(wrapper); +// +// entity.setEverInitialized(everInitialized); + masterKeyActivateMapper.updateById(masterKeyActivateEntity); + } + + +// @Override +// public void updateActivateStatus(Boolean activateStatus) { +// LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); +// +// wrapper.last("LIMIT 1"); +// +// MasterKeyActivateEntity entity = masterKeyActivateMapper.selectOne(wrapper); +// +// entity.setEverInitialized(activateStatus); +// masterKeyActivateMapper.updateById(entity); +// } +} diff --git a/src/main/java/com/cisd/tms/modules/mk/service/MasterKeyActivateService.java b/src/main/java/com/cisd/tms/modules/mk/service/MasterKeyActivateService.java new file mode 100644 index 0000000..f129123 --- /dev/null +++ b/src/main/java/com/cisd/tms/modules/mk/service/MasterKeyActivateService.java @@ -0,0 +1,11 @@ +package com.cisd.tms.modules.mk.service; + +import com.cisd.tms.modules.mk.dto.MasterKeyActivateInfoResponse; +import com.cisd.tms.modules.mk.dto.MasterKeyActivateRequest; + +public interface MasterKeyActivateService { + + void activate(MasterKeyActivateRequest masterKeyActivateRequest); + + MasterKeyActivateInfoResponse getMasterKeyActivateInfo(); +} diff --git a/src/main/java/com/cisd/tms/modules/mk/service/impl/LmkServiceImpl.java b/src/main/java/com/cisd/tms/modules/mk/service/impl/LmkServiceImpl.java index c642f46..1a6ebc8 100644 --- a/src/main/java/com/cisd/tms/modules/mk/service/impl/LmkServiceImpl.java +++ b/src/main/java/com/cisd/tms/modules/mk/service/impl/LmkServiceImpl.java @@ -4,39 +4,26 @@ import com.cisd.tms.common.enums.ErrorCode; import com.cisd.tms.common.exception.BizException; import com.cisd.tms.common.util.DivisionUtils; 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.EccSignature; import com.cisd.tms.integration.crypto.pcie.model.*; import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService; import com.cisd.tms.modules.auth.service.AuthSecurityResetService; import com.cisd.tms.modules.mk.common.LMKConstant; import com.cisd.tms.modules.mk.config.MasterKeyInitProperties; -import com.cisd.tms.modules.mk.dto.MasterKeyBackupMaterial; -import com.cisd.tms.modules.mk.dto.MasterKeyBackupPacket; -import com.cisd.tms.modules.mk.dto.MasterKeyPacketIkPart; -import com.cisd.tms.modules.mk.dto.MasterKeyPacketLmkPart; -import com.cisd.tms.modules.mk.dto.MasterKeyPacketUserKeyPart; -import com.cisd.tms.modules.mk.dto.MasterKeyStateResult; +import com.cisd.tms.modules.mk.dto.*; +import com.cisd.tms.modules.mk.entity.MasterKeyActivateEntity; import com.cisd.tms.modules.mk.enums.IKEnums; import com.cisd.tms.modules.mk.enums.MasterKeyStatus; +import com.cisd.tms.modules.mk.repository.MasterKeyActivateRepository; import com.cisd.tms.modules.mk.service.LmkService; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Base64; -import java.util.Comparator; -import java.util.HashSet; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Hex; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.nio.charset.StandardCharsets; +import java.util.*; + /** * 主密钥生命周期服务实现。 */ @@ -70,20 +57,23 @@ public class LmkServiceImpl implements LmkService { private final AuthSecurityResetService authSecurityResetService; private final Object backupRoundLock = new Object(); private CachedBackupRound cachedBackupRound; + private final MasterKeyActivateRepository masterKeyActivateRepository; @Autowired public LmkServiceImpl( PcieCryptoService pcieCryptoService, MasterKeyInitProperties masterKeyInitProperties, - AuthSecurityResetService authSecurityResetService + AuthSecurityResetService authSecurityResetService, + MasterKeyActivateRepository masterKeyActivateRepository ) { this.pcieCryptoService = pcieCryptoService; this.masterKeyInitProperties = masterKeyInitProperties; this.authSecurityResetService = authSecurityResetService; + this.masterKeyActivateRepository = masterKeyActivateRepository; } - public LmkServiceImpl(PcieCryptoService pcieCryptoService, MasterKeyInitProperties masterKeyInitProperties) { - this(pcieCryptoService, masterKeyInitProperties, () -> { }); + public LmkServiceImpl(PcieCryptoService pcieCryptoService, MasterKeyInitProperties masterKeyInitProperties, MasterKeyActivateRepository masterKeyActivateRepository) { + this(pcieCryptoService, masterKeyInitProperties, () -> { }, masterKeyActivateRepository); } @Override @@ -91,6 +81,17 @@ public class LmkServiceImpl implements LmkService { if (pcieCryptoService.checkLmk()) { throw new BizException(ErrorCode.CONFLICT.getCode(), "主密钥已存在,拒绝重新初始化"); } + + MasterKeyActivateEntity masterKeyActivateEntity = masterKeyActivateRepository.find(). + orElseThrow(() -> new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "激活记录不存在")); + boolean everInitialized = masterKeyActivateEntity.getEverInitialized(); + boolean activationStatus = masterKeyActivateEntity.getActivationStatus(); + if (!everInitialized) { + if (!activationStatus) { + throw new BizException(ErrorCode.FORBIDDEN.getCode(), "需要先进行激活"); + } + } + // 密钥体系一旦重建,之前导出的两份备份包就全部失效,必须清空当前轮次缓存。 clearCachedBackupRound(); byte[] oldPin = decodeConfiguredPin("tms.mk.init-identify.old-pin-base64", masterKeyInitProperties.getOldPinBase64()); @@ -100,6 +101,10 @@ public class LmkServiceImpl implements LmkService { result.setStatus(true); result.setSeedMac(Hex.toHexString(pcieCryptoService.initializeMasterKey(oldPin, newPin))); authSecurityResetService.resetAfterMasterKeyInitialized(); + + masterKeyActivateEntity.setActivationStatus(false); + masterKeyActivateEntity.setEverInitialized(false); + masterKeyActivateRepository.update(masterKeyActivateEntity); return result; } diff --git a/src/main/java/com/cisd/tms/modules/mk/service/impl/MasterKeyActivateServiceImpl.java b/src/main/java/com/cisd/tms/modules/mk/service/impl/MasterKeyActivateServiceImpl.java new file mode 100644 index 0000000..755aa26 --- /dev/null +++ b/src/main/java/com/cisd/tms/modules/mk/service/impl/MasterKeyActivateServiceImpl.java @@ -0,0 +1,385 @@ +package com.cisd.tms.modules.mk.service.impl; + +import com.cisd.tms.common.enums.ErrorCode; +import com.cisd.tms.common.exception.BizException; +import com.cisd.tms.integration.crypto.pcie.model.DeviceInfoResult; +import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService; +import com.cisd.tms.modules.device.config.DeviceProfileProperties; +import com.cisd.tms.modules.device.dto.DeviceInfoResponse; +import com.cisd.tms.modules.device.entity.DeviceSoftwareVersionEntity; +import com.cisd.tms.modules.device.repository.DeviceSoftwareVersionRepository; +import com.cisd.tms.modules.device.service.DeviceService; +import com.cisd.tms.modules.mk.config.MasterKeyActivateProperties; +import com.cisd.tms.modules.mk.dto.MasterKeyActivateInfoResponse; +import com.cisd.tms.modules.mk.dto.MasterKeyActivateRequest; +import com.cisd.tms.modules.mk.entity.MasterKeyActivateEntity; +import com.cisd.tms.modules.mk.repository.MasterKeyActivateRepository; +import com.cisd.tms.modules.mk.service.MasterKeyActivateService; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.sunyard.cisd.DeviceFingerprint; +import com.sunyard.cisd.DeviceFingerprintService; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.digests.SM3Digest; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.signers.SM2Signer; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.interfaces.ECPrivateKey; +import org.bouncycastle.jce.interfaces.ECPublicKey; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.springframework.stereotype.Service; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Base64; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class MasterKeyActivateServiceImpl implements MasterKeyActivateService { + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + + private final PcieCryptoService pcieCryptoService; + private final MasterKeyActivateProperties masterKeyActivateProperties; + private final DeviceSoftwareVersionRepository deviceSoftwareVersionRepository; + private final DeviceProfileProperties deviceProfileProperties; + private final DeviceService deviceService; + private final MasterKeyActivateRepository masterKeyActivateRepository; + + static { + if (Security.getProvider("BC") == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + + @Override + public MasterKeyActivateInfoResponse getMasterKeyActivateInfo() { + DeviceInfoResponse deviceInfoResponse = deviceService.info(); + DeviceInfoResult deviceInfo = pcieCryptoService.getDeviceInfo(); + + MasterKeyActivateInfoResponse masterKeyActivateInfo = new MasterKeyActivateInfoResponse(); + + if (deviceInfoResponse.getMasterKeyStatus()) { + masterKeyActivateInfo.setDeviceStatus("正常"); + } else { + masterKeyActivateInfo.setDeviceStatus("异常"); + masterKeyActivateInfo.setExceptionMessage("密钥异常"); + } + + if (deviceInfo == null){ + masterKeyActivateInfo.setSerialNumber(""); + } else { + masterKeyActivateInfo.setSerialNumber(deviceInfo.getDeviceSerial()); + } + masterKeyActivateInfo.setDeviceModel(trim(deviceProfileProperties.getModel())); + masterKeyActivateInfo.setDeviceName(trim(deviceProfileProperties.getName())); + masterKeyActivateInfo.setVersion(loadTmsVersion()); + return masterKeyActivateInfo; + } + + + + + @Override + public void activate(MasterKeyActivateRequest masterKeyActivateRequest){ + MasterKeyActivateEntity masterKeyActivateEntity = masterKeyActivateRepository.find().orElseThrow(() -> new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "激活记录不存在")); + + Boolean everInitialized = masterKeyActivateEntity.getEverInitialized(); + if (everInitialized) { + throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "从未进行初始化密钥, 无需激活"); + } + + if (masterKeyActivateRequest.getUserId() == null){ + throw new IllegalArgumentException("使用者ID不能为空"); + } + + if (masterKeyActivateRequest.getCredential() == null){ + throw new IllegalArgumentException("身份凭证不能为空"); + } + + if (masterKeyActivateRequest.getActivationCode() == null){ + throw new IllegalArgumentException("设备激活码不能为空"); + } + + try { + DeviceFingerprintService deviceFingerprintService = new DeviceFingerprintService(); + DeviceFingerprint deviceFingerprint = deviceFingerprintService.getDeviceFingerprint(); + + String deviceSerial = deviceFingerprint.getDeviceSerialNumber(); + String motherboardSerial = deviceFingerprint.getMotherboardSerialNumber(); + String cpuModel = deviceFingerprint.getCpuModel(); + String cpuSerial = deviceFingerprint.getCpuSerialNumber(); + String memorySize = deviceFingerprint.getMemorySize(); + String macAddress = deviceFingerprint.getFirstNetworkMacAddress(); + String diskSerial = deviceFingerprint.getHardDiskSerialNumber(); + + String timestamp = String.valueOf(System.currentTimeMillis()); + + String nonce = randomHex(16); + + //todo 后面读取文件 + MasterKeyActivateServiceImpl.Sm2KeyPair sm2KeyPair = generateSm2KeyPair(); + + String deviceFingerprintSource = + deviceSerial + + motherboardSerial + + cpuModel + + cpuSerial + + memorySize + + macAddress + + diskSerial; + + String deviceFingerprintSm2 = sm2SignBase64( + deviceFingerprintSource.getBytes(StandardCharsets.UTF_8), + sm2KeyPair.privateKey + ); + + + String userId = trim(masterKeyActivateRequest.getUserId()); + String credential = trim(masterKeyActivateRequest.getCredential()); + String activationCode = trim(masterKeyActivateRequest.getActivationCode()); + + + + + String hashSource = userId + credential + activationCode + deviceSerial + + deviceFingerprint + timestamp + nonce; + String hash = sm3Hex(hashSource); + + Params params = new Params(); + params.userId = userId; + params.credential = credential; + params.activationCode = activationCode; + params.deviceSerial = deviceSerial; + params.deviceFingerprint = deviceFingerprintSm2; + params.timestamp = timestamp; + params.nonce = nonce; + + ActivateRequest request = new ActivateRequest(); + request.params = params; + request.hash = hash; + + //todo 先写死后续改实际的激活服务 + masterKeyActivateEntity.setActivationStatus(true); + masterKeyActivateRepository.update(masterKeyActivateEntity); +// String json = OBJECT_MAPPER.writeValueAsString(request); +//// System.out.print(json); +// HttpRequest httpRequest = HttpRequest.newBuilder() +// .uri(URI.create(masterKeyActivateProperties.getActivateUrl())) +// .header("Content-Type", "application/json;charset=UTF-8") +// .header("Accept", "application/json") +// .POST(HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8)) +// .build(); +// +// HttpClient client = HttpClient.newHttpClient(); +// +// HttpResponse response = client.send( +// httpRequest, +// HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8) +// ); +// +// ServerResponse result = +// OBJECT_MAPPER.readValue(response.body(), ServerResponse.class); +// +// if ("ok".equals(result.status)) { +// MasterKeyActivateData dataResponse = result.getData(); +// String inputHash = dataResponse.getInputHash(); +// String deviceActivationPublicKey = dataResponse.getDeviceActivationPublicKey(); +// String activationResult = dataResponse.getActivationResult(); +// +// } else { +// throw new Exception(result.getMsg()); +// } + + } catch (Exception e) { + masterKeyActivateEntity.setActivationStatus(false); + masterKeyActivateRepository.update(masterKeyActivateEntity); + throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "激活失败:" + e.getMessage()); + } + } + + + + + private String sm2SignBase64( + byte[] data, + ECPrivateKeyParameters privateKey + ) throws Exception { + + SM2Signer signer = new SM2Signer(new SM3Digest()); + + CipherParameters parameters = new ParametersWithRandom(privateKey, SECURE_RANDOM); + + signer.init(true, parameters); + signer.update(data, 0, data.length); + + byte[] signature = signer.generateSignature(); + + return Base64.getEncoder().encodeToString(signature); + } + + + private Sm2KeyPair generateSm2KeyPair(){ + try{ + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC"); + ECParameterSpec sm2Spec = ECNamedCurveTable.getParameterSpec("sm2p256v1"); + keyPairGenerator.initialize(sm2Spec, SECURE_RANDOM); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate(); + ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic(); + BigInteger d = privateKey.getD(); + + ECDomainParameters domainParameters = new ECDomainParameters( + sm2Spec.getCurve(), + sm2Spec.getG(), + sm2Spec.getN(), + sm2Spec.getH() + ); + + ECPrivateKeyParameters privateKeyParameters = + new ECPrivateKeyParameters(d, domainParameters); + + ECPublicKeyParameters publicParameters = + new ECPublicKeyParameters(publicKey.getQ(), domainParameters); + + + Sm2KeyPair sm2KeyPair = new Sm2KeyPair(); + sm2KeyPair.privateKey = privateKeyParameters; + sm2KeyPair.publicKeyParameters = publicParameters; + sm2KeyPair.publicKey = publicKey; + + return sm2KeyPair; + } catch (Exception e){ + throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "sm2密钥对生成失败"); + } + + } + + private String sm3Hex(String input) { + byte[] data = input.getBytes(StandardCharsets.UTF_8); + + SM3Digest digest = new SM3Digest(); + digest.update(data, 0, data.length); + + byte[] result = new byte[digest.getDigestSize()]; + digest.doFinal(result, 0); + + return bytesToHex(result); + } + + private String randomHex(int byteLength) { + byte[] bytes = new byte[byteLength]; + SECURE_RANDOM.nextBytes(bytes); + return bytesToHex(bytes); + } + + private String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(bytes.length * 2); + + for (byte b : bytes) { + sb.append(String.format("%02x", b & 0xff)); + } + + return sb.toString(); + } + + + private boolean sm2VerifyActivationResult( + String inputHash, + String activationResult, + ECPublicKeyParameters publicKeyParameters + ) { + try { + + byte[] signatureBytes = parseP1Signature(activationResult); + + SM2Signer signer = new SM2Signer(new SM3Digest()); + + + signer.init(false, publicKeyParameters); + + byte[] data = inputHash.getBytes(StandardCharsets.UTF_8); + + signer.update(data, 0, data.length); + + return signer.verifySignature(signatureBytes); + + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + private byte[] parseP1Signature(String activationResult) { + String value = activationResult.trim(); + if (value.startsWith("P1:")) { + value = value.substring(3); + } + return Base64.getDecoder().decode(value); + } + + public static class ActivateRequest { + + public Params params; + public String hash; + } + + public static class Params { + + public String userId; + public String credential; + public String activationCode; + public String deviceSerial; + public String deviceFingerprint; + public String timestamp; + public String nonce; + } + + + @JsonIgnoreProperties(ignoreUnknown = true) + @Data + public static class ServerResponse { + public String status; + public String msg; + public Integer code; + public MasterKeyActivateData data; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + @Data + public static class MasterKeyActivateData { + + public String inputHash; + public String deviceActivationPublicKey; + public String activationResult; + } + + private static class Sm2KeyPair { + private ECPrivateKeyParameters privateKey; + private ECPublicKeyParameters publicKeyParameters; + private ECPublicKey publicKey; + } + + private String loadTmsVersion() { + Optional version = deviceSoftwareVersionRepository.findByComponentCode("TMS"); + return version.map(DeviceSoftwareVersionEntity::getCurrentVersion).map(MasterKeyActivateServiceImpl::trim).orElse(""); + } + + private static String trim(String value) { + return value == null ? "" : value.trim(); + } +} diff --git a/src/main/resources/db/migration/V1__tms_schema_full.sql b/src/main/resources/db/migration/V1__tms_schema_full.sql index 920b71f..51a31a5 100644 --- a/src/main/resources/db/migration/V1__tms_schema_full.sql +++ b/src/main/resources/db/migration/V1__tms_schema_full.sql @@ -714,3 +714,20 @@ CREATE TABLE IF NOT EXISTS tms_backup_config ( sign_data varchar(255) NOT NULL COMMENT '其他字段的签名值', PRIMARY KEY (`id`) ) + + +CREATE TABLE tms_master_key_activate ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + + ever_initialized BOOLEAN NOT NULL, + + activation_status BOOLEAN NOT NULL, + + create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) +); + +INSERT INTO tms_master_key_activate ( + ever_initialized, + activation_status +) VALUES (true,false); diff --git a/src/test/java/com/cisd/tms/modules/mk/controller/LmkControllerTest.java b/src/test/java/com/cisd/tms/modules/mk/controller/LmkControllerTest.java index c0b7fc5..def9f3e 100644 --- a/src/test/java/com/cisd/tms/modules/mk/controller/LmkControllerTest.java +++ b/src/test/java/com/cisd/tms/modules/mk/controller/LmkControllerTest.java @@ -3,6 +3,7 @@ package com.cisd.tms.modules.mk.controller; import com.cisd.tms.common.exception.GlobalExceptionHandler; import com.cisd.tms.modules.mk.dto.MasterKeyStateResult; import com.cisd.tms.modules.mk.service.LmkService; +import com.cisd.tms.modules.mk.service.MasterKeyActivateService; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.http.MediaType; @@ -18,11 +19,12 @@ class LmkControllerTest { @Test void shouldReturnRecoveredMasterKeySeedMac() throws Exception { LmkService lmkService = Mockito.mock(LmkService.class); + MasterKeyActivateService masterKeyActivateService = Mockito.mock(MasterKeyActivateService.class); MasterKeyStateResult result = new MasterKeyStateResult(); result.setStatus(true); result.setSeedMac("1112131415161718"); Mockito.when(lmkService.recoverKeyPackets(Mockito.any())).thenReturn(result); - MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new LmkController(lmkService)) + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new LmkController(lmkService, masterKeyActivateService)) .setControllerAdvice(new GlobalExceptionHandler()) .build(); @@ -62,7 +64,8 @@ class LmkControllerTest { @Test void shouldRejectRecoverPacketsWithPacketIndexesOtherThanOneAndTwo() throws Exception { LmkService lmkService = Mockito.mock(LmkService.class); - MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new LmkController(lmkService)) + MasterKeyActivateService masterKeyActivateService = Mockito.mock(MasterKeyActivateService.class); + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new LmkController(lmkService, masterKeyActivateService)) .setControllerAdvice(new GlobalExceptionHandler()) .build(); diff --git a/src/test/java/com/cisd/tms/modules/mk/service/LmkServiceTest.java b/src/test/java/com/cisd/tms/modules/mk/service/LmkServiceTest.java index 551dfe5..500c6cb 100644 --- a/src/test/java/com/cisd/tms/modules/mk/service/LmkServiceTest.java +++ b/src/test/java/com/cisd/tms/modules/mk/service/LmkServiceTest.java @@ -1,51 +1,41 @@ package com.cisd.tms.modules.mk.service; +import com.cisd.tms.common.enums.ErrorCode; +import com.cisd.tms.common.exception.BizException; import com.cisd.tms.integration.crypto.pcie.Gm0018AlgorithmIds; import com.cisd.tms.integration.crypto.pcie.jna.EccRefPublicKey; import com.cisd.tms.integration.crypto.pcie.jna.SdfeIkComponent; -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.DeviceStatusResult; -import com.cisd.tms.integration.crypto.pcie.model.EccInternalSignRequest; -import com.cisd.tms.integration.crypto.pcie.model.EccInternalVerifyRequest; -import com.cisd.tms.integration.crypto.pcie.model.IkSignRequest; -import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest; -import com.cisd.tms.integration.crypto.pcie.model.MasterKeyRecoveryRequest; -import com.cisd.tms.integration.crypto.pcie.model.MasterKeyRecoveryResult; -import com.cisd.tms.integration.crypto.pcie.model.RecoverUserKeyRequest; +import com.cisd.tms.integration.crypto.pcie.model.*; import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService; -import com.cisd.tms.common.enums.ErrorCode; -import com.cisd.tms.common.exception.BizException; import com.cisd.tms.modules.auth.service.AuthSecurityResetService; import com.cisd.tms.modules.mk.config.MasterKeyInitProperties; -import com.cisd.tms.modules.mk.dto.MasterKeyBackupPacket; -import com.cisd.tms.modules.mk.dto.MasterKeyPacketIkPart; -import com.cisd.tms.modules.mk.dto.MasterKeyPacketLmkPart; -import com.cisd.tms.modules.mk.dto.MasterKeyPacketUserKeyPart; -import com.cisd.tms.modules.mk.dto.MasterKeyStateResult; +import com.cisd.tms.modules.mk.dto.*; +import com.cisd.tms.modules.mk.repository.MasterKeyActivateRepository; 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.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mockito; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + class LmkServiceTest { @Test void shouldInitMasterKeyWithConfiguredPinsAndReturnSeedMac() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); Mockito.when(pcieCryptoService.initializeMasterKey(Mockito.any(), Mockito.any())).thenReturn(new byte[] {0x01, 0x23, 0x45, 0x67}); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); MasterKeyStateResult result = service.initMasterKey(); @@ -61,11 +51,12 @@ class LmkServiceTest { @Test void shouldResetAuthSecurityStateAfterMasterKeyInitializationSucceeds() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); AuthSecurityResetService authSecurityResetService = Mockito.mock(AuthSecurityResetService.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); Mockito.when(pcieCryptoService.initializeMasterKey(Mockito.any(), Mockito.any())).thenReturn(new byte[] {0x01, 0x23}); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties, authSecurityResetService); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, authSecurityResetService, masterKeyActivateRepository); service.initMasterKey(); @@ -77,11 +68,12 @@ class LmkServiceTest { @Test void shouldPropagateInitMasterKeyFailure() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); Mockito.when(pcieCryptoService.initializeMasterKey(Mockito.any(), Mockito.any())) .thenThrow(new IllegalStateException("主密钥初始化失败")); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, service::initMasterKey); @@ -91,10 +83,11 @@ class LmkServiceTest { @Test void shouldRejectInitMasterKeyWhenMasterKeyAlreadyExists() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); Mockito.when(pcieCryptoService.checkLmk()).thenReturn(true); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); BizException exception = Assertions.assertThrows(BizException.class, service::initMasterKey); @@ -106,8 +99,9 @@ class LmkServiceTest { @Test void shouldDestroyMasterKeyAfterDeletingUserKey() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); service.destroyMasterKey(); @@ -121,10 +115,11 @@ class LmkServiceTest { @Test void shouldReturnStatusFalseWhenMasterKeyDoesNotExist() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); Mockito.when(pcieCryptoService.checkLmk()).thenReturn(false); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); MasterKeyStateResult result = service.queryMasterKeyStatus(); @@ -136,11 +131,12 @@ class LmkServiceTest { @Test void shouldReturnStatusTrueAndSeedMacWhenMasterKeyExists() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); Mockito.when(pcieCryptoService.checkLmk()).thenReturn(true); Mockito.when(pcieCryptoService.exportLmkSeedMac()).thenReturn(new byte[] {(byte) 0xAA, (byte) 0xBB}); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); MasterKeyStateResult result = service.queryMasterKeyStatus(); @@ -151,13 +147,14 @@ class LmkServiceTest { @Test void shouldExportIkPublicKeyHexViaDedicatedIkApi() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); BackupDataResult publicKey = new BackupDataResult(); publicKey.setLength(new EccRefPublicKey().size()); publicKey.setData(sequentialBytes(new EccRefPublicKey().size(), 0x31)); Mockito.when(pcieCryptoService.exportIkPublicKey(2)).thenReturn(publicKey); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); String result = service.exportIkPublicKeyHex(); @@ -169,6 +166,7 @@ class LmkServiceTest { @Test void shouldBuildBackupPacketForPacketContract() throws Exception { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); BackupDataResult lmkBackup = new BackupDataResult(); lmkBackup.setLength(20); @@ -196,7 +194,7 @@ class LmkServiceTest { Mockito.when(pcieCryptoService.backupUserKey(1, 0, 120)).thenReturn(userSignBackup); Mockito.when(pcieCryptoService.backupUserKey(1, 1, 120)).thenReturn(userEncBackup); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); MasterKeyBackupPacket packet = service.buildBackupPacket(2); int componentBytesLength = 3 * 64; @@ -226,6 +224,7 @@ class LmkServiceTest { @Test void shouldReuseSingleBackupRoundAcrossTwoPacketBuilds() throws Exception { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); BackupDataResult lmkBackupRound1 = new BackupDataResult(); @@ -279,7 +278,7 @@ class LmkServiceTest { Mockito.when(pcieCryptoService.backupUserKey(1, 0, 120)).thenReturn(userSignRound1, userSignRound2); Mockito.when(pcieCryptoService.backupUserKey(1, 1, 120)).thenReturn(userEncRound1, userEncRound2); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); MasterKeyBackupPacket packet1 = service.buildBackupPacket(1); MasterKeyBackupPacket packet2 = service.buildBackupPacket(2); @@ -334,12 +333,13 @@ class LmkServiceTest { @Test void shouldRecoverAllKeyPacketsInOrder() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); MasterKeyRecoveryResult recoveryResult = new MasterKeyRecoveryResult(); recoveryResult.setLmkSeedMac(hex("1112131415161718")); recoveryResult.setDeviceStatus(new DeviceStatusResult()); Mockito.when(pcieCryptoService.recoverMasterKeyMaterial(Mockito.any())).thenReturn(recoveryResult); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); MasterKeyBackupPacket packet1 = recoverPacketFixture(1); MasterKeyBackupPacket packet2 = recoverPacketFixture(2); @@ -372,6 +372,7 @@ class LmkServiceTest { @Test void shouldHashRawDataBeforeInternalSign() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); BackupDataResult digestResult = new BackupDataResult(); digestResult.setLength(32); @@ -387,7 +388,7 @@ class LmkServiceTest { Mockito.when(pcieCryptoService.digest(Mockito.any())).thenReturn(digestResult); Mockito.when(pcieCryptoService.signIk(Mockito.any())).thenReturn(signResult); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); String signatureHex = service.signIk("1223"); @@ -406,6 +407,7 @@ class LmkServiceTest { @Test void shouldHashRawDataBeforeInternalVerify() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyActivateRepository masterKeyActivateRepository = Mockito.mock(MasterKeyActivateRepository.class); MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); BackupDataResult digestResult = new BackupDataResult(); digestResult.setLength(32); @@ -417,7 +419,7 @@ class LmkServiceTest { }); Mockito.when(pcieCryptoService.digest(Mockito.any())).thenReturn(digestResult); - LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + LmkService service = new LmkServiceImpl(pcieCryptoService, properties, masterKeyActivateRepository); service.verifyIk("1223", "aabb");