云计算百科
云计算领域专业知识百科平台

从零开始实现 Java 程序 License 验证系统(附完整代码与实操指南)

前言

最近自己在做一款用户对于安全性要求很高的工具软件,结合实际工程经验做一下分享。毕竟在软件开发中,为了保护知识产权、控制软件使用权限,License 验证系统是常见的技术手段。本文将以单机 Java 程序为例,详细讲解如何实现一套完整的 License 验证系统,涵盖RSA 非对称加密、AES 对称加密、硬件绑定、有效期校验等核心功能,且原理同样适用于 BS 架构程序(文末会说明 BS 场景的适配方法)。

通过本文,你将学会:

  • 生成 RSA 公私钥对
  • 获取机器唯一硬件标识(防篡改)
  • 生成带有效期和硬件绑定的 License
  • 加密存储 License 配置文件
  • 程序启动时验证 License 有效性
  • 一、系统架构与核心原理

    1.1 整体流程概览

    License 验证系统的核心是 “先加密生成,后解密验证”,如下:

    1.2 核心加密技术

    • RSA 非对称加密:开发者持有私钥(生成 License),程序持有公钥(验证 License)。私钥加密的内容只能用公钥解密,确保 License 无法被伪造。
    • AES 对称加密:用于加密存储 License 配置文件(公钥 + 加密 License),避免明文暴露。AES 密钥通过环境变量传递(不硬编码),提升安全性。
    • 硬件绑定:通过收集机器的 MAC 地址、CPU 序列号等唯一标识,确保 License 仅能在指定机器运行。

    二、核心代码实现(附完整类)

    2.1 License 核心工具类(LicenseUtils.java)

    负责生成 RSA 密钥对、生成 License、验证 License,以及获取硬件信息。

    import javax.crypto.BadPaddingException;

    import javax.crypto.Cipher;

    import javax.crypto.IllegalBlockSizeException;

    import java.io.IOException;

    import java.net.NetworkInterface;

    import java.nio.charset.StandardCharsets;

    import java.security.*;

    import java.security.spec.PKCS8EncodedKeySpec;

    import java.security.spec.X509EncodedKeySpec;

    import java.time.LocalDate;

    import java.time.format.DateTimeFormatter;

    import java.util.*;

    import java.util.List;

    public class LicenseUtils {

        // RSA算法常量

        private static final String RSA_ALGORITHM = \”RSA\”;

        // 日期格式(严格ISO标准:yyyy-MM-dd)

        private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE;

        /**

         * 生成RSA公私钥对(2048位)

         */

        public static KeyPair generateRsaKeyPair() throws NoSuchAlgorithmException {

            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA_ALGORITHM);

            keyPairGen.initialize(2048); // 2048位密钥,足够安全

            return keyPairGen.generateKeyPair();

        }

        /**

         * 生成License(私钥加密)

         * @param privateKeyBase64 私钥(Base64编码)

         * @param expireDate 有效期(格式:yyyy-MM-dd)

         * @param hardwareInfo 硬件信息(机器唯一标识)

         */

        public static String generateLicense(String privateKeyBase64, String expireDate, String hardwareInfo) throws Exception {

            // 验证日期格式

            LocalDate.parse(expireDate, DATE_FORMATTER); 

            

            // 拼接License内容:有效期|硬件信息(用|分隔)

            String licenseContent = String.format(\”%s|%s\”, expireDate, hardwareInfo);

            

            // 私钥解密

            PrivateKey privateKey = getPrivateKey(privateKeyBase64);

            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);

            cipher.init(Cipher.ENCRYPT_MODE, privateKey);

            byte[] encrypted = cipher.doFinal(licenseContent.getBytes(StandardCharsets.UTF_8));

            

            return Base64.getEncoder().encodeToString(encrypted);

        }

        /**

         * 验证License(公钥解密+有效性检查)

         * @param publicKeyBase64 公钥(Base64编码)

         * @param encryptedLicense 加密的License(Base64编码)

         */

        public static boolean verifyLicense(String publicKeyBase64, String encryptedLicense) throws Exception {

            // 公钥解密

            PublicKey publicKey = getPublicKey(publicKeyBase64);

            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedLicense);

            

            String licenseContent;

            try {

                Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);

                cipher.init(Cipher.DECRYPT_MODE, publicKey);

                licenseContent = new String(cipher.doFinal(encryptedBytes), StandardCharsets.UTF_8);

            } catch (IllegalBlockSizeException | BadPaddingException e) {

                throw new SecurityException(\”License解密失败(可能被篡改)\”);

            }

            // 解析License内容(有效期|硬件信息)

            String[] parts = licenseContent.split(\”\\\\|\”);

            if (parts.length != 2) {

                throw new IllegalArgumentException(\”License格式错误,预期:有效期|硬件信息,实际:\” + licenseContent);

            }

            // 检查有效期

            LocalDate expireDate = LocalDate.parse(parts[0], DATE_FORMATTER);

            if (LocalDate.now().isAfter(expireDate)) {

                throw new SecurityException(\”License已过期(有效期至:\” + parts[0] + \”)\”);

            }

            // 检查硬件信息

            String currentHardware = getHardwareInfo();

            if (!currentHardware.equals(parts[1])) {

                throw new SecurityException(\”硬件信息不匹配(当前:\” + currentHardware + \”,注册:\” + parts[1] + \”)\”);

            }

            return true;

        }

        /**

         * 获取机器硬件信息(MAC地址+CPU/主板序列号)

         */

        public static String getHardwareInfo() throws IOException {

            List<String> identifiers = new ArrayList<>();

            // 1. 获取所有非环回网卡的MAC地址

            try {

                String mac = getMacAddress();

                if (!mac.isEmpty()) identifiers.add(mac);

            } catch (Exception e) {

                System.err.println(\”获取MAC地址失败:\” + e.getMessage());

            }

            // 2. 获取CPU/主板序列号(跨平台)

            try {

                String serial = getHardwareSerial();

                if (!serial.isEmpty()) identifiers.add(serial);

            } catch (Exception e) {

                System.err.println(\”获取硬件序列号失败:\” + e.getMessage());

     &nbs

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 从零开始实现 Java 程序 License 验证系统(附完整代码与实操指南)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!