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>