Java加密解密class文件,使用classLoader动态解密class文件

Posted 鲸落

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java加密解密class文件,使用classLoader动态解密class文件相关的知识,希望对你有一定的参考价值。


前言

在日常开发中,可能会遇到要对系统中比较敏感的代码进行保护,那么下面就总结一下保护源码的方法中最简单的方式,即文件加密

首先,加密和解密的大致思想是:加密无非就是对class文件进行异或一下,解密呢,那就是再对class文件异或回来即可。

加密后的文件如果想要用到的话,就需要classLoader动态加载进来,具体实现请移步至:自定义ClassLoader动态加载Class文件

 

代码实现

  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>

 

以上是关于Java加密解密class文件,使用classLoader动态解密class文件的主要内容,如果未能解决你的问题,请参考以下文章

JAVA虚拟机系列三-类加载过程双亲委派模型对象实例化过程

spring总结

Java类加载器及Android类加载器基础

Java实现自定义classLoader动态解密class文件

解密Java虚拟机如何加载一个Class文件

Java Class 加密工具 ClassFinal