class由于可以进行反编译,这样对某个核心的模块来说,会造成关键技术的泄漏。如何对class类进行加密,是某些公司会考虑的问题。
以下公布一个实际的类。实现了一个ClassLoader,可以直接操作加密后的class文件。
其中的加密方式是采用DES加密。当然类需要先进行加密。ClassLoader做的是一个加载类前的解密工作。
public class Start extends ClassLoader
{
// 这些对象在构造函数中设置,
// 以后loadClass()方法将利用它们解密类
private SecretKey key;
private Cipher cipher;
private static Start instance = null ;
protected Start() {
super() ;
}
// 构造函数:设置解密所需要的对象
private Start( SecretKey key ) throws GeneralSecurityException,
IOException {
this.key = key;
String algorithm = "DES";
SecureRandom sr = new SecureRandom();
// System.err.println( "[Start: creating cipher]" );
cipher = Cipher.getInstance( algorithm );
cipher.init( Cipher.DECRYPT_MODE, key, sr );
}
// main过程:我们要在这里读入密匙,创建Start的
// 实例,它就是我们的定制ClassLoader。
// 设置好ClassLoader以后,我们用它装入应用实例,
// 最后,我们通过Java Reflection API调用应用实例的main方法
static public void main( String args[] ) throws Exception {
String keyFilename = args[0];
String appName = args[1];
// 这些是传递给应用本身的参数
String realArgs[] = new String[args.length-2];
System.arraycopy( args, 2, realArgs, 0, args.length-2 );
// 读取密匙
// System.err.println( "[Start: reading key]" );
byte rawKey[] = getCodeByte(keyFilename);
DESKeySpec dks = new DESKeySpec( rawKey );
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance( "DES" );
SecretKey key = keyFactory.generateSecret( dks );
// 创建解密的ClassLoader
instance = new Start( key );
// 创建应用主类的一个实例
// 通过ClassLoader装入它
// System.err.println( "[Start: loading "+appName+"]" );
Class clasz = instance.loadClass( appName );
// 最后,通过Reflection API调用应用实例
// 的main()方法
// 获取一个对main()的引用
String proto[] = new String[1];
Class mainArgs[] = { (new String[1]).getClass() };
Method main = clasz.getMethod( "main", mainArgs );
// 创建一个包含main()方法参数的数组
Object argsArray[] = { realArgs };
// System.err.println( "[Start: running "+appName+".main()]" );
// 调用main()
main.invoke( null, argsArray );
}
public static Start getInstance() {
return instance ;
}
public Class loadClass( String name, boolean resolve )
throws ClassNotFoundException {
try {
// 我们要创建的Class对象
Class clasz = null;
// 必需的步骤1:如果类已经在系统缓冲之中
// 我们不必再次装入它
clasz = findLoadedClass( name );
if (clasz != null)
return clasz;
// 下面是定制部分
try {
byte classData[];
// try {
// // 读取经过加密的类文件
// classData = readClassFile(name);
// } catch (Exception e) {
// try {
// classData = readZipFile(name) ;
// } catch (Exception e) {
// classData = readClassFile(name);
// }
// }
classData = readFromURL(name) ;
if (classData != null) {
// 解密...
byte decryptedClassData[] = cipher.doFinal( classData );
// ... 再把它转换成一个类
clasz = defineClass( name, decryptedClassData,
0, decryptedClassData.length );
// System.err.println( "[Start: decrypting class "+name+"]" );
}
} catch( Exception fnfe ) {
// System.out.println("decrypting error: "+name) ;
// fnfe.printStackTrace();
}
// if ( clasz == null )
// clasz = ClassLoader.getSystemClassLoader().loadClass(name);
// 必需的步骤2:如果上面没有成功
// 我们尝试用默认的ClassLoader装入它
if (clasz == null)
clasz = super.loadClass( name,resolve );
// 必需的步骤3:如有必要,则装入相关的类
if (resolve && clasz != null)
resolveClass( clasz );
// 把类返回给调用者
return clasz;
} catch( Exception ie ) {
throw new ClassNotFoundException( ie.toString());
}
}
static private byte[] readFromURL(String className) throws IOException {
String fileName = className.replace('.','/')+".class" ;
URL classURL = ClassLoader.getSystemClassLoader().getResource(fileName);
if (classURL == null) {
throw new RuntimeException("Cannot find resource /"" +className + "/"");
}
InputStream in = classURL.openStream() ;
int size=JspUtil.getUrlLength(classURL) ;
byte[] b=new byte[(int)size];
int rb=0;
int chunk=0;
while (((int)size - rb) > 0) {
chunk=in.read(b,rb,(int)size - rb);
if (chunk==-1) {
break;
}
rb+=chunk;
}
if (rb != size)
throw new IOException( "Only read "+rb+" of "+size+" for "+className );
in.close();
return b;
}
private static byte[] getCodeByte(String codeStr){
byte[] bytes = new byte[codeStr.length()/2] ;
for ( int i = 0,j=0 ; i < codeStr.length() ; ) {
bytes[j++] = new Integer(getByte(codeStr.charAt(i++)) * 16 | getByte(codeStr.charAt(i++))).byteValue() ;
}
return bytes ;
}
private static byte getByte(char c) {
switch(c)
{
case '0':
return 0;
case '1':
return 1;
case '2':
return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
case 'A':
return 10;
case 'B':
return 11;
case 'C':
return 12;
case 'D':
return 13;
case 'E':
return 14;
case 'F':
return 15;
}
return 0 ;
}
}
以下是加密类的实现:
public class EncryptClasses
{
static public void main( String args[] ) throws Exception {
String keyFilename = args[0];
String algorithm = "DES";
// 生成密匙
SecureRandom sr = new SecureRandom();
byte rawKey[] = Util.readFile( keyFilename );
DESKeySpec dks = new DESKeySpec( rawKey );
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance( algorithm );
SecretKey key = keyFactory.generateSecret( dks );
// 创建用于实际加密操作的Cipher对象
Cipher ecipher = Cipher.getInstance( algorithm );
ecipher.init( Cipher.ENCRYPT_MODE, key, sr );
// 加密命令行中指定的每一个类
for (int i=1; i
File pathFile = new File(filename) ;
if ( pathFile.isDirectory() ) {
encryptPathFile(ecipher,pathFile) ;
} else if ( pathFile.isFile() ) {
encryptClassFile(ecipher,pathFile);
} else
System.out.println("error when parse "+pathFile.getPath()) ;
// 读入类文件
}
}
private static void encryptClassFile(Cipher ecipher,File classFile) {
try {
if ( classFile.getPath().lastIndexOf(".class") < 0 ) return ;
// 读入类文件
byte classData[] = Util.readFile( classFile.getPath() );
// 加密
byte encryptedClassData[] = ecipher.doFinal( classData );
// 保存加密后的内容
Util.writeFile( classFile.getPath(), encryptedClassData );
System.out.println( "Encrypted "+classFile.getPath() );
} catch (Exception e) {
e.printStackTrace();
}
}
private static void encryptPathFile(Cipher ecipher,File pathFile) {
File[] classFiles = pathFile.listFiles() ;
for ( int i = 0 ; i < classFiles.length ; i++ ) {
File classFile = classFiles[i] ;
if ( classFile.isDirectory() ) encryptPathFile(ecipher,classFile);
else if ( classFile.isFile() ) encryptClassFile(ecipher,classFile);
else System.out.println("error when parse "+classFile.getPath()) ;
}
}
}