Java虚拟机----自定义类加载器:实现对字节码的加密解密

来源:互联网 发布:成本测算软件 编辑:程序博客网 时间:2024/05/24 00:25

一、概述

        上一篇Java虚拟机----类的加载过程》分析了类加载的全过程,本文将以一个示例实现自定义类加载器。

        Java 源文件的编译结果缺省为字节码,也就是后缀名为“.class”的文件,那么在很多情况下,我们并不希望看到编译后的字节码文件被其他人使用一些反编译工具将程序中的字节码文件反编译为源文件,以透露了一些非开源的数据信息,尤其是随着目前网络的日益普及,互联网的飞速发展,各式各样的Java反编译工具日新月异的更新着。那么尽管不能百分之百的有效组织编译后的字节码文件被反编译,那么至少可以通过一些字节码加解密技术来增加反编译的难度。尽管目前的加密算法很多,可以参阅《 Java加密技术——对称加密算法一览》。

        本示例将采用3DES对称加密算法对编译后的字节码进行加密处理,加密后的字节码文件就增加了被其他人反编译的难度,当然加密后的字节码文件很容易用我们自定义的类加载器执行加载,在执行加载的时候配合自定义类加载器重新定义了类的加载规则,以便实现一些自定义的处理逻辑。

        先来了解下3DES加密算法。

二、3DES加密算法

        DES,即Data Encryption Standard的缩写,即数据加密算法。是IBM公司于1975年研究成功并公开发表的。DES算法的入口参数有三个:KeyDataMode。其中Key8个字节共64,DES算法的工作密钥;Data也为8个字节64,是要被加密或被解密的数据;ModeDES的工作方式,有两种:加密或解密[Java代码中就是2个常量] 

        3DES也叫 Triple DES,它是DES加密算法的一种模式,使用356位的密钥对数据进行三次加密。简单来说,由于计算机的运算能力的增强,原版DES密码的密钥容易被暴力破解,3DES即是用来提供一种相对简单的方法,通过增加DES的密钥长度来避免类似的破解。

        本例中的加密解密的算法实现在com.ljheee.security.Use3DES类中。代码如下:

 package com.ljheee.security;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * 使用3DES 算法对目标数据执行加解密
 * 
 * @author ljheee
 */
public class Use3DES {
private static final String ALGORITHM = "DESede";//定义加密算法
/**

* @param key 192位的加密Key
* @param src 明文数据
* @return
*/
public static byte[] encrypt(byte[] key, byte[] src){
    byte[] value = null;
    SecretKey deskey = new SecretKeySpec(key, ALGORITHM);
    try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, deskey);
            value = cipher.doFinal(src);
      } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
      } catch (NoSuchPaddingException e) {
            e.printStackTrace();
      } catch (InvalidKeyException e) {
            e.printStackTrace();
      } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
      } catch (BadPaddingException e) {
            e.printStackTrace();
      }
            return value;
}

/**
* 解密
* @param key 192位的加密Key
* @param src 待解密数据
* @return
*/
public static byte[] decrypt(byte[] key, byte[] src){
      byte[] value = null;
      SecretKey deskey = new SecretKeySpec(key, ALGORITHM);

      try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, deskey);
            value = cipher.doFinal(src);
      } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
      } catch (NoSuchPaddingException e) {
            e.printStackTrace();
      } catch (InvalidKeyException e) {
            e.printStackTrace();
      } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
      } catch (BadPaddingException e) {
            e.printStackTrace();
      }
      return value;
}
//测试
public static void main(String[] args) {
      byte[] key = "01234567899876543210abcd".getBytes();

      byte[] encoded = encrypt(key, "554278".getBytes());
      System.out.println("加密后"+encoded);
      System.out.println("解密后"+new String(decrypt(key, encoded)));
}
}

三、自定义类加载器

        接下来我们要做的是,新建一个测试类Test,对编译后的字节码文件[Test.class,一般在工程bin目录下]执行3DES加密;再使用自定义的类加载器将加密的字节码文件在加载前解密。工程结构、代码如下:

 

 package com.ljheee.loader;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.ljheee.security.Use3DES;
/**
 * 自定义类加载器
 * 对加密后的字节码进行解密
 * @author ljheee
 *
 */
public class MyClassLoader extends ClassLoader {
/**
* 原 字节码路径
*/
private String byteCode_Path;
/**
* 密钥
*/
private byte[] key;

public MyClassLoader(String byteCode_Path, byte[] key) {
      this.byteCode_Path = byteCode_Path;
      this.key = key;
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
      byte[] value = null;
      BufferedInputStream in = null;

      try {
            in = new BufferedInputStream(new FileInputStream(byteCode_Path+name+".class"));

            value = new byte[in.available()];
            in.read(value);
      } catch (FileNotFoundException e) {
            e.printStackTrace();
      } catch (IOException e) {
            e.printStackTrace();
      } finally {
            try {
                  if(null != in) in.close();
            } catch (IOException e) {
                  e.printStackTrace();
            }
      }
      //将加密后的字节码--解密
      value = Use3DES.decrypt(key, value);
      return defineClass(value, 0, value.length);//将byte数组转化为一个类的Class对象实例
}

public static void main(String[] args) {
      BufferedInputStream in = null;
      try {
            //把原  字节码文件读到src字节数组。注意:此字节码文件是新建测试类Test后编译后的,一般在工程bin目录下
            in = new BufferedInputStream(new FileInputStream("E:\\GitCode\\MyClassLoader\\bin\\com\\ljheee\\loader\\Test.class"));
            byte[] src = new byte[in.available()];
            in.read(src);
            in.close();

            byte[] key = "01234567899876543210abcd".getBytes();//密钥24位
            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("E:/GitCode/Test.class"));

            //将字节码  加密后,写到"E:\\GitCode"
            out.write(Use3DES.encrypt(key, src));
            out.close();

            //创建自定义类加载器,加载目标字节码
            MyClassLoader loader = new MyClassLoader("E:/GitCode/", key);
            System.out.println(loader.loadClass("Test").getClassLoader().getClass().getName());
      } catch (FileNotFoundException e) {
            e.printStackTrace();
      } catch (IOException e) {
            e.printStackTrace();
      } catch (ClassNotFoundException e) {
            e.printStackTrace();
      }
}
}

 


完整工程:https://github.com/ljheee/MyClassLoader

1 0
原创粉丝点击