在日常开发中,可能会遇到要对系统中比较敏感的代码进行保护,那么下面就总结一下保护源码的方法中最简单的方式,即文件加密
首先,加密和解密的大致思想是:加密无非就是对class文件进行异或一下,解密呢,那就是再对class文件异或回来即可。
加密后的文件如果想要用到的话,就需要classLoader动态加载进来,具体实现请移步至:https://blog.csdn.net/qq_28082757/article/details/81481981
/**
* 加解密类
*/
public class EdCipher {
private String encryptFolder = "encrypt";
/**
* 加密方法
* @param name 需要加密的文件名
*/
public void encryptClass(String name) {
String path = getFilePath(name);
// classFile为待加密的class文件
File classFile = new File(path);
if (!classFile.exists()) {
// TODO 如果文件不存在,做相应的处理。一般情况下都是抛出异常;
} else {
// folder 是准备在待加密的文件也就是classFIle的同级目录下创建一个文件夹,里面放着加密后的文件
File folder = new File(classFile.getParent() + File.separator + encryptFolder);
if (!folder.exists()) {
folder.mkdirs();
}
}
// cipheredClass 为加密后文件的全路径文件名
String cipheredClass = classFile.getParent() + File.separator + encryptFolder + File.separator + classFile.getName();
try (
FileInputStream fileInputStream = new FileInputStream(classFile);
BufferedInputStream bis = new BufferedInputStream(fileInputStream);
FileOutputStream fileOutputStream = new FileOutputStream(cipheredClass);
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream)
) {
int data;
while ((data = bis.read()) != -1) {
bos.write(data ^ 0xFF);
}
bos.flush();
} catch (IOException e) {
e.printStackTrace();
}
// 现在将原来未加密的文件删除
classFile.delete();
// 这里在文件后面加了一个“en”,最后生成的文件就是xxx.classen,这样做的目的是为了在启动服务器的时候,tomcat会自动检查classespath下的class文件,如果我不加上一个“en”,那么改加密文件就会被tomcat扫描到。如果被扫描到了,但是它又是一个被加密后的文件,头部信息被修改了,那么tomcat就会报错,启动不起来。这算是一个小技巧。
File oldFile = new File(path + "en");
if (oldFile.exists()) {
oldFile.delete();
}
File cipheredFile = new File(cipheredClass);
cipheredFile.renameTo(oldFile);
cipheredFile.getParentFile().delete();
}
/**
* 解密方法
* @param name 需要解密的文件名
*/
protected byte[] decryptClass(String name) {
String path;
if (!name.contains(".class")) {
path = getDefFilePath(name);
} else {
path = name;
}
File encryptedClassFile = new File(path);
if (!encryptedClassFile.exists()) {
System.out.println("decryptClass() File:" + path + " not found!");
return null;
}
byte[] result = null;
BufferedInputStream bis = null;
ByteArrayOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream(encryptedClassFile));
bos = new ByteArrayOutputStream();
int data;
while ((data = bis.read()) != -1) {
bos.write(data ^ 0xFF);
}
bos.flush();
result = bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bis != null) {
bis.close();
}
if (bos != null) {
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
//获取加密前文件的绝对路径
private String getFilePath(String name) {
String path;
String str = name.substring(name.lastIndexOf(".") + 1, name.length()) + ".class";
path = EdCipher.class.getResource(str).toString();
path = path.substring(path.indexOf("file:/") + "file:/".length(), path.length());
if (System.getProperty("os.name").toUpperCase().contains("LINUX")) {
path = File.separator + path;
}
return path;
}
//获取加密后文件的绝对路径
private String getDefFilePath(String name) {
String path;
String str = name.substring(name.lastIndexOf(".") + 1, name.length()) + ".classen";
path = EdCipher.class.getResource(str).toString();
path = path.substring(path.indexOf("file:/") + "file:/".length(), path.length());
return path;
}
// 测试
public static void main(String[] args) {
EdCipher edCipher = new EdCipher();
edCipher.encryptClass(args[0]);
}
}
如果要想在Ant打包的时候,就加密文件,就需要在build.xml配置文件中调用该类的Main方法即可;
<!-- 加密 -->
<target name="encrypt">
<java classname="EdCipher" failonerror="true">
<classpath refid="classpath.run"/>
<arg line="需要加密的文件的包名+文件名"/>
</java>
</target>
踏实一些,不要着急,你想要的,岁月都会给你。