軟件簡介
XJar — Spring-Boot JAR 包加密運行工具,避免源碼泄露以及反編譯。
Spring Boot JAR安全加密運行工具,同時支持原生的JAR。
基於對JAR包內資源的加密以及拓展ClassLoader來構建的一套程序加密啟動,動態解密運行的方案,避免源碼泄露或反編譯。
功能特性
-
無需侵入代碼,只需要把編譯好的JAR包通過工具加密即可。
-
完全內存解密,杜絕源碼以及字節碼泄露以及反編譯。
-
支持所有JDK內置加解密算法。
-
可選擇需要加解密的字節碼或其他資源文件,避免計算資源浪費。
環境依賴-廢話不多說,直接上源碼。新建項目
配置pom
<?xml version="1.0" encoding="UTF-8"?> <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> <groupId>com</groupId> <artifactId>xjar-encrype</artifactId> <version>1.0-SNAPSHOT</version> <!-- 設置 jitpack.io 倉庫 --> <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>v2.0.6</version> </dependency> </dependencies> </project>
寫代碼
import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.SimpleDateFormat; import java.util.Date; import static io.xjar.agent.hibernate.XjarTest.encryptJarDangerMode; public class UserSwing { public static void main(String[] args) { // 創建 JFrame 實例 JFrame frame = new JFrame("Jar加密,防止反編譯"); // Setting the width and height of frame frame.setSize(600, 400); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); /* 創建面板,這個類似於 HTML 的 div 標簽 * 我們可以創建多個面板並在 JFrame 中指定位置 * 面板中我們可以添加文本字段,按鈕及其他組件。 */ JPanel panel = new JPanel(); // 添加面板 frame.add(panel); /* * 調用用戶定義的方法並添加組件到面板 */ placeComponents(panel); // 設置界面可見 frame.setVisible(true); } private static void placeComponents(final JPanel panel) { /* 布局部分我們這邊不多做介紹 * 這邊設置布局為 null */ panel.setLayout(null); // 創建 需要加密的jar JLabel JLabel fromLabel = new JLabel("選擇需要加密的jar:"); fromLabel.setBounds(10,20,120,25); panel.add(fromLabel); /* * 用於記錄未加密jar的文本域 */ final JTextField fromText = new JTextField(20); fromText.setBounds(140,20,210,25); panel.add(fromText); // 創建選擇按鈕 JButton fromButton = new JButton("選擇..."); fromButton.setBounds(360, 20, 80, 25); panel.add(fromButton); // 加密后jar要保存的位置 JLabel toLabel = new JLabel("選擇需要保存的位置"); toLabel.setBounds(10,50,120,25); panel.add(toLabel); /* *文本域用於記錄保存路徑 */ final JTextField toText = new JTextField(20); toText.setBounds(140,50,210,25); panel.add(toText); // 創建選擇按鈕 JButton toButton = new JButton("選擇..."); toButton.setBounds(360, 50, 80, 25); panel.add(toButton); // 輸入密碼的文本域 JLabel passwordLabel = new JLabel("加密密碼:"); passwordLabel.setBounds(10,80,80,25); panel.add(passwordLabel); /* * 這個類似用於輸入的文本域 * 但是輸入的信息會以點號代替,用於包含密碼的安全性 */ final JPasswordField passwordText = new JPasswordField(20); passwordText.setBounds(100,80,165,25); panel.add(passwordText); // 創建登錄按鈕 JButton startButton = new JButton("開始"); startButton.setBounds(10, 110, 80, 25); panel.add(startButton); //日志顯示框 final JTextArea textArea = new JTextArea(""); textArea.setBounds(10,150,300,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); } System.out.println(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); System.out.println(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()); System.out.println("fromJarPath=" + fromJarPath); System.out.println("toJarPath=" + toJarPath); System.out.println("password=" + password); if (fromJarPath != null && !"".equals(fromJarPath)) { if (toJarPath != null && !"\\encrypt".equals(toJarPath.substring(0,8))) { if (password != null && !"".equals(password)) { //打印輸入日志 StringBuilder builder = new StringBuilder(); builder.append("fromJarPath=" + fromJarPath + "\n") .append("toJarPath=" + toJarPath + "\n") ; textArea.setText(builder.toString()); //開始加密文件 encryptJarDangerMode(fromJarPath,toJarPath,password); textArea.append("jar加密成功!\n請測試接口是否正常(注意:Swagger不可用)"); } else { JOptionPane.showMessageDialog(null, "請輸入加密的密碼!", "密碼不能為空!", JOptionPane.ERROR_MESSAGE); } } else { JOptionPane.showMessageDialog(null, "保存路徑不能為空!", "保存路徑不能為空!", JOptionPane.ERROR_MESSAGE); } } else { JOptionPane.showMessageDialog(null, "jar文件不能為空!", "jar文件不能為空!", JOptionPane.ERROR_MESSAGE); } } }); } /** * 獲取當前格式化時間的方法 * @return */ private static String getNowDateTime() { String dateNow = ""; SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); Date date = new Date(); dateNow = format.format(date); return dateNow; } }
直接將項目main運行 如下圖
當然還有直接了當的方法哦
import io.xjar.XConstants; import io.xjar.XKit; import io.xjar.boot.XBoot; import io.xjar.key.XKey; /** * @description jar包加密 * jar加密后,大小會翻倍,同時swagger無法訪問,接口暫時未發現問題 */ public class XjarTest { public static void main(String[] args) { // Spring-Boot Jar包加密 String password = "adas"; String fromJarPath = "F:\\old-0.0.1-SNAPSHOT.jar"; String toJarPath = "F:\\new.jar"; encryptJarDangerMode(fromJarPath, toJarPath, password); } /** * 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 { // Spring-Boot Jar包加密 XKey xKey = XKit.key(password); XBoot.encrypt(fromJarPath, toJarPath, xKey); } catch (Exception e) { e.printStackTrace(); } } /** * 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) { e.printStackTrace(); } } /** * jar包危險加密模式 * 即不需要輸入密碼即可啟動的加密方式,這種方式META-INF/MANIFEST.MF中會保留密鑰,請謹慎使用! * @param fromJarPath 需要加密的jar * @param toJarPath 加密后的jar * @param password 加密密碼 */ public static void encryptJarDangerMode(String fromJarPath, String toJarPath, String password) { try { XKey xKey = XKit.key(password); XBoot.encrypt(fromJarPath, toJarPath, xKey, XConstants.MODE_DANGER); } catch (Exception e) { e.printStackTrace(); } } }
jar包下載不下來可配置maven私服
<mirror> <id>alimaven</id> <mirrorOf>central,!jitpack.io</mirrorOf> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> </mirror>
一個命令解決maven依賴下載失敗后無法重新下載依賴的問題-請到本地maven下執行該cmd命令
for /r %i in (*.lastUpdated) do del %i
剩下的你懂的哦~
請一鍵三連···