Преглед изворни кода

change:
设备加密绑定功能制作

kindring пре 1 година
родитељ
комит
4cecb82e26

+ 1 - 0
authorize/authorize.hfy

@@ -0,0 +1 @@
+dDZzV05ybXhHNE1rUkt0UGFLVmZjQ0tUZmNVYS92bWRERU1mNWpKK0w5ZHMwVnV0UmVIRzBOWXMwSG9iS21tMXNYN3FpKzR6dTB3SXBTSHJ2dVNKMlhvdEhUdStkNFBHcUdpcmRHRmZMTm9ZMk40UnB6TytRRGswcFlkSEtPM3dpdVovakN2YzZoK3FhVHZUOVpNTFh4alkzaEduTTc1QU9UU2xoMGNvN2ZESDdsd3BsL2xVYTF1Vk0rUkxTbTIx

BIN
package/gbDocker/classfinal-fatjar.jar


+ 6 - 0
pom.xml

@@ -95,6 +95,12 @@
 	</profiles>
 
 	<dependencies>
+<!--		加密依赖,用于实现功能 -->
+		<dependency>
+			<groupId>net.roseboy</groupId>
+			<artifactId>classfinal-core</artifactId>
+			<version>1.2.1</version>
+		</dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-data-redis</artifactId>

+ 7 - 0
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java

@@ -21,6 +21,8 @@ import javax.servlet.SessionCookieConfig;
 import javax.servlet.SessionTrackingMode;
 import java.util.Collections;
 
+import com.genersoft.iot.vmp.conf.Authorize;
+
 /**
  * 启动类
  */
@@ -32,6 +34,7 @@ public class VManageBootstrap extends SpringBootServletInitializer {
 
 	private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class);
 
+	private Authorize authorize = new Authorize();
 	private static String[] args;
 	private static ConfigurableApplicationContext context;
 	public static void main(String[] args) {
@@ -45,6 +48,10 @@ public class VManageBootstrap extends SpringBootServletInitializer {
 		logger.info("构建版本: {}", gitUtil1.getBuildVersion());
 		logger.info("构建时间: {}", gitUtil1.getBuildDate());
 		logger.info("GIT最后提交时间: {}", gitUtil1.getCommitTime());
+		logger.info("机器码: {}", Authorize.getMachineCode());
+//		Authorize.generateAuthorizeFile(Authorize.baseAuthorizeFilePath, "{\"com\":\"深圳合方圆\",\"machineCode\":\"12402306B27BB6D9118EC29224DD3FCDD41D8CD98F00B204E9800998ECF8427ED41D8CD98F00B204E9800998ECF8427E\"}");
+		logger.info("--------------------------------------------------");
+		Authorize.decryptAuthorizeFile(Authorize.baseAuthorizeFilePath);
 	}
 	// 项目重启
 	public static void restart() {

+ 49 - 0
src/main/java/com/genersoft/iot/vmp/conf/AesUtils.java

@@ -0,0 +1,49 @@
+package com.genersoft.iot.vmp.conf;
+
+import com.genersoft.iot.vmp.VManageBootstrap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.Key;
+import java.security.spec.KeySpec;
+import java.util.Base64;
+
+public class AesUtils {
+    private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class);
+    private static final String ALGORITHM = "AES";
+    private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
+
+    // 密钥转换函数
+    public static byte[] deriveAesKeyFromPassword(String password) throws Exception {
+        byte[] salt = new byte[32]; // Generate a random salt
+        int iterationCount = 10000;
+        int keyLength = 256; // 256-bit key length for AES
+
+        KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, iterationCount, keyLength);
+        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
+        byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
+
+        return keyBytes;
+    }
+    public static String encrypt(String data, String password) throws Exception {
+        //
+        Key aesKey = new SecretKeySpec(deriveAesKeyFromPassword(password), ALGORITHM);
+        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
+        cipher.init(Cipher.ENCRYPT_MODE, aesKey);
+        byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
+        return Base64.getEncoder().encodeToString(encryptedBytes);
+    }
+
+    public static String decrypt(String encryptedData, String password) throws Exception {
+        Key aesKey = new SecretKeySpec(deriveAesKeyFromPassword(password), ALGORITHM);
+        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
+        cipher.init(Cipher.DECRYPT_MODE, aesKey);
+        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
+        return new String(decryptedBytes, StandardCharsets.UTF_8);
+    }
+}

+ 141 - 0
src/main/java/com/genersoft/iot/vmp/conf/Authorize.java

