自定义类加载器的问题

时间:2010-02-17 08:50:31

标签: java classloader

我想实现一个自定义类加载器,以便对我的jar文件进行数字签名。 由于性能问题,我不想加密我的所有类。 所以我想实现一个自定义类加载器,当它被调用时 它将类委托给它的父级,如果父级无法加载它自己处理的类。 这是我的代码:

package org.dpdouran.attach;
import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.spec.AlgorithmParameterSpec;import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class CustomClassLoader extends ClassLoader {
    private static final int BUFFER_SIZE = 8192;
    @Override
    protected Class<?> findClass(String className) throws ClassNotFoundException {
        System.out.println("loading...  "+className);
        String clsFile = className.replace('.', '/') + ".class";
        InputStream in = getResourceAsStream(clsFile);
        if(in==null)
            return null;
        byte[] buffer = new byte[BUFFER_SIZE];
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int n = -1;
        try {
            while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
                out.write(buffer, 0, n);
            }
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        //do decrypt
        byte[] classBytes = out.toByteArray();
        byte[] iv = new byte[] { (byte) 0x8E, 0x12, 0x39, (byte) 0x9C,
                0x07, 0x72, 0x6F, 0x5A };
        AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
        Cipher dcipher=null;
        try {
            dcipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        byte keyBytes[] = "abcdEFGH".getBytes();
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "DES");
        try {
            dcipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
        } catch (InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        byte[] dbytes = null;
        try {
            dbytes = dcipher.doFinal(classBytes);
        } catch (IllegalBlockSizeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return defineClass(className, dbytes, 0, dbytes.length);
    }
    public CustomClassLoader( ClassLoader parent){
        super(sun.misc.Launcher.getLauncher().getClassLoader());
    }
}

我也通过更改“java.system.class.loader”属性更改了默认系统类加载器。 当我运行我的应用程序时,它与未加密的类工作正常,但当它到达加密类时,它会抛出ClassFormatError,我的findClasses方法永远不会被调用! 我怎么能确定我的自定义类加载器将在加密类上调用? 感谢

1 个答案:

答案 0 :(得分:0)

尝试以编程方式设置类加载器并查看其是否有效

Thread.currentThread().setContextClassLoader(myClassLoader);

当我实现我的类加载器时,我实现了loadClass方法而不是findClass。尝试做类似

的事情
try {
  return super.loadClass(name);
catch (Exception e) {
     ... your code here
}

另一方面,文档说不要覆盖loadClass而是覆盖findClass。

//编辑

另一个想法。

看起来你保留加密的类没有加密的.class文件。所以它看起来像父类加载器找到正确的.class文件,从不调用你的findClass。但是类文件的格式是错误的,因为它是加密的。 序列是my.loadClass-&gt; parent.loadClass-&gt; parent.loadClass ... - &gt; my.findClass

因此,您必须确保父类加载器不会找到该类。只需重命名加密类 - 为它们提供另一个扩展名或将它们保存在单独的文件夹中。

应该做的伎俩