SpringBoot包进行加密
前言
笔者使用 ProGuard
最后没跑起来,打包后,跑一半碰到一些奇奇怪怪的 Bean 缺失,所以,你们能跑就能跑,不能跑看其他文章吧。
ProGuard
介绍
ProGuard 是一个用于 Java 字节码的代码优化和混淆工具。它能够在将 Java 代码编译成字节码后,对字节码进行优化、压缩和混淆,以减小代码体积、提高执行性能,并增加代码的安全性。
主要提供以下功能:
- 代码混淆:ProGuard 可以对类、方法、字段等进行重命名,使得反编译后的代码难以理解和逆向工程。这有助于保护你的代码免受恶意用户的逆向分析。
- 代码压缩:ProGuard 可以删除无用的类、方法、字段和代码块,减小生成的字节码文件大小。这有助于减少应用程序的下载和加载时间。
- 类优化:ProGuard 可以执行一些优化操作,例如移除无用的类和方法调用、内联短方法、合并常量等,从而提高应用程序的运行性能。
- 资源压缩:除了优化字节码,ProGuard 还可以处理应用程序的资源文件,如图片、布局文件等,从而减小应用的 APK 大小。
- 消除未使用的代码:ProGuard 可以分析应用程序的代码,并检测出未使用的代码,然后将其删除,以减小应用的大小。
- 类、方法级别的访问控制:ProGuard 可以帮助你限制外部访问你的类和方法,以增加代码的安全性。
- 自动优化:ProGuard 的配置文件可以根据你的需求进行定制,同时 ProGuard 也提供了一些默认的优化和混淆规则,使得配置变得相对简单。
- 支持多种输入输出格式:ProGuard 可以处理不同格式的输入文件,包括 JAR、WAR、EAR、APK 等,也可以生成不同格式的输出文件。
通常,ProGuard 用于优化和混淆 Android 应用的代码,以保护应用的知识产权,减小应用的大小,提高性能。同时,它也可以用于普通的 Java 应用程序,以提高执行性能和安全性。不过需要注意的是,使用 ProGuard 时需要仔细测试,确保应用程序的功能和性能没有受到影响。
引入插件
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.demo</groupId>
<artifactId>test-demo</artifactId>
<version>1.0</version>
</parent>
<artifactId>test-api</artifactId>
<packaging>jar</packaging>
<!--<packaging>war</packaging>-->
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- 省略 -->
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- 代码混淆 -->
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.6.0</version>
<executions>
<!-- 以下配置说明执行mvn的package命令时候,会执行proguard-->
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 对什么东西进行加载,这里仅有classes成功,不可能对配置文件及JSP混淆吧 -->
<injar>${project.build.finalName}.jar</injar>
<!-- 输出jar名称,输入输出jar同名的时候就是覆盖,也是比较常用的配置。 -->
<outjar>${project.build.finalName}.jar</outjar>
<!-- 这是输出路径配置,但是要注意这个路径必须要包括injar标签填写的jar -->
<outputDirectory>${project.build.directory}</outputDirectory>
<!-- 是否混淆 默认是true -->
<obfuscate>true</obfuscate>
<!-- 配置一个文件,通常叫做proguard.cfg,该文件主要是配置options选项,也就是说使用proguard.cfg那么options下的所有内容都可以移到proguard.cfg中 -->
<proguardInclude>${project.basedir}/proguard.cfg</proguardInclude>
<!-- 报错 文件名或扩展名太长,加上这个就好了 -->
<putLibraryJarsInTempDir>true</putLibraryJarsInTempDir>
<!-- 额外的jar包,通常是项目编译所需要的jar -->
<libs>
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jce.jar</lib>
<lib>${java.home}/lib/jsse.jar</lib>
</libs>
<!-- 对输入jar进行过滤比如,如下配置就是对META-INFO文件不处理。 -->
<!--<inLibsFilter>!META-INF/**,!META-INF/versions/9/**.class</inLibsFilter>-->
<!--这里特别重要,此处主要是配置混淆的一些细节选项,比如哪些类不需要混淆,哪些需要混淆-->
<options>
<!-- 可以在此处写option标签配置,不过我上面使用了proguardInclude,故而我更喜欢在proguard.cfg中配置 -->
</options>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
<excludeGroupIds>
org.projectlombok
</excludeGroupIds>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 打 war 包启用以下配置 -->
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<!– 中创中间件需排除依赖 –>
<!–
<packagingExcludes>
WEB-INF/lib/jul-to-slf4j-*.jar,
WEB-INF/lib/javax.servlet-api-*.jar,
WEB-INF/lib/tomcat-*.jar,
%regex[WEB-INF/lib/jackson-(annotations|core|databind|module-jaxb-annotations|module-parameter-names)-.*\.jar]
</packagingExcludes>
–>
</configuration>
</plugin>
-->
<!-- 编码和编译和JDK版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<!--打包插件-->
<!--
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
-->
</plugins>
</build>
</project>
混淆字典
文件 directory.txt
放在项目根目录,内容如下,每行保持唯一性就行:
0000O000000o
000O00000Oo
000O00000o0
000O00000o
000O00000oO
000O00000oo
000O0000O0o
000O0000OOo
000O0000Oo0
000O0000Oo
这里提供 2 个字典:directory-cn.txt 、directory.txt
或者直接上 GitHub 搜索,点此前往
混淆参数
新建文件 proguard.cfg
放在项目根目录,参考内容如下:
# 配置字典
-obfuscationdictionary 'directory.txt'
-classobfuscationdictionary 'directory-cn.txt'
-packageobfuscationdictionary 'directory.txt'
# 指定Java的版本
-target 1.8
# 不警告
-dontwarn
# 不理会警告,否则混淆失败
-ignorewarnings
# 用于在混淆和优化过程中保留输入目录结构。
-keepdirectories
# 不压缩,proguard会对代码进行优化压缩,他会删除从未使用的类或者类成员变量等
-dontshrink
# 不优化,是否关闭字节码级别的优化
-dontoptimize
# 在混淆过程中不要跳过非公共库类和非公共库类成员。
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
# 混淆时不生成大小写混合的类名,默认是可以大小写混合
-dontusemixedcaseclassnames
# 对于类成员的命名的混淆采取唯一策略(一个类中的成员不使用重复的命名,如Student类混淆后不能出现a属性和a方法。)
-useuniqueclassmembernames
# 混淆类名之后,对使用Class.forName('className')之类的地方进行相应替代
-adaptclassstrings
# 不混淆所有特殊的类,对异常、注解信息、泛型予以保留
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
# 此选项将保存接口中的所有原始名称(不混淆)-->
-keepnames interface ** { *; }
# 保留参数名,因为控制器,或者Mybatis等接口的参数如果混淆会导致无法接受参数,xml文件找不到参数
-keepparameternames
# 不混淆枚举
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 不混淆所有类,保存原始定义的注释-
-keepclassmembers class * {
@org.springframework.context.annotation.Bean *;
@org.springframework.beans.factory.annotation.Autowired *;
@org.springframework.beans.factory.annotation.Value *;
@org.springframework.stereotype.Service *;
@org.springframework.stereotype.Component *;
@org.springframework.cloud.client.discovery.EnableDiscoveryClient *;
@org.springframework.cloud.netflix.eureka.EnableEurekaClient *;
@org.springframework.cloud.openfeign.EnableFeignClients *;
@org.springframework.context.annotation.Import *;
@org.springframework.boot.autoconfigure.SpringBootApplication *;
@com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig *;
}
# 打印配置信息
-printconfiguration
# springboot 入口
-keep class cn.demo.DemoRunApiApplication { *; }
注意:
启动类不能混淆
Bean 的名称重复,让 SpringBoot 生成唯一的 BeanName
@SpringBootApplication public class DemoRunApiApplication { public static class CustomGenerator implements BeanNameGenerator { @Override public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { // 将 bean 改为 包路径 + 类名 return definition.getBeanClassName(); } } public static void main(String[] args) { new SpringApplicationBuilder(DemoRunApiApplication.class) .beanNameGenerator(new CustomGenerator()) .run(args); } }
实体类要保留
这里的实体类包括各种 Entity、DTO......原因解释:
- Mybatis 的 XML 的 ResultType 需要实体类的全路径
- Jackson 需要序列化,字段混淆前端会找不到
Controller 要保留
解释:Controller 混淆了前端找不到请求路径,模板引擎例如 thymeleaf 找不到路径
SpringBoot Config 配置不能混淆
解释:一些配置类比如 datasource、aopconfig 如果混淆会导致各种启动报错
编译打包
正常操作即可
XJar
介绍
xjar 是一个 Spring Boot JAR 安全加密运行工具,同时支持的原生 JAR。基于对 JAR 包内资源的加密以及拓展 ClassLoader 来构建的一套程序加密启动, 动态解密运行的方案,避免源码泄露以及反编译。
功能特性:
- 无代码侵入,只需要把编译好的 JAR 包通过工具加密即可
- 完全内存解密,降低源码以及字节码泄露或反编译的风险
- 支持所有 JDK 内置加解密算法
- 可选择需要加解密的字节码或其他资源文件
- 支持 Maven 插件,加密更加便捷
- 动态生成 Go 启动器,保护密码不泄露
使用
普通方式
引入依赖
<project>
<!-- 设置 jitpack.io 仓库(必须添加 https://jitpack.io Maven仓库) -->
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<!-- 添加 XJar 依赖 -->
<dependencies>
<dependency>
<groupId>com.github.core-lib</groupId>
<artifactId>xjar</artifactId>
<version>4.0.2</version>
<!-- 如果使用 JUnit 测试类来运行加密可以将 XJar 依赖的 scope 设置为 test -->
<!-- <scope>test</scope> -->
</dependency>
</dependencies>
</project>
加密源码
XCryptos.encryption()
.from("/path/to/read/plaintext.jar")
.use("io.xjar")
.include("/io/xjar/**/*.class")
.include("/mapper/**/*Mapper.xml")
.exclude("/static/**/*")
.exclude("/conf/*")
.to("/path/to/save/encrypted.jar");
方法名称 | 参数列表 | 是否必选 | 方法说明 |
---|---|---|---|
from | (String jar) | 二选一 | 指定待加密 JAR 包路径 |
from | (File jar) | 指定待加密 JAR 包文件 | |
use | (String password) | 二选一 | 指定加密密码 |
use | (String algorithm, int keysize, int ivsize, String password) | 指定加密算法及加密密码 | |
include | (String ant) | 可多次调用 | 指定要加密的资源相对于 classpath 的 ANT 路径表达式 |
include | (Pattern regex) | 可多次调用 | 指定要加密的资源相对于 classpath 的正则路径表达式 |
exclude | (String ant) | 可多次调用 | 指定不加密的资源相对于 classpath 的 ANT 路径表达式 |
exclude | (Pattern regex) | 可多次调用 | 指定不加密的资源相对于 classpath 的正则路径表达式 |
to | (String xJar) | 二选一 | 指定加密后 JAR 包输出路径, 并执行加密. |
to | (File xJar) | 指定加密后 JAR 包输出文件, 并执行加密. |
注:
- 指定加密算法的时候密钥长度以及向量长度必须在算法可支持范围内,具体加密算法的密钥及向量长度请自行百度或谷歌。
- include 和 exclude 同时使用时即加密在 include 的范围内且排除了 exclude 的资源。
编译脚本
go build xjar.go
注:
- 通过上方加密源码进行加密并且加密成功后 XJar 会在输出的 JAR 包同目录下生成一个名为 xjar.go 的的 Go 启动器源码文件。
- 将 xjar.go 在不同的平台进行编译即可得到不同平台的启动器可执行文件,其中 Windows 下文件名为 xjar.exe 而 Linux 下为 xjar。
- 用于编译的机器需要安装 Go 环境,用于运行的机器则可不必安装 Go 环境,具体安装教程请自行搜索。
- 由于启动器自带 JAR 包防篡改校验,故启动器无法通用,即便密码相同也不行。
启动运行
# 运行方式如下
/path/to/xjar /path/to/java [OPTIONS] -jar /path/to/encrypted.jar [ARGS]
/path/to/xjar /path/to/javaw [OPTIONS] -jar /path/to/encrypted.jar [ARGS]
# 若使用 nohup 方式启动则 nohup 要放在 Go 启动器可执行文件名(xjar)之前。
nohup /path/to/xjar /path/to/java [OPTIONS] -jar /path/to/encrypted.jar [ARGS]
# 例子: 如果当前命令行就在 xjar 所在目录, java 环境变量也设置好了
./xjar java -Xms256m -Xmx1024m -jar /path/to/encrypted.jar
# 由于 -jar 后面必须紧跟文件路径,会导致 -D 参数无法使用,不完美解决方案就是设置临时会话的环境变量(以下是 win 方式)
set env=dev && xjar.exe java -jar hfrdp3-api.jar
注:
- 在 Java 启动命令前加上编译好的 Go 启动器可执行文件名(xjar)即可启动运行加密后的 JAR 包。
- 若 Go 启动器可执行文件名(xjar)不在当前命令行所在目录则要通过绝对路径或相对路径指定。
- 仅支持通过
-jar
方式启动, 不支持-cp
或-classpath
的方式。 -
-jar
后面必须紧跟着启动的加密 jar 文件路径!
Maven 插件集成
Maven 项目可通过集成 xjar-maven-plugin 以免去每次加密都要执行一次上述的代码,随着 Maven 构建自动生成加密后的 JAR 和 Go 启动器源码文件。
引入依赖
<project>
<!-- 设置 jitpack.io 插件仓库 -->
<pluginRepositories>
<pluginRepository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</pluginRepository>
</pluginRepositories>
<!-- 添加 XJar Maven 插件 -->
<build>
<plugins>
<plugin>
<groupId>com.github.core-lib</groupId>
<artifactId>xjar-maven-plugin</artifactId>
<version>4.0.2</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
<phase>package</phase>
<!-- 将插件的 phase 设置为 install(默认值为:package), 打包命令采用 mvn clean install -->
<!-- <phase>install</phase> -->
<configuration>
<password>io.xjar</password>
<!-- 可选参数 -->
<!--
<algorithm/>
<keySize/>
<ivSize/>
<includes>
<include/>
</includes>
<excludes>
<exclude/>
</excludes>
<sourceDir/>
<sourceJar/>
<targetDir/>
<targetJar/>
-->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
对于 Spring Boot 项目或模块, 该插件要后于 spring-boot-maven-plugin
插件执行, 有两种方式:
- 将插件放置于
spring-boot-maven-plugin
的后面,因为其插件的默认phase
也是package
- 将插件的
phase
设置为install
,打包命令采用mvn clean install
注意:
不兼容 spring-boot-maven-plugin
的 executable = true
以及 embeddedLaunchScript
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- 需要将executable和embeddedLaunchScript参数删除, 目前还不能支持对该模式Jar的加密!后面可能会支持该方式的打包.
<configuration>
<executable>true</executable>
<embeddedLaunchScript>...</embeddedLaunchScript>
</configuration>
-->
</plugin>
编译 JAR
也可以通过 Maven 命令执行:
mvn xjar:build -Dxjar.password=io.xjar
mvn xjar:build -Dxjar.password=io.xjar -Dxjar.targetDir=/directory/to/save/target.xjar
# 但通常情况下是让 XJar 插件绑定到指定的 phase 中自动执行,这样就能在项目构建的时候自动构建出加密的包。
mvn clean package -Dxjar.password=io.xjar
mvn clean install -Dxjar.password=io.xjar -Dxjar.targetDir=/directory/to/save/target.xjar
强烈建议不要在 pom.xml
的 xjar-maven-plugin
配置中写上密码,这样会导致打包出来的 xjar
包中的 pom.xml
文件保留着密码,极其容易暴露密码!强烈推荐通过 mvn
命令来指定加密密钥!
参数说明:
参数名称 | 命令参数名称 | 参数说明 | 参数类型 | 缺省值 | 示例值 |
---|---|---|---|---|---|
password | -Dxjar.password | 密码字符串 | String | 必须 | 任意字符串, io.xjar |
algorithm | -Dxjar.algorithm | 加密算法名称 | String | AES/CBC/PKCS5Padding | JDK 内置加密算法, 如:AES/CBC/PKCS5Padding 和 DES/CBC/PKCS5Padding |
keySize | -Dxjar.keySize | 密钥长度 | int | 128 | 根据加密算法而定, 56, 128, 256 |
ivSize | -Dxjar.ivSize | 密钥向量长度 | int | 128 | 根据加密算法而定, 128 |
sourceDir | -Dxjar.sourceDir | 源 jar 所在目录 | File | ${project.build.directory} | 文件目录 |
sourceJar | -Dxjar.sourceJar | 源 jar 名称 | String | ${project.build.finalName}.jar | 文件名称 |
targetDir | -Dxjar.targetDir | 目标 jar 存放目录 | File | ${project.build.directory} | 文件目录 |
targetJar | -Dxjar.targetJar | 目标 jar 名称 | String | ${project.build.finalName}.xjar | 文件名称 |
includes | -Dxjar.includes | 需要加密的资源路径表达式 | String[] | 无 | io/xjar/* , mapper/Mapper.xml , 支持 Ant 表达式 |
excludes | -Dxjar.excludes | 无需加密的资源路径表达式 | String[] | 无 | static/ , META-INF/resources/ , 支持 Ant 表达式 |
注:
- 指定加密算法的时候密钥长度以及向量长度必须在算法可支持范围内,具体加密算法的密钥及向量长度请自行百度或谷歌。
- include 和 exclude 同时使用时即加密在 include 的范围内且排除了 exclude 的资源。
go-jar-encryption
go-jar-encryption 是对 xjar 项目进行封装,使用 golang 编写 pc 客户端,方便运维操作,操作界面丰富,上手简单,可编译出 win、linux 平台的可执行加密后的 jar 包。
下载链接:go-java-jar-encryption_win64.zip
jar-protect
介绍
jar-protect 是 java 的 jar 加密加壳工具,对 class 文件进行加密防护,对 peroperties、yml 等配置文件进行加密,避免反编译破解,从而保护软件版权。
使用说明:
- 使用 jdk8 编译,支持 jdk8+ 版本
- 目前支持 springboot 打包的 jar 文件(其他未测)
- 目前支持 class 文件加密和 yml、properties、xml 等配置文件加密
除了代码写的蛮拉胯的,其他还成。(这是笔者 fork 格式化等操作后的.....)
原理
使用
下载源码并打包
git clone https://gitee.com/nn200433/jar-protect.git mvn clean package
- 得到
jar-project.jar
文件,把它复制到你想放的位置 新建
jar-project.security.properties
文件参考如下:
# 过期时间,为空则不限制过期时间(默认到9999-01-01) expireTime=2023-08-19 # 加密密码,为空则随机生成动态密码 password= # 加密解密文件地址(加密java代码源码),为空则使用自带des加密(参考底下的加密文件模板) myEncryptCodeFile= # 加密方写入的版权信息声明,为空则无 myVersionInfo=请正规渠道获得版本授权文件,严禁进行反编译修改或破解,一经发现会追溯法律责任!
加密文件模板:
package com.free.bsf.jarprotect.core.encrypt; import com.free.bsf.jarprotect.core.base.BsfException; import com.free.bsf.jarprotect.core.base.Context; import com.free.bsf.jarprotect.core.encrypt.IEncrypt; /*MyEncrypt类名不能更改,注意引用相应的包(仅支持jdk自身的类库,不能使用第三方类库)*/ public class MyEncrypt implements IEncrypt { @Override public byte[] e(byte[] d) { try { //Context.Default.getPassword() /*加密逻辑代码*/ }catch (Exception e){ throw new BsfException(e); } } @Override public byte[] d(byte[] d) { try { //Context.Default.getPassword() /*解密逻辑代码*/ }catch (Exception e){ throw new BsfException(e); } } }
加密 SrpingBoot 项目
# fromJar 待加密的jar包的地址,支持相对路径 # excludeClass 排除(不加密)类文件,支持前后*进行模糊匹配 # includeJar 包含(需要加密)jar包,支持前后*进行模糊匹配 # includeConfig 包含(需要加密)文件,如.xml,.properties,.yml等配置文件,支持前后*进行模糊匹配 # 多个配置都是用英文逗号隔开的 # jdk17 需要加 --add-opens java.base/java.lang=ALL-UNNAMED java -jar jar-project.jar --fromJar "D:\\demo\\demo-api\\target\\demo-api.jar" --excludeClass "*Application*" --includeJar "demo-*" --includeConfig "*.properties"
运行成功后会在
D:\demo\demo-api\target
目录下生成encrypt-demo-api.jar
与encrypt-demo-api.security.properties
两个文件。
# 配套的许可,你需要它来运行jar! # Fri Aug 18 20:47:52 CST 2023 password=54d36905d49d4783bdc749d524477f87 myDecryptCode=MjAyMy0wOC0xOV95djY2dmdBQUFEUUFZQUVBTDJOdmJTOW1jbVZsTDJKelppOXFZWEp3Y205MFpXTjBMMk52Y21VdlpXNWpjbmx3ZEM5RmJtTnllWEIwUkVWVEJ3QUJBUUFRYW1GMllTOXNZVzVuTDA5aWFtVmpkQWNBQXdFQUxXTnZiUzltY21WbEwySnpaaTlxWVhKd2NtOTBaV04wTDJOdmNtVXZaVzVqY25sd2RDOUpSVzVqY25sd2RBY0FCUUVBQmp4cGJtbDBQZ0VBQXlncFZnRUFCRU52WkdVQkFBOU1hVzVsVG5WdFltVnlWR0ZpYkdVQkFCSk1iMk5oYkZaaGNtbGhZbXhsVkdGaWJHVUJBQVIwYUdsekFRQXhUR052YlM5bWNtVmxMMkp6Wmk5cVlYSndjbTkwWldOMEwyTnZjbVV2Wlc1amNubHdkQzlGYm1OeWVYQjBSRVZUT3d3QUJ3QUlDZ0FFQUE0QkFBRmxBUUFHS0Z0Q0tWdENBUUFCWkFFQUUycGhkbUV2YkdGdVp5OUZlR05sY0hScGIyNEhBQk1CQUFaa1pYTkxaWGtCQUI1TWFtRjJZWGd2WTNKNWNIUnZMM053WldNdlJFVlRTMlY1VTNCbFl6c0JBQXByWlhsR1lXTjBiM0o1QVFBZlRHcGhkbUY0TDJOeWVYQjBieTlUWldOeVpYUkxaWGxHWVdOMGIzSjVPd0VBQ1hObFkzSmxkR3RsZVFFQUdFeHFZWFpoZUM5amNubHdkRzh2VTJWamNtVjBTMlY1T3dFQUJuSmhibVJ2YlFFQUhFeHFZWFpoTDNObFkzVnlhWFI1TDFObFkzVnlaVkpoYm1SdmJUc0JBQVpqYVhCb1pYSUJBQlZNYW1GMllYZ3ZZM0o1Y0hSdkwwTnBjR2hsY2pzQkFCVk1hbUYyWVM5c1lXNW5MMFY0WTJWd2RHbHZianNCQUFKYlFnRUFEVk4wWVdOclRXRndWR0ZpYkdVQkFCeHFZWFpoZUM5amNubHdkRzh2YzNCbFl5OUVSVk5MWlhsVGNHVmpCd0FpQVFBcFkyOXRMMlp5WldVdlluTm1MMnBoY25CeWIzUmxZM1F2WTI5eVpTOWlZWE5sTDBOdmJuUmxlSFFIQUNRQkFBZEVaV1poZFd4MEFRQXJUR052YlM5bWNtVmxMMkp6Wmk5cVlYSndjbTkwWldOMEwyTnZjbVV2WW1GelpTOURiMjUwWlhoME93d0FKZ0FuQ1FBbEFDZ0JBQXRuWlhSUVlYTnpkMjl5WkFFQUZDZ3BUR3BoZG1FdmJHRnVaeTlUZEhKcGJtYzdEQUFxQUNzS0FDVUFMQUVBQkZWVVJqZ0JBQnBNYW1GMllTOXVhVzh2WTJoaGNuTmxkQzlEYUdGeWMyVjBPd3dBTGdBdkNRQUNBREFCQUJCcVlYWmhMMnhoYm1jdlUzUnlhVzVuQndBeUFRQUlaMlYwUW5sMFpYTUJBQjRvVEdwaGRtRXZibWx2TDJOb1lYSnpaWFF2UTJoaGNuTmxkRHNwVzBJTUFEUUFOUW9BTXdBMkFRQUZLRnRDS1ZZTUFBY0FPQW9BSXdBNUFRQURSRVZUQ0FBN0FRQWRhbUYyWVhndlkzSjVjSFJ2TDFObFkzSmxkRXRsZVVaaFkzUnZjbmtIQUQwQkFBdG5aWFJKYm5OMFlXNWpaUUVBTXloTWFtRjJZUzlzWVc1bkwxTjBjbWx1WnpzcFRHcGhkbUY0TDJOeWVYQjBieTlUWldOeVpYUkxaWGxHWVdOMGIzSjVPd3dBUHdCQUNnQStBRUVCQUE1blpXNWxjbUYwWlZObFkzSmxkQUVBTmloTWFtRjJZUzl6WldOMWNtbDBlUzl6Y0dWakwwdGxlVk53WldNN0tVeHFZWFpoZUM5amNubHdkRzh2VTJWamNtVjBTMlY1T3d3QVF3QkVDZ0ErQUVVQkFCcHFZWFpoTDNObFkzVnlhWFI1TDFObFkzVnlaVkpoYm1SdmJRY0FSd29BU0FBT0FRQVRhbUYyWVhndlkzSjVjSFJ2TDBOcGNHaGxjZ2NBU2dFQUtTaE1hbUYyWVM5c1lXNW5MMU4wY21sdVp6c3BUR3BoZG1GNEwyTnllWEIwYnk5RGFYQm9aWEk3REFBL0FFd0tBRXNBVFFFQUJHbHVhWFFCQURNb1NVeHFZWFpoTDNObFkzVnlhWFI1TDB0bGVUdE1hbUYyWVM5elpXTjFjbWwwZVM5VFpXTjFjbVZTWVc1a2IyMDdLVllNQUU4QVVBb0FTd0JSQVFBSFpHOUdhVzVoYkF3QVV3QVJDZ0JMQUZRQkFDNWpiMjB2Wm5KbFpTOWljMll2YW1GeWNISnZkR1ZqZEM5amIzSmxMMkpoYzJVdlFuTm1SWGhqWlhCMGFXOXVCd0JXQVFBWUtFeHFZWFpoTDJ4aGJtY3ZWR2h5YjNkaFlteGxPeWxXREFBSEFGZ0tBRmNBV1FFQUNVRnNaMjl5YVhSb2JRRUFFa3hxWVhaaEwyeGhibWN2VTNSeWFXNW5Pd0VBRFVOdmJuTjBZVzUwVm1Gc2RXVUJBQXBUYjNWeVkyVkdhV3hsQVFBUFJXNWpjbmx3ZEVSRlV5NXFZWFpoQUNFQUFnQUVBQUVBQmdBQkFCb0FXd0JjQUFFQVhRQUFBQUlBUEFBREFBRUFCd0FJQUFFQUNRQUFBQzhBQVFBQkFBQUFCU3EzQUEreEFBQUFBZ0FLQUFBQUJnQUJBQUFBRHdBTEFBQUFEQUFCQUFBQUJRQU1BQTBBQUFBQkFCQUFFUUFCQUFrQUFBQU9BQUVBQWdBQUFBSUJzQUFBQUFBQUFRQVNBQkVBQVFBSkFBQUE4Z0FFQUFjQUFBQk11d0FqV2JJQUtiWUFMYklBTWJZQU43Y0FPazBTUExnQVFrNHRMTFlBUmpvRXV3QklXYmNBU1RvRkVqeTRBRTQ2QmhrR0JSa0VHUVcyQUZJWkJpdTJBRld3VGJzQVYxa3N0d0JhdndBQkFBQUFRUUJDQUJRQUF3QUtBQUFBSmdBSkFBQUFKUUFVQUNZQUdnQW5BQ0VBS0FBcUFDa0FNUUFxQURzQUt3QkNBQ3dBUXdBdEFBc0FBQUJTQUFnQUZBQXVBQlVBRmdBQ0FCb0FLQUFYQUJnQUF3QWhBQ0VBR1FBYUFBUUFLZ0FZQUJzQUhBQUZBREVBRVFBZEFCNEFCZ0JEQUFrQUVBQWZBQUlBQUFCTUFBd0FEUUFBQUFBQVRBQVNBQ0FBQVFBaEFBQUFDQUFCOXdCQ0J3QVVBQUVBWGdBQUFBSUFYdz09
解密命令
需配套解密配置文件
encrypt-demo-api.security.properties
一同食用!!!# 语法:java -javaagent:已加密.jar -jar 已加密.jar # jdk17 需要加 --add-opens java.base/java.lang=ALL-UNNAMED java -javaagent:encrypt-demo-api.jar -jar encrypt-demo-api.jar
smart-license
介绍
smart-license 是一款用于安全加固的开源项目。 主要服务于非开源产品、商业软件、具备试用功能的付费软件等,为软件提供授权制的使用方式。
名词介绍:
- License,通过 smart-license 生成的授权文件,导入至要授权使用的软件产品中。
- 授权内容,需要进行 License 加工处理的基础数据。例如,将软件产品运行的配置文件作为源数据,经由 smart-license 授权处理后生成 License 文件。
原理
使用
云端申请 License
- 登录 Shield.盾(笔者逆推了下证书生成『后面发现原作者旧版本分支中也有生成许可的代码...』,代码地址:smart-license)
- 完成表单登记,上传 License 源文件
- 服务生成 License 后会自动触发浏览器下载:
License.shield
文件。
在你的工程中引入 smart-license 客户端依赖。
<dependency> <groupId>org.smartboot.license</groupId> <artifactId>license-client</artifactId> <version>2.0</version> </dependency>
载入 License(如若 License 已过期,则会触发过期回调。)
private void loadLicense(Properties properties) { 1️⃣ License license = new License(entity -> EnterprisePlugin.this.uninstall(),10); 2️⃣ try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("License.shield")) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; int size; while ((size = inputStream.read(bytes)) > 0) { byteArrayOutputStream.write(bytes, 0, size); } 3️⃣ LicenseEntity entity = license.loadLicense(byteArrayOutputStream.toByteArray()); 4️⃣ properties.load(new ByteArrayInputStream(entity.getData())); System.out.println(properties); } catch (IOException e) { throw new RuntimeException(e); } }
说明:
- 初始化 License 客户端。注册 license 过期后的回调逻辑,以及过期状态下的回调重复触发频率(单位:秒)。
- 加载 License 文件流。
- 解析 License 进行合法性校验,并获取授权内容。
- 基于授权内容进行软件运行时配置初始化。