为了企业的代码的安全,可以在打包之前将类文件加密之后,打包成相关的文件,在加载时,获取类文件信息,并解密加载到JVM中。
关于实现的代码如下:
package com.easyway.space.commons.classloaders.security;
import static com.easyway.space.commons.classloaders.security.CommonSpaceConstant.SECURITY_KEY_FILE_LOCATION_KEY;
import static com.easyway.space.commons.classloaders.security.CommonSpaceConstant.SYSTEMCONFIG_FILE_LOCATION;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
/**
*
* 类安全加载工具类
* @author longgangbai
*
*/
public class ClassSecurityUtils {
public static Logger logger=Logger.getLogger(ClassSecurityUtils.class);
public static String SECURITY_KEY_FILE_LOCATION;
static{
SECURITY_KEY_FILE_LOCATION =PropertiesUtils.getProperties(SYSTEMCONFIG_FILE_LOCATION).getProperty(SECURITY_KEY_FILE_LOCATION_KEY);
}
/**
* 将客户端的jar文件通过循环依次加密
* @param clazzPath 类文件路径
* @throws Exception
*/
public static void cryptClass(String clazzPath) throws Exception {
//获取密钥信息
FileInputStream fi = new FileInputStream(new File(SECURITY_KEY_FILE_LOCATION));
byte rawKeyData[]=IOUtils.toByteArray(fi);
//创建加密的对象
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(rawKeyData);
SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key, sr);
//获取class文件加密前的信息
File clazzFile=new File(clazzPath);
FileInputStream fi2 = new FileInputStream(clazzFile);
byte data[] = IOUtils.toByteArray(fi2);
//获取加密之后的信息并写入文件
byte encryptedData[] = cipher.doFinal(data);
FileOutputStream fo = new FileOutputStream(clazzFile);
IOUtils.write(encryptedData, fo);
}
/**
*
* 用于解析加密过的class文件的并加载到JVM中
* @param filepath 密钥文件的路径
* @param clazzPath 需要解密的classpath文件的路径
* @param clazzLoader 相应的类加载器
* @throws InvalidKeyException
* @throws InvalidKeySpecException
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws ClassNotFoundException
*/
public static void decryptClass(String filepath,String clazzPath,CustomerClassLoader clazzLoader) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, ClassNotFoundException{
//获取密钥文件的信息
File file=new File(filepath);
//获取Class 文件的信息
File clazzFile=new File(clazzPath);
if(file.exists()){
try {
//获取密钥的信息
byte rawKeyData[] = FileUtils.readFileToByteArray(file);
//设置安全算法的密钥
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(rawKeyData);
//采用DES加密的算法
SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES");
//初始化密钥对象
cipher.init(Cipher.DECRYPT_MODE, key, sr);
if(clazzFile.exists())
{
//获取加密之前的文件的信息
byte rawEncryptedClassData[] = FileUtils.readFileToByteArray(clazzFile);
//解密加密文件的信息
byte decryptedClazzData[] = cipher.doFinal(rawEncryptedClassData);
//通过类加载器加载类到JVM中
String className=clazzFile.getName();
clazzLoader.loadClass(decryptedClazzData, className);
}
} catch (IOException e) {
logger.error("解析加载文件"+clazzFile.getName(), e);
}
}
}
}