@@ -0,0 +1,141 @@
+package com.genersoft.iot.vmp.conf;
+
+//package net.roseboy.classfinal;
+
+
+import com.alibaba.fastjson2.JSON;
+import com.genersoft.iot.vmp.VManageBootstrap;
+import net.roseboy.classfinal.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.Base64Utils;
+
+import java.io.*;
+
+import java.util.List;
+import java.util.Scanner;
+
+// 程序授权类. 用于控制程序的使用权限.
+public class Authorize {
+
+//    调用 lib/classfinal-fatjar.jar 中的方法. 用于获取机器码
+    private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class);
+
+
+    public static String baseAuthorizeFilePath = "authorize/authorize.hfy";
+
+    private String authorizeFilePath = "authorize/authorize.hfy";
+
+    /**
+     * 生成机器码 96 位
+     */
+    public static String getMachineCode() {
+        String code = new String(SysUtils.makeMarchinCode());
+        return code;
+    }
+
+    // 读取授权文件
+    public static byte[] readAuthorizeFile(String path) {
+        if(path == null) {
+            path = baseAuthorizeFilePath;
+        }
+        logger.info("path: {}", path);
+        File file = new File(path);
+        if(!file.exists()) {
+            logger.error("无法获取到授权文件. 请检查授权文件是否存在.");
+            return null;
+        }
+        byte[] data = IoUtils.readFileToByte(file);
+//        String code = new String(data);
+//        logger.info("code: {}", code);
+//        if(code.length() == 0) {
+//            return null;
+//        }
+        // 解析授权文件
+        return data;
+    }
+
+    /**
+     * 解密授权文件
+     * @param authorizePath 授权文件路径
+     * @return
+     */
+    public static String decryptAuthorizeFile(String authorizePath) {
+        try{
+            String machineCode = getMachineCode();
+            byte[] authorizeCode = readAuthorizeFile(authorizePath);
+            if (machineCode == null) {
+                logger.error("机器码获取失败. 请检查联系管理员. ");
+                return null;
+            }
+            if(authorizeCode == null || authorizeCode.length == 0) {
+                logger.error("授权文件读取失败. 请检查授权文件是否存在. ");
+                return null;
+            }
+            // 使用 base64 转换文本
+            byte[] data = Base64Utils.decode(authorizeCode);
+            String code = new String(data);
+            logger.info("code: {}", code);
+            // 解密授权文件
+            String password = machineCode.substring(16, 32) + machineCode + machineCode.substring(64, 80);
+            String decryptStr = AesUtils.decrypt(code, password);
+            logger.info("decryptStr: {}", decryptStr);
+            return decryptStr;
+        }catch (Exception e) {
+            logger.error("授权文件解析失败. 请检查练习管理员进行排查. ");
+            logger.error("错误信息: {}", e.getMessage());
+            return null;
+        }
+    }
+
+    // 生成授权文件
+    public static boolean generateAuthorizeFile(String authorizePath, String authorizeCode) {
+        try{
+            String machineCode = getMachineCode();
+            if (machineCode == null) {
+                logger.error("机器码获取失败. 请检查联系管理员. ");
+                return false;
+            }
+            if(authorizeCode == null || authorizeCode.length() == 0) {
+                logger.error("授权码获取失败. 请检查授权码是否正确. ");
+                return false;
+            }
+            // 机器码长度转换 96 位 到128位 从16位 开始 取 16个字符 添加至机器码前方  再从 64位开始取 16个字符 添加至机器码后方
+            String key = machineCode.substring(16, 32) + machineCode + machineCode.substring(64, 80);
+            logger.info("key: {}", key);
+            logger.info("key length {}", key.length());
+            // 解密授权文件
+            String encryptStr = AesUtils.encrypt(authorizeCode, key);
+            logger.info("encryptStr: {}", encryptStr);
+            // 使用 base64 转换文本
+            byte[] data = Base64Utils.encode(encryptStr.getBytes());
+            String code = new String(data);
+            logger.info("code: {}", code);
+            // 写入文件
+            File file = new File(authorizePath);
+            if(!file.exists()) {
+                file.createNewFile();
+            }
+            IoUtils.writeTxtFile(file, code);
+            return true;
+        }catch (Exception e) {
+            logger.error("授权文件生成失败. 请检查练习管理员进行排查. ");
+            logger.error("错误信息: {}", e.getMessage());
+            return false;
+        }
+    }
+
+    // 基础授权文件解析
+    public static authorData parseBaseAuthorizeFile(String authorizePath) {
+        String data = decryptAuthorizeFile(authorizePath);
+        if(data == null) {
+            return null;
+        }
+        // json 解析 fastjson2 依赖
+        JSONObject  = JSON.parse(data);
+        return authorData;
+    }
+
+
+
+}

+ 55 - 0
src/main/java/com/genersoft/iot/vmp/conf/authorData.java

@@ -0,0 +1,55 @@
+package com.genersoft.iot.vmp.conf;
+
+
+public class authorData {
+    // 机器码
+    private String machineCode;
+    // 公司名
+    private String company;
+    // 随机码
+    private String authorizeCode;
+    // 授权申请时间
+    private String authorizeTime;
+    // 用户密码, 用于程序运行
+    private String password;
+
+    public String getMachineCode() {
+        return machineCode;
+    }
+
+    public void setMachineCode(String machineCode) {
+        this.machineCode = machineCode;
+    }
+
+    public String getCompany() {
+        return company;
+    }
+
+    public void setCompany(String company) {
+        this.company = company;
+    }
+
+    public String getAuthorizeCode() {
+        return authorizeCode;
+    }
+
+    public void setAuthorizeCode(String authorizeCode) {
+        this.authorizeCode = authorizeCode;
+    }
+
+    public String getAuthorizeTime() {
+        return authorizeTime;
+    }
+
+    public void setAuthorizeTime(String authorizeTime) {
+        this.authorizeTime = authorizeTime;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

BIN
src/main/lib/classfinal-fatjar.jar


+ 2 - 0
依赖库/README.md

@@ -0,0 +1,2 @@
+# 用于直接存放项目依赖的库
+> github 上直接下载

+ 2 - 1
设备绑定机制.md

@@ -19,6 +19,7 @@
 - 机器码
 - 服务端时间戳
 - 随机码
+- 用户密码
 
 2. 授权信息文件
 > 用于存储授权信息
@@ -30,4 +31,4 @@
 
 3. 授权程序
 - 程序运行的时间戳
-- 上次记录生成的时间戳
+- 上次记录生成的时间戳