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 index e14a10a..60a7e89 100644 --- a/src/main/java/com/cisd/tms/modules/mk/config/MasterKeyActivateProperties.java +++ b/src/main/java/com/cisd/tms/modules/mk/config/MasterKeyActivateProperties.java @@ -7,9 +7,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties; public class MasterKeyActivateProperties { //todo 后续添加到配置文件 - private String activateUrl = "http://127.0.0.1:8080/device/activate"; + private String platformUrl = "http://127.0.0.1:8080/device/active"; - public String getActivateUrl() { return activateUrl; } + public String getPlatformUrl() { return platformUrl; } - public void setActivateUrl(String activateUrl) { this.activateUrl = activateUrl; } + public void setPlatformUrl(String platformUrl) { this.platformUrl = platformUrl; } } 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 index 34d92b2..ab3977d 100644 --- 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 @@ -21,26 +21,24 @@ import com.sunyard.cisd.device.tool.DeviceFingerprint; import com.sunyard.cisd.device.tool.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.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; -import java.security.KeyPair; -import java.security.KeyPairGenerator; +import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; +import java.security.Signature; +import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import java.util.Optional; @@ -48,6 +46,10 @@ import java.util.Optional; @RequiredArgsConstructor public class MasterKeyActivateServiceImpl implements MasterKeyActivateService { + private static final String DEVICE_DIR = "/home/tms/device"; + public static final String SIGN_FILE = DEVICE_DIR + "/dev.sign"; + private static final String ACTIVATION_PUBLIC_KEY_FILE = DEVICE_DIR + "/dev.active.pub"; + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static final SecureRandom SECURE_RANDOM = new SecureRandom(); @@ -59,6 +61,9 @@ public class MasterKeyActivateServiceImpl implements MasterKeyActivateService { private final DeviceService deviceService; private final MasterKeyActivateRepository masterKeyActivateRepository; + private static final String PROVIDER = "BC"; + private static final String SIGNATURE_ALGO = "SM3withSM2"; + static { if (Security.getProvider("BC") == null) { Security.addProvider(new BouncyCastleProvider()); @@ -127,90 +132,67 @@ public class MasterKeyActivateServiceImpl implements MasterKeyActivateService { 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 - ); - + byte[] deviceFingerprintBytes = readFileBytes(SIGN_FILE); + String deviceFingerprintJson = Base64.getEncoder().encodeToString(deviceFingerprintBytes); 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; + params.setUserId(userId); + params.setCredential(credential); + params.setDeviceActivationCode(activationCode); + params.setDeviceSerialNumber(deviceSerial); + params.setDeviceFingerprintJson(deviceFingerprintJson); + params.setTimestamp(timestamp); + params.setNonce(nonce); ActivateRequest request = new ActivateRequest(); - request.params = params; - request.hash = hash; + request.setParams(params); + request.setHash(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()); -// } + String json = OBJECT_MAPPER.writeValueAsString(request); +// System.out.print(json); + HttpRequest httpRequest = HttpRequest.newBuilder() + .uri(URI.create(masterKeyActivateProperties.getPlatformUrl())) + .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 Hash = dataResponse.getHash(); + String deviceActivationPublicKey = dataResponse.getDeviceActivationPublicKey(); + String deviceActivationResult = dataResponse.getDeviceActivationResult(); + verifySm2Signature(Hash, deviceActivationResult, deviceActivationPublicKey); + masterKeyActivateEntity.setActivationStatus(true); + masterKeyActivateRepository.update(masterKeyActivateEntity); + writeFile(ACTIVATION_PUBLIC_KEY_FILE, deviceActivationPublicKey.getBytes(StandardCharsets.UTF_8)); + } else { + throw new Exception(result.getMsg()); + } } catch (Exception e) { masterKeyActivateEntity.setActivationStatus(false); @@ -220,63 +202,6 @@ public class MasterKeyActivateServiceImpl implements MasterKeyActivateService { } - - - 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); @@ -306,80 +231,49 @@ public class MasterKeyActivateServiceImpl implements MasterKeyActivateService { } - private boolean sm2VerifyActivationResult( - String inputHash, - String activationResult, - ECPublicKeyParameters publicKeyParameters - ) { + public boolean verifySm2Signature(String data, String signatureBase64, String publicKeyBase64) { try { + byte[] keyBytes = Base64.getDecoder().decode(publicKeyBase64); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("EC", PROVIDER); + PublicKey publicKey = keyFactory.generatePublic(keySpec); - 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); - + Signature signature = Signature.getInstance(SIGNATURE_ALGO, PROVIDER); + signature.initVerify(publicKey); + signature.update(data.getBytes(StandardCharsets.UTF_8)); + byte[] signatureBytes = Base64.getDecoder().decode(signatureBase64); + return signature.verify(signatureBytes); } catch (Exception e) { - e.printStackTrace(); - return false; + throw new RuntimeException("SM2验签失败", e); } } - private byte[] parseP1Signature(String activationResult) { - String value = activationResult.trim(); - if (value.startsWith("P1:")) { - value = value.substring(3); - } - return Base64.getDecoder().decode(value); - } + + + @Data 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; + private Params params; + private String hash; } @JsonIgnoreProperties(ignoreUnknown = true) @Data public static class ServerResponse { - public String status; - public String msg; - public Integer code; - public MasterKeyActivateData data; + private String status; + private String msg; + private Integer code; + private 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 hash; + private String deviceActivationPublicKey; + private String deviceActivationResult; } private String loadTmsVersion() { @@ -387,7 +281,100 @@ public class MasterKeyActivateServiceImpl implements MasterKeyActivateService { return version.map(DeviceSoftwareVersionEntity::getCurrentVersion).map(MasterKeyActivateServiceImpl::trim).orElse(""); } + + public static byte[] readFileBytes(String filePath) throws Exception { + File file = new File(filePath); + try (FileInputStream fis = new FileInputStream(file)) { + byte[] content = new byte[(int) file.length()]; + fis.read(content); + return content; + } + } + + public static void writeFile(String filePath, byte[] content) throws Exception { + File file = new File(filePath); + File parentDir = file.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + parentDir.mkdirs(); + } + try (OutputStream os = new FileOutputStream(file)) { + os.write(content); + } + } + + private static String trim(String value) { return value == null ? "" : value.trim(); } + + + + public static class Params { + private String userId; + private String credential; + private String deviceActivationCode; + private String deviceSerialNumber; + private String deviceFingerprintJson; + private String timestamp; + private String nonce; + + public Params() { + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getCredential() { + return credential; + } + + public void setCredential(String credential) { + this.credential = credential; + } + + public String getDeviceActivationCode() { + return deviceActivationCode; + } + + public void setDeviceActivationCode(String deviceActivationCode) { + this.deviceActivationCode = deviceActivationCode; + } + + public String getDeviceSerialNumber() { + return deviceSerialNumber; + } + + public void setDeviceSerialNumber(String deviceSerialNumber) { + this.deviceSerialNumber = deviceSerialNumber; + } + + public String getDeviceFingerprintJson() { + return deviceFingerprintJson; + } + + public void setDeviceFingerprintJson(String deviceFingerprintJson) { + this.deviceFingerprintJson = deviceFingerprintJson; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getNonce() { + return nonce; + } + + public void setNonce(String nonce) { + this.nonce = nonce; + } + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index aec6974..bafdba8 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -335,6 +335,9 @@ tms: old-pin-base64: ${TMS_MK_INIT_IDENTIFY_OLD_PIN_BASE64:NjY2NjY2} # SDFE_InitIdentify 新 PIN(Base64 编码);主密钥初始化接口会读取该值。 new-pin-base64: ${TMS_MK_INIT_IDENTIFY_NEW_PIN_BASE64:NjY2NjY2} + activate: + # 激活服务平台路径 + platform-url: ${TMS_MK_ACTIVATE_PLATFORM_URL:http://127.0.0.1:8080/device/active} security: # 内部接口鉴权 token(前后端内部调用需一致)。 internal-token: ${TMS_INTERNAL_TOKEN:change-me-internal-token}