wisdomisite-java/src/main/java/com/zhgd/xmgl/util/XjarEncryUtil.java
2024-04-14 21:05:01 +08:00

283 lines
12 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.zhgd.xmgl.util;
import io.xjar.XCryptos;
import io.xjar.XKit;
import io.xjar.boot.XBoot;
import io.xjar.key.XKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @desc:xjar 加密工具针对java开发项目jar包进行加密jar加密后大小会翻倍同时swagger无法访问接口暂时未发现问题
* @author: wangsh
* @time: 2021/4/15 9:34
*/
@Slf4j
public class XjarEncryUtil {
public static void main(String[] args) {
createJFrame();
}
/**
* 创建面板,这个类似于 HTML 的 div 标签,我们可以创建多个面板并在 JFrame 中指定位置,面板中我们可以添加文本字段,按钮及其他组件。
*/
public static void createJFrame() {
// 创建 JFrame 实例
JFrame frame = new JFrame("XJar加密防止反编译");
// 设置窗口大小
frame.setSize(600, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//创建面板,这个类似于 HTML 的 div 标签,可以创建多个面板并在 JFrame 中指定位置,
// 面板中可以添加文本字段,按钮及其他组件。
JPanel panel = new JPanel();
// 添加面板
frame.add(panel);
//调用用户定义的方法并添加组件到面板
addComponents(panel);
// 设置界面可见
frame.setVisible(true);
}
/**
* 调用用户定义的方法并添加组件到面板
*/
private static void addComponents(JPanel panel) {
//布局部分我们这边不多做介绍,这边设置布局为 null
panel.setLayout(null);
// 创建 需要加密的jar JLabel
JLabel fromLabel = new JLabel("选择加密的jar");
fromLabel.setBounds(10, 20, 120, 30);
panel.add(fromLabel);
//用于记录未加密jar的文本域
final JTextField fromText = new JTextField(20);
fromText.setBounds(100, 20, 300, 30);
panel.add(fromText);
// 创建选择按钮
JButton fromButton = new JButton("选择");
fromButton.setBounds(420, 20, 80, 30);
panel.add(fromButton);
// 加密后jar要保存的位置
JLabel toLabel = new JLabel("选择保存位置:");
toLabel.setBounds(10, 50, 120, 30);
panel.add(toLabel);
//文本域用于记录保存路径
final JTextField toText = new JTextField(20);
toText.setBounds(100, 50, 300, 30);
panel.add(toText);
// 创建选择按钮
JButton toButton = new JButton("选择");
toButton.setBounds(420, 50, 80, 30);
panel.add(toButton);
// 输入密码的文本域
JLabel passwordLabel = new JLabel("加密密码:");
passwordLabel.setBounds(10, 80, 80, 30);
panel.add(passwordLabel);
//这个类似用于输入的文本域,但是输入的信息会以点号代替,用于包含密码的安全性
final JPasswordField passwordText = new JPasswordField(20);
passwordText.setBounds(100, 80, 300, 30);
panel.add(passwordText);
// 创建开始按钮
JButton startButton = new JButton("加密");
startButton.setBounds(100, 110, 80, 30);
panel.add(startButton);
// 创建开始按钮
JButton endButton = new JButton("解密");
endButton.setBounds(200, 110, 80, 30);
panel.add(endButton);
//日志显示框
final JTextArea textArea = new JTextArea("");
textArea.setBounds(10, 150, 550, 150);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
panel.add(textArea);
//选择jar按钮监听事件
fromButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { //按钮点击事件
JFileChooser chooser = new JFileChooser(); //设置选择器
chooser.setMultiSelectionEnabled(false); //设为单选
int returnVal = chooser.showOpenDialog(null); //是否打开文件选择框
if (returnVal == JFileChooser.APPROVE_OPTION) { //如果符合文件类型
String filepath = chooser.getSelectedFile().getAbsolutePath(); //获取绝对路径
if (!".jar".equals(filepath.substring(filepath.length() - 4))) {
JOptionPane.showMessageDialog(null, "文件格式不正确请选择jar文件", "文件格式错误", JOptionPane.ERROR_MESSAGE);
} else {
fromText.setText(filepath);
}
log.info(filepath);
}
}
});
//选择加密后jar保存路径按钮监听事件
toButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { //按钮点击事件
JFileChooser chooser = new JFileChooser(); //设置选择器
chooser.setMultiSelectionEnabled(false); //设为单选
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); //设置只选目录
chooser.setDialogTitle("选择加密后jar保存位置");
int returnVal = chooser.showOpenDialog(null); //是否打开文件选择框
if (returnVal == JFileChooser.APPROVE_OPTION) { //如果符合文件类型
String filepath = chooser.getSelectedFile().getAbsolutePath(); //获取绝对路径
toText.setText(filepath);
log.info(filepath);
}
}
});
//选择开始径按钮的监听事件
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String fromJarPath = fromText.getText();
String toJarPath = toText.getText() + "\\encrypt" + getNowDateTime() + ".jar";
String password = new String(passwordText.getPassword());
log.info("fromJarPath=" + fromJarPath);
log.info("toJarPath=" + toJarPath);
log.info("password=" + password);
if (StringUtils.isEmpty(fromJarPath)) {
JOptionPane.showMessageDialog(null, "jar文件不能为空", "jar文件不能为空", JOptionPane.ERROR_MESSAGE);
return;
}
if (StringUtils.isEmpty(toJarPath)) {
JOptionPane.showMessageDialog(null, "保存路径不能为空!", "保存路径不能为空!", JOptionPane.ERROR_MESSAGE);
return;
}
if (StringUtils.isEmpty(toJarPath)) {
JOptionPane.showMessageDialog(null, "请输入加密的密码!", "密码不能为空!", JOptionPane.ERROR_MESSAGE);
return;
}
//打印输入日志
StringBuilder builder = new StringBuilder();
builder.append("fromJarPath=" + fromJarPath + "\n");
builder.append("toJarPath=" + toJarPath + "\n");
textArea.setText(builder.toString());
//开始加密文件
encryptJar(fromJarPath, toJarPath, password);
textArea.append("jar加密成功\n请测试接口是否正常注意Swagger不可用");
}
});
//选择开始径按钮的监听事件
endButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String fromJarPath = fromText.getText();
String toJarPath = toText.getText() + "\\encrypt" + getNowDateTime() + ".jar";
String password = new String(passwordText.getPassword());
log.info("fromJarPath=" + fromJarPath);
log.info("toJarPath=" + toJarPath);
log.info("password=" + password);
if (StringUtils.isEmpty(fromJarPath)) {
JOptionPane.showMessageDialog(null, "jar文件不能为空", "jar文件不能为空", JOptionPane.ERROR_MESSAGE);
return;
}
if (StringUtils.isEmpty(toJarPath)) {
JOptionPane.showMessageDialog(null, "保存路径不能为空!", "保存路径不能为空!", JOptionPane.ERROR_MESSAGE);
return;
}
if (StringUtils.isEmpty(toJarPath)) {
JOptionPane.showMessageDialog(null, "请输入加密的密码!", "密码不能为空!", JOptionPane.ERROR_MESSAGE);
return;
}
//打印输入日志
StringBuilder builder = new StringBuilder();
builder.append("fromJarPath=" + fromJarPath + "\n");
builder.append("toJarPath=" + toJarPath + "\n");
textArea.setText(builder.toString());
//开始加密文件
decryptJar(fromJarPath, toJarPath, password);
textArea.append("jar加密成功\n请测试接口是否正常注意Swagger不可用");
}
});
}
/**
* 获取当前格式化时间的方法
*/
private static String getNowDateTime() {
String dateNow = "";
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = new Date();
dateNow = format.format(date);
return dateNow;
}
/**
* jar包加密防止反编译
* 此编译方式在运行jar包时需要输入密码
* 运行方式一
* // 命令行运行JAR 然后在提示输入密码的时候输入密码后按回车即可正常启动
* java -jar /path/to/encrypted.jar
* 运行方式二:
* // 也可以通过传参的方式直接启动,不太推荐这种方式,因为泄露的可能性更大!
* java -jar /path/to/encrypted.jar --xjar.password=PASSWORD
* 运行方式三:
* // 对于 nohup 或 javaw 这种后台启动方式,无法使用控制台来输入密码,推荐使用指定密钥文件的方式启动
* nohup java -jar /path/to/encrypted.jar --xjar.keyfile=/path/to/xjar.key
* xjar.key 文件说明:
* 格式:
* password: PASSWORD
* algorithm: ALGORITHM
* keysize: KEYSIZE
* ivsize: IVSIZE
* hold: HOLD
* 参数说明:
* password 密码 无 密码字符串
* algorithm 密钥算法 AES 支持JDK所有内置算法如AES / DES ...
* keysize 密钥长度 128 根据不同的算法选取不同的密钥长度。
* ivsize 向量长度 128 根据不同的算法选取不同的向量长度。
* hold 是否保留 false 读取后是否保留密钥文件。
*
* @param fromJarPath 需要加密的jar
* @param toJarPath 加密后的jar
* @param password 加密密码
*/
public static void encryptJar(String fromJarPath, String toJarPath, String password) {
try {
XCryptos.encryption()
.from(fromJarPath)
.use(password)
.include("/com/**/*")
.to(toJarPath);
} catch (Exception e) {
log.error("error", e);
}
}
/**
* jar包解密
*
* @param fromJarPath 已通过Xjar加密的jar文件路径
* @param toJarPath 解密后的jar文件
* @param password 密码
*/
public static void decryptJar(String fromJarPath, String toJarPath, String password) {
try {
XKey xKey = XKit.key(password);
XBoot.decrypt(fromJarPath, toJarPath, xKey);
} catch (Exception e) {
log.error("error", e);
}
}
}