From a89fd0c116ed91809b74d2f90923bf50bf1a32dc Mon Sep 17 00:00:00 2001 From: cheney Date: Wed, 6 May 2026 16:32:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AE=BE=E5=A4=87=E6=BF=80?= =?UTF-8?q?=E6=B4=BB=E7=9B=B8=E5=85=B3=E6=A8=A1=E5=9D=97=EF=BC=8C=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=20Bean=20=E7=9A=84=E5=B1=9E=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- device-activation-platform/Readme.md | 68 ++++++++++ device-activation-platform/pom.xml | 63 +++++++++ .../cisd/DeviceActivationApplication.java | 11 ++ .../cisd/DeviceActivationController.java | 40 ++++++ .../sunyar/cisd/DeviceActivationRequest.java | 126 ++++++++++++++++++ .../sunyar/cisd/DeviceActivationResponse.java | 94 +++++++++++++ .../sunyar/cisd/DeviceActivationService.java | 61 +++++++++ .../src/main/java/com/sunyar/cisd/Main.java | 17 --- .../src/main/resources/application.yml | 6 + 9 files changed, 469 insertions(+), 17 deletions(-) create mode 100644 device-activation-platform/Readme.md create mode 100644 device-activation-platform/pom.xml create mode 100644 device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationApplication.java create mode 100644 device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationController.java create mode 100644 device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationRequest.java create mode 100644 device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationResponse.java create mode 100644 device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationService.java delete mode 100644 device-activation-platform/src/main/java/com/sunyar/cisd/Main.java create mode 100644 device-activation-platform/src/main/resources/application.yml diff --git a/device-activation-platform/Readme.md b/device-activation-platform/Readme.md new file mode 100644 index 0000000..7425d4f --- /dev/null +++ b/device-activation-platform/Readme.md @@ -0,0 +1,68 @@ +激活登录请求参数 req { + params { + 使用者ID + 初始密码 + } +} + +激活登录响应参数 res { + status : 'ok' 成功; 'error' 错误 + msg: "提示消息" + code: "状态码" +} + + +激活申请请求参数 req { + params { + 设备的序列号 + 激活原因 + } +} + +激活申请响应参数 res { + 身份凭证 + 设备激活码 +} + + +设备激活请求参数 req { + params { + 使用者ID + 身份凭证 + 设备激活码 + 设备序列号 + 设备指纹 + 当前时间戳 + 随机数 + } + hash: params 对象所有属性字符串按顺序累计计算 SM3 摘要值 +} + +设备激活响应参数 res { + status : 'ok' 成功; 'error' 错误 + msg: "提示消息" + code: "状态码" + data: { + hash: 入参的 hash + 设备激活公钥: 公钥格式 + 设备激活结果: SM2 算法对 hash 值的签名, pkcs1 格式。 + } +} + +设备指纹信息 { + 主板序列号 + 设备序列号 + CPU型号 + CPU序列号 + 内存大小 + 首块网卡MAC地址 + 硬盘序列号 + 起始日期 + 终止日期 +} + +设备指纹是设备指纹信息的 SM2 签名(pkcs1 格式)。 +~~设备指纹信息存储于文件 /home/tms/device/dev.info 文件,json 格式。~~ +设备指纹存放于签名文件 /home/tms/device/dev.sign, pkcs1 格式。校验值 /home/tms/device/dev.sign.sm3。 +设备指纹密钥公钥存储于文件 /home/tms/device/dev.fingerprint.pub, 公钥格式。校验值 /home/tms/device/dev.fingerprint.pub.sm3。 +设备激活密钥公钥存储于文件 /home/tms/device/dev.active.pub, 公钥格式。校验值 /home/tms/device/dev.active.pub.sm3。 \ No newline at end of file diff --git a/device-activation-platform/pom.xml b/device-activation-platform/pom.xml new file mode 100644 index 0000000..6d1c599 --- /dev/null +++ b/device-activation-platform/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.5.11 + + + + com.sunyar + device-activation-platform + 1.0.0 + device-activation-platform + Device Activation Platform + + + 17 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + true + + + + org.bouncycastle + bcprov-jdk18on + 1.83 + + + + org.bouncycastle + bcpkix-jdk18on + 1.83 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationApplication.java b/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationApplication.java new file mode 100644 index 0000000..42a4599 --- /dev/null +++ b/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationApplication.java @@ -0,0 +1,11 @@ +package com.sunyar.cisd; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DeviceActivationApplication { + public static void main(String[] args) { + SpringApplication.run(DeviceActivationApplication.class, args); + } +} \ No newline at end of file diff --git a/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationController.java b/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationController.java new file mode 100644 index 0000000..69571c2 --- /dev/null +++ b/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationController.java @@ -0,0 +1,40 @@ +package com.sunyar.cisd; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/device") +public class DeviceActivationController { + + @Autowired + private DeviceActivationService deviceActivationService; + + @PostMapping("/active") + public DeviceActivationResponse activate(@RequestBody DeviceActivationRequest request) { + try { + if (request.getParams() == null) { + return DeviceActivationResponse.error("参数不能为空", "1001"); + } + + DeviceActivationRequest.Params params = request.getParams(); + String concatenatedParams = params.toConcatenatedString(); + String calculatedHash = deviceActivationService.calculateSm3Hash(concatenatedParams); + + String deviceActivationPublicKey = deviceActivationService.generateDeviceActivationPublicKey(); + String deviceActivationResult = deviceActivationService.signWithSm2Pkcs1(calculatedHash, deviceActivationPublicKey); + + DeviceActivationResponse.Data data = new DeviceActivationResponse.Data(); + data.setHash(calculatedHash); + data.setDeviceActivationPublicKey(deviceActivationPublicKey); + data.setDeviceActivationResult(deviceActivationResult); + + return DeviceActivationResponse.ok("设备激活成功", data); + } catch (Exception e) { + return DeviceActivationResponse.error("设备激活失败: " + e.getMessage(), "1002"); + } + } +} \ No newline at end of file diff --git a/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationRequest.java b/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationRequest.java new file mode 100644 index 0000000..2e11ce0 --- /dev/null +++ b/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationRequest.java @@ -0,0 +1,126 @@ +package com.sunyar.cisd; + +public class DeviceActivationRequest { + private Params params; + private String hash; + + public DeviceActivationRequest() { + } + + public Params getParams() { + return params; + } + + public void setParams(Params params) { + this.params = params; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public static class Params { + private String userId; + private String credential; + private String deviceActivationCode; + private String deviceSerialNumber; + private String deviceFingerprintJson; + private String deviceSignature; + private String devicePublicKey; + 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 getDeviceSignature() { + return deviceSignature; + } + + public void setDeviceSignature(String deviceSignature) { + this.deviceSignature = deviceSignature; + } + + public String getDevicePublicKey() { + return devicePublicKey; + } + + public void setDevicePublicKey(String devicePublicKey) { + this.devicePublicKey = devicePublicKey; + } + + 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; + } + + public String toConcatenatedString() { + StringBuilder sb = new StringBuilder(); + if (userId != null) sb.append(userId); + if (credential != null) sb.append(credential); + if (deviceActivationCode != null) sb.append(deviceActivationCode); + if (deviceSerialNumber != null) sb.append(deviceSerialNumber); + if (deviceFingerprintJson != null) sb.append(deviceFingerprintJson); + if (deviceSignature != null) sb.append(deviceSignature); + if (devicePublicKey != null) sb.append(devicePublicKey); + if (timestamp != null) sb.append(timestamp); + if (nonce != null) sb.append(nonce); + return sb.toString(); + } + } +} \ No newline at end of file diff --git a/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationResponse.java b/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationResponse.java new file mode 100644 index 0000000..bb2adf2 --- /dev/null +++ b/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationResponse.java @@ -0,0 +1,94 @@ +package com.sunyar.cisd; + +public class DeviceActivationResponse { + private String status; + private String msg; + private String code; + private Data data; + + public DeviceActivationResponse() { + } + + public static DeviceActivationResponse ok(String msg, Data data) { + DeviceActivationResponse response = new DeviceActivationResponse(); + response.status = "ok"; + response.msg = msg; + response.code = "0"; + response.data = data; + return response; + } + + public static DeviceActivationResponse error(String msg, String code) { + DeviceActivationResponse response = new DeviceActivationResponse(); + response.status = "error"; + response.msg = msg; + response.code = code; + response.data = null; + return response; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public Data getData() { + return data; + } + + public void setData(Data data) { + this.data = data; + } + + public static class Data { + private String hash; + private String deviceActivationPublicKey; + private String deviceActivationResult; + + public Data() { + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getDeviceActivationPublicKey() { + return deviceActivationPublicKey; + } + + public void setDeviceActivationPublicKey(String deviceActivationPublicKey) { + this.deviceActivationPublicKey = deviceActivationPublicKey; + } + + public String getDeviceActivationResult() { + return deviceActivationResult; + } + + public void setDeviceActivationResult(String deviceActivationResult) { + this.deviceActivationResult = deviceActivationResult; + } + } +} \ No newline at end of file diff --git a/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationService.java b/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationService.java new file mode 100644 index 0000000..e74d993 --- /dev/null +++ b/device-activation-platform/src/main/java/com/sunyar/cisd/DeviceActivationService.java @@ -0,0 +1,61 @@ +package com.sunyar.cisd; + +import org.bouncycastle.crypto.digests.SM3Digest; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.encoders.Hex; +import org.springframework.stereotype.Service; + +import java.nio.charset.StandardCharsets; +import java.security.Security; +import java.security.Signature; +import java.util.Base64; + +@Service +public class DeviceActivationService { + + private static final String PROVIDER = "BC"; + private static final String SIGNATURE_ALGO = "SM3withSM2"; + + static { + if (Security.getProvider(PROVIDER) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + + public String calculateSm3Hash(String data) { + SM3Digest digest = new SM3Digest(); + byte[] input = data.getBytes(StandardCharsets.UTF_8); + digest.update(input, 0, input.length); + byte[] hash = new byte[digest.getDigestSize()]; + digest.doFinal(hash, 0); + return Hex.toHexString(hash); + } + + public String signWithSm2Pkcs1(String data, String privateKeyBase64) { + try { + byte[] keyBytes = Base64.getDecoder().decode(privateKeyBase64); + java.security.spec.PKCS8EncodedKeySpec keySpec = new java.security.spec.PKCS8EncodedKeySpec(keyBytes); + java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("EC", PROVIDER); + java.security.PrivateKey privateKey = keyFactory.generatePrivate(keySpec); + + Signature signature = Signature.getInstance(SIGNATURE_ALGO, PROVIDER); + signature.initSign(privateKey); + signature.update(data.getBytes(StandardCharsets.UTF_8)); + byte[] signatureBytes = signature.sign(); + return Base64.getEncoder().encodeToString(signatureBytes); + } catch (Exception e) { + throw new RuntimeException("SM2签名失败", e); + } + } + + public String generateDeviceActivationPublicKey() { + try { + java.security.KeyPairGenerator keyGen = java.security.KeyPairGenerator.getInstance("EC", PROVIDER); + keyGen.initialize(256); + java.security.KeyPair keyPair = keyGen.generateKeyPair(); + return Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()); + } catch (Exception e) { + throw new RuntimeException("生成设备激活公钥失败", e); + } + } +} \ No newline at end of file diff --git a/device-activation-platform/src/main/java/com/sunyar/cisd/Main.java b/device-activation-platform/src/main/java/com/sunyar/cisd/Main.java deleted file mode 100644 index 22d61ce..0000000 --- a/device-activation-platform/src/main/java/com/sunyar/cisd/Main.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.sunyar.cisd; - -//TIP 要运行代码,请按 或 -// 点击装订区域中的 图标。 -public class Main { - public static void main(String[] args) { - //TIP 当文本光标位于高亮显示的文本处时按 - // 查看 IntelliJ IDEA 建议如何修正。 - System.out.printf("Hello and welcome!"); - - for (int i = 1; i <= 5; i++) { - //TIP 按 开始调试代码。我们已经设置了一个 断点 - // 但您始终可以通过按 添加更多断点。 - System.out.println("i = " + i); - } - } -} \ No newline at end of file diff --git a/device-activation-platform/src/main/resources/application.yml b/device-activation-platform/src/main/resources/application.yml new file mode 100644 index 0000000..5a4408a --- /dev/null +++ b/device-activation-platform/src/main/resources/application.yml @@ -0,0 +1,6 @@ +server: + port: 8080 + +spring: + application: + name: device-activation-platform \ No newline at end of file