Java语言是一种应用广泛的编程语言,再加上其平台无关性的特点,如果不对Java语言编写的软件进行相应的加密处理,软件源代码就很容易被一些居心叵测的人窃取,造成软件内容泄露。为此,我们运用经典的加密算法Trple DES对Java源文件编译后生成的类文件进行加密,然后对JVM的类装载器进行改造,使其能够识别加密后的类文件,同时为了提供更高程度的加密,利用RSA算法对前一加密阶段生成的密钥进行加密,最终达到真正保护软件版权等目的。
一、Java代码加密技术
对于Java代码,一般有以下几种加密方法:
1、Java代码模糊处理
代码模糊处理字面上的意思就是模糊处理代码的行为,Java模糊处理器用不易察觉的方法改变程序,以至于它的运行对JVM来说是一模一样的,但它使得试图理解程序的人更加迷惑了。一种常用的模糊处理代码的方法是用一个非法的字符串来替代类文件中的标记,这比使用没有意义的字符串具有更好的模糊处理效果。然而,可以修改反编译器,使之能够处理这些模糊类文件。所以仅仅依赖‘模糊类文件’来保证代码的安全是不够的。
2、对源文件进行加密
比如PGP(Pretty Good Privacy)或GPG((NU Privacy Guard)。用户在应用之前必须先进行解密,但是解密后用户就得到了一份不加密的文件,相当于事先没有加密,所以这种技术称之为保密更为合适。
3、加密类文件(.class文件)
因为Java代码被编译为类文件,然后由JVM加载类文件,把它转换为二进制机器码。因此可以对编译后形成的类文件进行加密,JVM用定制的类装载器(ClasfLoader)解密文件。JVM每次装入类文件时都需要一个称为ClasLoader的对象,这个对象负责把新的类装入正在运行的JVM。JVM给Clas9Joader一个包含了待装入类名字的字符串,然后由ClasLoader负责找到类文件,装入原始数据,并把它转换成一个Class对象。用户下载的是加密过的类文件,在加密类文件装入之时进行解密,因此可以看成是一种即时解密器。由于解密后的字节码文件永远不会保存到文件系统,所以窃密者很难得到解密后的代码。
在此,我们选取第三种加密技术,并利用Trple DES (3DES)算法,对类文件进行加密。
二、TripleDES加密算法
DES加密算法为密码体制中的对称密码体制,如图2所示。其密钥长度为56位,明文按64位进行分组,将分组后的明文组和56位的密钥按位替代或交换的方法形成密文组的加密方法。
DES工作的基本原理是,其入口参数有三个:keydata、mode、key为加密解密使用的密钥,data为加密解密的数据,mode为其工作模式。当模式为加密模式时,明文按照64位进行分组,形成明文组,key用于对数据加密,当模式为解密模式时,key用于对数据解密。实际运用中,密钥只用到了64位中的56位,这样才具有高的安全性。
3DES是DES加密算法的一种模式,它使用3条64位的密钥对数据进行三次加密。比起DES,3DES更为安全。3DES是DES向AES过渡的加密算法,是DES的一个更安全的变形。它以DES为基本模块,通
过组合分组方法设计出分组加密算法,其具体实现如下:设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,M代表明文,S代表密表,则:
3DES加密过程为:S=Ek3 (Dk2 (Ekl (M)))。
3DES解密过程为:M =Dkl((EK2 (Dk3(S)))。
Java加密扩展即Java Cryptograp hy Exten SiDn,简称JCE。它是Sun的加密服务软件,包含了加密和密匙生成功能。JCE是JCA(Java Cryptography Architecture)的一种扩展。
JCE没有规定具体的加密算法,但提供了一个框架,加密算法的具体实现可以作为服务提供者加入。除了JCE框架之外,JCE软件包还包含了SunjCE服务提供者,其中包括许多有用的加密算法,比如DES和RSA等常用加密算法。在实际的应用当中,需要下载相应的.jar文件可到http://www. bouncycastle. org下载bcpIOv - jdk14 - 123. jar)。运用3DES算法加密解密的大致步骤如下:
生成密钥:
//生成一个可信任的随机数源
SecureRandjom dataSrc=naA/ SecureRandanl():
//为我们选择的3 DES算法生成一个KeyGenerator对象
KeyGenerabr keyGene =KeyGenerabr. getjnstance("DES");
Kg. init (dataSn:) ;
//生成密钥
Secret Key key=keyGene. geneniteKey();
//将密钥数据保存为文件供以后使用,其中keyFile.h tn l为保存的文件
Util.writeFile (keyFile. htnl. key. getEncoded());
加密数据:
//产生一个可信任的随机数源
SecureRandom dataSrc=new SecureRandom();
//从密钥文件keyFile. hml中得到密钥数据
Byte ke)Data=UtiL readFile (keyFile. htnD;
//从原始密钥数据创建DESKeySpec对象
DESKeySpec dkspec=newDESKeySpec(rawKe)Data);
//创建一个密钥工厂,然后用它把DESKeySpec转换成Secret Key对象
Secre tKeyFactory keyFac =Secre tKeyFactorry. getln stance ( "DES" ) ;
Secret Key key = keyFac. generateSecret( dkspec ) ;
//Cipher对象实际完成加密操作
Cipher cipher=Cpher. getlnstance(”DES”);
//用密钥初始化Cipher对象
cpher. init( Cipher. I:NCRYPT_MODE, key, dataSrc);
//通过读类文件获取需要加密的数据,unEnc ryp tFile为需要加密的明文文件名
Byte data=Util. readFile (unEncryptFileName);
//执行加密
Byte encryptedClassData=cpher. doFinal(data);
//保存加密后的文件,覆盖原有的类文件。
U til.w riteFile(unEnc ryp tFilename,
encryp tedClasData);
解密数据:
//生成一个可信任的随机数源
Secun:Random dataSrc=new SecureRandom();
//从密钥文件中获取原始密钥
Byte ke}Dam=UtiL readFile( keyFile. htnl);
//创建一个D ESKeySpec对象
DESKeySpec dkspec=new DESKeySpec(ke}Data);
//创建一个密钥工厂,然后用它把D ESKeySp ec对象转换成Secret Key对象
SecretKeyFacn)ry key Fac=SecretKeyFacbry getlnstance(”3DES");
SecretKey key=keyFac. generateSecret( dkspec);
//Cip he r对象实际完成解密
Cpher cipher=Cipher. getlnstance(”3DES”);
//用密钥初始化Cipher对象
Cipher. init( Cipher.DECRYPT MODE, key, dataSrc);
//获得经过加密处理的数据
Byte encrypkdData=Util. readFile (unEncryp tFilenane);
//执行解密
Byte decryptedData=cipher. doFinal(encryp tedD ata;
//然后将解密后的数据转化成原来的类文件。
3DES加密算法对文件的加密解密工作具体流程图见图3,其中K1,K2,K3为3条64位的密钥。由于JVM都有一个默认的类转载器(ClasLoader)用来装载类文件,如果由默认的Classlader寻找经过加密的类文件,由于类文件已经加密,所以它不会认可这个类文件,装入过程将失败。因此,我们必须自己实现C1assLoader,然后将上述代码与自定义的类装载器结合起来,就可以变解密便运行,从而实现保护代码的作用。然而,因为对称式的加密方法如果是在网络上传输加密文件就很难把密钥告诉对方,不管用什么方法都有可能被别窃听到。因此,如果3DES加密算法的密钥在传输过程中泄漏,那么窃取者就可以用这个密钥解密,得到类文件的明文,然后用Java反编译类文件就可以得到Java源文件,从而使所有的加密工作失效。
同时,如果窃取者对类装载器进行修改,使其将解密后的类文件保存到一文件处而非立即运行,然后反编译保持下来的解密后的类文件,就得到了Java源文件,同样使得加密工作失效。但是这些都有一个前提,那就是窃取者得到了密钥。因而对密钥的加密工作就很的重要。在此采用非对称经典的非对称加密RSA算法。
三、RSA加密算法
RSA加密算法属于非对称加密算法。与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。非对称式的加密方法的公钥是可以公开的,不怕别人知道,收件人解密时只要用自己的私钥即可,这样就很好地避免了密钥的安全性问题。
非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其他方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。甲方只能用其专用密钥解密由其公用密钥加密后的任何信息。
非对称加密算法消除了最终用户交换密钥的需要,保密性好,但加密和解密花费时间长、速度慢,只适用于对少量数据进行加密,因此在这里采用经典的非对称加密RSA算法对3DES算法生产的密钥进行加密。
RSA方法的工作原理如下:
(1)任意选取两个不同的大质数p和q,计算乘积r=p×q。
(2)任意选取一个大整数e,e与(p-1)×(q-l)互质,整数e用做加密密钥。注意:e的选取是很容易的。
例如,所有大于p和q的质数都可用。
(3)确定解密密钥d:dXe=Imod(p -1)x(q -1);根据e、p和q可以容易地计算出d。
(4)公开整数r和e,但是不公开d。
(5)将明文P(假设P是一个小于r的整数)加密为密文C,计算方法为C=Pe mod r(e为幂次方)。
(6)将密文C解密为明文P,计算方法为P=Cd mod r(d为幂次方)。
然而只根据r和e(不是p和q)要计算出d是不可能的。因此,任何人都可对明文进行加密,但只有授权用户(知道d)才可对密文解密。所以RSA方法可以具有很好的加密效果。
利用RSA加密算法加密解密的大致步骤如下:
File testFile=nev File(”test.html“);
//test.html为需要加密的明文
//读入明文
File hputStrean in=new FilelnputStream(file);
ByteArnUJOuputStrean out=new
B yteA na}OuputStream();
byte[]temptbuf=new byte[1024];
int count=0:
while((count=in.read(temptbuf))!=-1)(bout write( temptbut O,count);
temptbuf=new byte[1024];
}
in.clo se();
byte[]data=ouL tnByteArray();
//将明文转换成字节数组保存在data中
KeyPair keyPair = RSAUtiL generateKeyPair() ;
//生成密钥对
RSAPublicKeypub_key =RSAPublicKey) keyPair. getPublic () ;
R SAPrivateKey p ri_key =(RSAPrivateKey) keyPair. getPrivate () ;
byte[ ] modBytes =pubKey. geModulus() .tobyteA rray () ;
byte[ ] pubExpByks =pubKey. ge tPublicExponent() . roB yteA nay ( ) ;
byte[ ] prModBytes =priKey. ge Modulus().dByteA rray();
byte[]priExpBytes=p riKey. ge tPrivateExponent().bB yteA nay();
//生成公钥
RS4PublicKey pubKey=R SAUtiL genemteR SA PublicKey (pul:Mo dB ytes,pubExpB yteS);
//生成私钥
RSAPrivateKey p riKey=R SAU tiL generateRSAPrivateKey(p rModB ytes,p riExpB ytes);
byte[]tempt=RS4Util. encr)pt(pubKey, data);
//用公钥对data中的明文数据加密得到密文testFile=new File(" encOrpt_result html”);
OuputStrean out=nav FileOuputStrefm(testFile);
//将密文存放在enc ryp t_n: sult.htul文件中
ouL write( tempt);
out.cbse();
byte[]data=RStYUtiL decO,pt(priKey, tanpt);
//用私钥对tempt中的密文解密得到明文
testFile=nav File(”decWpt_n:sult- hhil");
out=new FileOutputStI℃an(testFile);
out.w rite( data);
//将解密后得到的明文存储在dec r3rp t_re sult html文件中
out flush () ;
out close () ;
}
RSA加密算法对密钥的加密解密的具体工作流程如图4所示。
至此,一个基于Triple DES和RSA加密算法的Java代码加密技术就完成了。利用加密解密技术是保证数据传输中数据安全性的一种常用的方法,Java语言由于其平台无关的特性,且应用十分广泛,因此保证安全性就显得特别的重要。利用3DES算法生产一个密钥对编译过后的类文件进行加密,再利用RSA算法对获得的密钥进行加密,在很大程度上可以保证Java源代码的安全性。整个加密解密的工作流程图如图5所示。
目前该技术已经实际运用在广州中间件研究中心的各种软件产品当中,很好的保护了该中心的软件版权的安全。
小知识之Triple DES加密算法
Triple DES加密算法又被称作3DES加密算法,它相当于是对每个数据块应用三次DES加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。