package net.roseboy.classfinal;
import javassist.ClassPool;
import javassist.NotFoundException;
import net.roseboy.classfinal.util.*;
import java.io.File;
import java.util.*;
/**
* java class加密
*
* @author roseboy
*/
public class JarEncryptor {
//加密配置文件:加载配置文件是注入解密代码的配置
static Map<String, String> aopMap = new HashMap<>();
static {
//org.springframework.core.io.ClassPathResource#getInputStream注入解密功能
aopMap.put("spring.class", "org.springframework.core.io.ClassPathResource#getInputStream");
aopMap.put("spring.code", "char[] c=${passchar};"
+ "is=net.roseboy.classfinal.JarDecryptor.getInstance().decryptConfigFile(this.path,is,c);");
aopMap.put("spring.line", "999");
//com.jfinal.kit.Prop#getInputStream注入解密功能
aopMap.put("jfinal.class", "com.jfinal.kit.Prop#<Prop>(java.lang.String,java.lang.String)");
aopMap.put("jfinal.code", "char[] c=${passchar};inputStream=net.roseboy.classfinal.JarDecryptor.getInstance().decryptConfigFile(fileName,inputStream,c);");
aopMap.put("jfinal.line", "62");
}
//要加密的jar或war
private String jarPath = null;
//要加密的包,多个用逗号隔开
private List<String> packages = null;
//-INF/lib下要加密的jar
private List<String> includeJars = null;
//排除的类名
private List<String> excludeClass = null;
//依赖jar路径
private List<String> classPath = null;
//需要加密的配置文件
private List<String> cfgfiles = null;
//密码
private char[] password = null;
//机器码
private char[] code = null;
//jar还是war
private String jarOrWar = null;
//工作目录
private File targetDir = null;
//-INF/lib目录
private File targetLibDir = null;
//-INF/classes目录
private File targetClassesDir = null;
//加密的文件数量
private Integer encryptFileCount = null;
//存储解析出来的类名和路径
private Map<String, String> resolveClassName = new HashMap<>();
/**
* 构造方法
*
* @param jarPath 要加密的jar或war
* @param password 密码
*/
public JarEncryptor(String jarPath, char[] password) {
super();
this.jarPath = jarPath;
this.password = password;
}
/**
* 加密jar的主要过程
*
* @return 解密后生成的文件的绝对路径
*/
public String doEncryptJar() {
if (!jarPath.endsWith(".jar") && !jarPath.endsWith(".war")) {
throw new RuntimeException("jar/war文件格式有误");
}
if (!new File(jarPath).exists()) {
throw new RuntimeException("文件不存在:" + jarPath);
}
if (password == null || password.length == 0) {
throw new RuntimeException("密码不能为空");
}
if (password.length == 1 && password[0] == '#') {
Log.debug("加密模式:无密码");
}
Log.debug("机器绑定:" + (StrUtils.isEmpty(this.code) ? "否" : "是"));
this.jarOrWar = jarPath.substring(jarPath.lastIndexOf(".") + 1);
Log.debug("加密类型:" + jarOrWar);
//临时work目录
this.targetDir = new File(jarPath.replace("." + jarOrWar, Const.LIB_JAR_DIR));
this.targetLibDir = new File(this.targetDir, ("jar".equals(jarOrWar) ? "BOOT-INF" : "WEB-INF")
+ File.separator + "lib");
this.targetClassesDir = new File(this.targetDir, ("jar".equals(jarOrWar) ? "BOOT-INF" : "WEB-INF")
+ File.separator + "classes");
Log.debug("临时目录:" + targetDir);
//[1]释放所有文件
List<String> allFile = JarUtils.unJar(jarPath, this.targetDir.getAbsolutePath());
allFile.forEach(s -> Log.debug("释放:" + s));
//[1.1]内部jar只释放需要加密的jar
List<String> libJarFiles = new ArrayList<>();
allFile.forEach(path -> {
if (!path.toLowerCase().endsWith(".jar")) {
return;
}
String name = path.substring(path.lastIndexOf(File.separator) + 1);
if (StrUtils.isMatchs(this.includeJars, name, false)) {
String targetPath = path.substring(0, path.length() - 4) + Const.LIB_JAR_DIR;
List<String> files = JarUtils.unJar(path, targetPath);
files.forEach(s -> Log.debug("释放:" + s));
libJarFiles.add(path);
libJarFiles.addAll(files);
}
});
allFile.addAll(libJarFiles);
//压缩静态文件
// allFile.forEach(s -> {
// if (!s.endsWith(".ftl")) {
// return;
// }
// File file = new File(s);
// String code = IoUtils.readTxtFile(file);
// code = HtmlUtils.removeComments(code);
// code = HtmlUtils.removeBlankLine(code);
// IoUtils.writeTxtFile(file, code);
// });
//[2]提取所有需要加密的class文件
List<File> classFiles = filterClasses(allFile);
//[3]将本项目的代码添加至jar中
addClassFinalAgent();
//[4]将正常的class加密,压缩另存
List<String> encryptClass = encryptClass(classFiles);
this.encryptFileCount = encryptClass.size();
//[5]清空class方法体,并保存文件
clearClassMethod(classFiles);
//[6]加密配置文件
encryptConfigFile();
//[7]打包回去
String result = packageJar(libJarFiles);
return result;
}
/**
* 找出所有需要加密的class文件
*
* @param allFile 所有文件
* @return 待加密的class列表
*/
public List<File> filterClasses(List<String> allFile) {
List<File> classFiles = new ArrayList<>();
allFile.forEach(file -> {
if (!file.endsWith(".class")) {
return;
}
//解析出类全名
String className = resolveClassName(file, true);
//判断包名相同和是否排除的类
if (StrUtils.isMatchs(this.packages, className, false)
&& !StrUtils.isMatchs(this.excludeClass, className, false)) {
classFiles.add(new File(file));
Log.debug("待加密: " + file);
}
});
return classFiles;
}
/**
* 加密class文件,放在META-INF/classes里
*
* @param classFiles jar/war 下需要加密的class文件
* @return 已经加密的类名
*/
private List<String> encryptClass(List<File> classFiles) {
List<String> encryptClasses = new ArrayList<>();
//加密后存储的位置
File metaDir = new File(this.targetDir, "META-INF" + File.separator + Const.FILE_NAME);
if (!metaDir.exists()) {
metaDir.mkdirs();
}
//无密码模式,自动生成一个密码
if (this.password.length == 1 && this.password[0] == '#') {
char[] randChars = EncryptUtils.randChar(32);
this.password = EncryptUtils.md5(randChars);
File configPass = new File(metaDir, Const.CONFIG_PASS);
IoUtils.writeFile(configPass, StrUtils.toBytes(randChars));
}
//有机器码
if (StrUtils.isNotEmpty(this.code)) {
File configCode = new File(metaDir, Const.CONFIG_CODE);
IoUtils.writeFile(configCode, StrUtils.toBytes(EncryptUtils.md5(this.code)));
}
//加密另存
classFiles.forEach(classFile -> {
String className = classFile.getName();
if (className.endsWith(".class")) {
className = resolveClassName(classFile.getAbsolutePath(), true);
}
byte[] bytes = IoUtils.readFileToByte(classFile);
char[] pass =
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
classfinal-master.zip (39个子文件)
classfinal-master
classfinal-web
pom.xml 2KB
src
main
resources
templates
index.ftl 3KB
static
js
jQuery.time.js 2KB
jquery.easing.min.js 5KB
jquery-1.9.1.min.js 90KB
pattern.png 25KB
css
css.css 2KB
application.yml 407B
logback-spring.xml 693B
java
net
roseboy
classfinal
Application.java 2KB
web
MainController.java 390B
.gitignore 213B
pom.xml 2KB
LICENSE 11KB
classfinal-core
pom.xml 1KB
src
main
java
net
roseboy
classfinal
InputForm.java 3KB
AgentTransformer.java 1KB
CoreAgent.java 5KB
Const.java 3KB
JarDecryptor.java 4KB
JarEncryptor.java 19KB
util
CmdLineOption.java 5KB
Log.java 990B
HtmlUtils.java 7KB
ClassUtils.java 7KB
IoUtils.java 6KB
SysUtils.java 6KB
EncryptUtils.java 12KB
JarUtils.java 9KB
StrUtils.java 6KB
.gitignore 213B
classfinal-maven-plugin
pom.xml 2KB
src
main
java
net
roseboy
classfinal
plugin
ClassFinalPlugin.java 3KB
.gitignore 213B
classfinal-fatjar
pom.xml 3KB
src
main
java
net
roseboy
classfinal
Agent.java 501B
Main.java 7KB
.gitignore 213B
.gitignore 213B
共 39 条
- 1
资源评论
Java程序员-张凯
- 粉丝: 1w+
- 资源: 6656
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功