Java加密解密class文件,使用classLoader動態解密class文件


前言

在平常開發中,可能會遇到要對系統中比較敏感的代碼進行保護,那麼下面就總結一下保護源碼的方法中最簡單的方式,即文件加密html

首先,加密和解密的大體思想是:加密無非就是對class文件進行異或一下,解密呢,那就是再對class文件異或回來便可。java

加密後的文件若是想要用到的話,就須要classLoader動態加載進來,具體實現請移步至:自定義ClassLoader動態加載Class文件tomcat

 

代碼實現

  1 /**
  2  * 加解密類
  3  */
  4 public class EdCipher {
  5 
  6     private String encryptFolder = "encrypt";
  7 
  8     /**
  9      * 加密方法
 10      * @param name 須要加密的文件名
 11      */
 12     public void encryptClass(String name) {
 13         String path = getFilePath(name);
 14         // classFile爲待加密的class文件
 15         File classFile = new File(path);
 16         if (!classFile.exists()) {
 17            // TODO 若是文件不存在,作相應的處理。通常狀況下都是拋出異常;
 18         } else {
 19            // folder 是準備在待加密的文件也就是classFIle的同級目錄下建立一個文件夾,裏面放着加密後的文件
 20             File folder = new File(classFile.getParent() + File.separator + encryptFolder);
 21             if (!folder.exists()) {
 22                 folder.mkdirs();
 23             }
 24         }
 25         // cipheredClass 爲加密後文件的全路徑文件名
 26         String cipheredClass = classFile.getParent() + File.separator + encryptFolder + File.separator + classFile.getName();
 27         try (
 28                 FileInputStream fileInputStream = new FileInputStream(classFile);
 29                 BufferedInputStream bis = new BufferedInputStream(fileInputStream);
 30                 FileOutputStream fileOutputStream = new FileOutputStream(cipheredClass);
 31                 BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream)
 32         ) {
 33             int data;
 34             while ((data = bis.read()) != -1) {
 35                 bos.write(data ^ 0xFF);
 36             }
 37             bos.flush();
 38         } catch (IOException e) {
 39             e.printStackTrace();
 40         }
 41 
 42         // 如今將原來未加密的文件刪除
 43         classFile.delete();
 44         
 45         //下面這一句在文件後面加了一個「en」,最後生成的文件就是xxx.classen,這樣作的目的是爲了在啓動服務器的時候
 46         //tomcat會自動檢查classespath下的class文件,若是我不加上一個「en」,那麼改加密文件就會被tomcat掃描到。
 47         //若是被掃描到了,可是它又是一個被加密後的文件,頭部信息被修改了,那麼tomcat就會報錯,啓動不起來。這算是一個小技巧。
 48         File oldFile = new File(path + "en");
 49         if (oldFile.exists()) {
 50             oldFile.delete();
 51         }
 52         File cipheredFile = new File(cipheredClass);
 53         cipheredFile.renameTo(oldFile);
 54         cipheredFile.getParentFile().delete();
 55     }
 56 
 57     /**
 58      * 解密方法
 59      * @param name 須要解密的文件名
 60      */
 61     protected byte[] decryptClass(String name) {
 62         String path;
 63         if (!name.contains(".class")) {
 64             path = getDefFilePath(name);
 65         } else {
 66             path = name;
 67         }
 68         File encryptedClassFile = new File(path);
 69         if (!encryptedClassFile.exists()) {
 70             System.out.println("decryptClass() File:" + path + " not found!");
 71             return null;
 72         }
 73         byte[] result = null;
 74         BufferedInputStream bis = null;
 75         ByteArrayOutputStream bos = null;
 76         try {
 77             bis = new BufferedInputStream(new FileInputStream(encryptedClassFile));
 78             bos = new ByteArrayOutputStream();
 79             int data;
 80             while ((data = bis.read()) != -1) {
 81                 bos.write(data ^ 0xFF);
 82             }
 83             bos.flush();
 84             result = bos.toByteArray();
 85         } catch (Exception e) {
 86             e.printStackTrace();
 87         } finally {
 88             try {
 89                 if (bis != null) {
 90                     bis.close();
 91                 }
 92                 if (bos != null) {
 93                     bos.close();
 94                 }
 95             } catch (IOException e) {
 96                 e.printStackTrace();
 97             }
 98         }
 99         return result;
100     }
101 
102    //獲取加密前文件的絕對路徑
103     private String getFilePath(String name) {
104         String path;
105         String str = name.substring(name.lastIndexOf(".") + 1, name.length()) + ".class";
106         path = EdCipher.class.getResource(str).toString();
107         path = path.substring(path.indexOf("file:/") + "file:/".length(), path.length());
108         if (System.getProperty("os.name").toUpperCase().contains("LINUX")) {
109             path = File.separator + path;
110         }
111         return path;
112     }
113 
114    //獲取加密後文件的絕對路徑 
115     private String getDefFilePath(String name) {
116         String path;
117         String str = name.substring(name.lastIndexOf(".") + 1, name.length()) + ".classen";
118         path = EdCipher.class.getResource(str).toString();
119         path = path.substring(path.indexOf("file:/") + "file:/".length(), path.length());
120         return path;
121     }
122 
123    // 測試
124     public static void main(String[] args) {
125         EdCipher edCipher = new EdCipher();
126         edCipher.encryptClass(args[0]);
127     }
128 }

 

若是要想在Ant打包的時候,就加密文件,就須要在build.xml配置文件中調用該類的Main方法便可

1 <!-- 加密 -->
2 <target name="encrypt">
3     <java classname="EdCipher" failonerror="true">
4         <classpath refid="classpath.run"/>
5         <arg line="須要加密的文件的包名+文件名"/>
6     </java>
7 </target>
相關文章
相關標籤/搜索