添加设备激活相关模块,设计 Bean 的属性。
This commit is contained in:
parent
e14ee17d2c
commit
a89fd0c116
68
device-activation-platform/Readme.md
Normal file
68
device-activation-platform/Readme.md
Normal file
@ -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。
|
||||||
63
device-activation-platform/pom.xml
Normal file
63
device-activation-platform/pom.xml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.5.11</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>com.sunyar</groupId>
|
||||||
|
<artifactId>device-activation-platform</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<name>device-activation-platform</name>
|
||||||
|
<description>Device Activation Platform</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk18on</artifactId>
|
||||||
|
<version>1.83</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcpkix-jdk18on</artifactId>
|
||||||
|
<version>1.83</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,17 +0,0 @@
|
|||||||
package com.sunyar.cisd;
|
|
||||||
|
|
||||||
//TIP 要<b>运行</b>代码,请按 <shortcut actionId="Run"/> 或
|
|
||||||
// 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
//TIP 当文本光标位于高亮显示的文本处时按 <shortcut actionId="ShowIntentionActions"/>
|
|
||||||
// 查看 IntelliJ IDEA 建议如何修正。
|
|
||||||
System.out.printf("Hello and welcome!");
|
|
||||||
|
|
||||||
for (int i = 1; i <= 5; i++) {
|
|
||||||
//TIP 按 <shortcut actionId="Debug"/> 开始调试代码。我们已经设置了一个 <icon src="AllIcons.Debugger.Db_set_breakpoint"/> 断点
|
|
||||||
// 但您始终可以通过按 <shortcut actionId="ToggleLineBreakpoint"/> 添加更多断点。
|
|
||||||
System.out.println("i = " + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: device-activation-platform
|
||||||
Loading…
Reference in New Issue
Block a user