作者:李琴 李家明
出處:計(jì)算機(jī)與信息技術(shù)
摘 要:本文首先分析了Java源代碼需要加密的原因,簡(jiǎn)要介紹了DES算法及Java密碼體系和Java密碼擴(kuò)展,最后說(shuō)明了利用DES加密算法保護(hù)Java源代碼的方法及步驟。
關(guān)鍵詞 Java 加密 DES算法
Java語(yǔ)言是一種非常適用于網(wǎng)絡(luò)編程的語(yǔ)言,它的基本結(jié)構(gòu)與C++極為相似,但拋棄了C/C++中指針等內(nèi)容,同時(shí)它吸收了Smalltalk、C++面向?qū)ο蟮木幊趟枷?。它具有?jiǎn)單性、魯棒性、可移植性、動(dòng)態(tài)性等特點(diǎn)。這些特點(diǎn)使得Java成為跨平臺(tái)應(yīng)用開(kāi)發(fā)的一種規(guī)范,在世界范圍內(nèi)廣泛流傳。
加密Java源碼的原因
Java源代碼經(jīng)過(guò)編譯以后在JVM中執(zhí)行。由于JVM界面是完全透明的,Java類文件能夠很容易通過(guò)反編譯器重新轉(zhuǎn)換成源代碼。因此,所有的算法、類文件等都可以以源代碼的形式被公開(kāi),使得軟件不能受到保護(hù),為了保護(hù)產(chǎn)權(quán),一般可以有以下幾種方法:
?。?)"模糊"類文件,加大反編譯器反編譯源代碼文件的難度。然而,可以修改反編譯器,使之能夠處理這些模糊類文件。所以僅僅依賴"模糊類文件"來(lái)保證代碼的安全是不夠的。
(2)流行的加密工具對(duì)源文件進(jìn)行加密,比如PGP(Pretty Good Privacy)或GPG(GNU Privacy Guard)。這時(shí),最終用戶在運(yùn)行應(yīng)用之前必須先進(jìn)行解密。但解密之后,最終用戶就有了一份不加密的類文件,這和事先不進(jìn)行加密沒(méi)有什么差別。
?。?)加密類文件,在運(yùn)行中JVM用定制的類裝載器(Class Loader)解密類文件。Java運(yùn)行時(shí)裝入字節(jié)碼的機(jī)制隱含地意味著可以對(duì)字節(jié)碼進(jìn)行修改。JVM每次裝入類文件時(shí)都需要一個(gè)稱為ClassLoader的對(duì)象,這個(gè)對(duì)象負(fù)責(zé)把新的類裝入正在運(yùn)行的JVM。JVM給ClassLoader一個(gè)包含了待裝入類(例如java.lang.Object)名字的字符串,然后由ClassLoader負(fù)責(zé)找到類文件,裝入原始數(shù)據(jù),并把它轉(zhuǎn)換成一個(gè)Class對(duì)象。
用戶下載的是加密過(guò)的類文件,在加密類文件裝入之時(shí)進(jìn)行解密,因此可以看成是一種即時(shí)解密器。由于解密后的字節(jié)碼文件永遠(yuǎn)不會(huì)保存到文件系統(tǒng),所以竊密者很難得到解密后的代碼。
由于把原始字節(jié)碼轉(zhuǎn)換成Class對(duì)象的過(guò)程完全由系統(tǒng)負(fù)責(zé),所以創(chuàng)建定制ClassLoader對(duì)象其實(shí)并不困難,只需先獲得原始數(shù)據(jù),接著就可以進(jìn)行包含解密在內(nèi)的任何轉(zhuǎn)換。
Java密碼體系和Java密碼擴(kuò)展
Java密碼體系(JCA)和Java密碼擴(kuò)展(JCE)的設(shè)計(jì)目的是為Java提供與實(shí)現(xiàn)無(wú)關(guān)的加密函數(shù)API。它們都用factory方法來(lái)創(chuàng)建類的例程,然后把實(shí)際的加密函數(shù)委托給提供者指定的底層引擎,引擎中為類提供了服務(wù)提供者接口在Java中實(shí)現(xiàn)數(shù)據(jù)的加密/解密,是使用其內(nèi)置的JCE(Java加密擴(kuò)展)來(lái)實(shí)現(xiàn)的。Java開(kāi)發(fā)工具集1.1為實(shí)現(xiàn)包括數(shù)字簽名和信息摘要在內(nèi)的加密功能,推出了一種基于供應(yīng)商的新型靈活應(yīng)用編程接口。Java密碼體系結(jié)構(gòu)支持供應(yīng)商的互操作,同時(shí)支持硬件和軟件實(shí)現(xiàn)。
Java密碼學(xué)結(jié)構(gòu)設(shè)計(jì)遵循兩個(gè)原則:
(1)算法的獨(dú)立性和可靠性。
(2)實(shí)現(xiàn)的獨(dú)立性和相互作用性。
算法的獨(dú)立性是通過(guò)定義密碼服務(wù)類來(lái)獲得。用戶只需了解密碼算法的概念,而不用去關(guān)心如何實(shí)現(xiàn)這些概念。實(shí)現(xiàn)的獨(dú)立性和相互作用性通過(guò)密碼服務(wù)提供器來(lái)實(shí)現(xiàn)。密碼服務(wù)提供器是實(shí)現(xiàn)一個(gè)或多個(gè)密碼服務(wù)的一個(gè)或多個(gè)程序包。軟件開(kāi)發(fā)商根據(jù)一定接口,將各種算法實(shí)現(xiàn)后,打包成一個(gè)提供器,用戶可以安裝不同的提供器。安裝和配置提供器,可將包含提供器的ZIP和JAR文件放在CLASSPATH下,再編輯Java安全屬性文件來(lái)設(shè)置定義一個(gè)提供器。Java運(yùn)行環(huán)境Sun版本時(shí), 提供一個(gè)缺省的提供器Sun。
下面介紹DES算法及如何利用DES算法加密和解密類文件的步驟。
DES算法簡(jiǎn)介
DES(Data Encryption Standard)是發(fā)明最早的最廣泛使用的分組對(duì)稱加密算法。DES算法的入口參數(shù)有三個(gè):Key、Data、Mode。其中Key為8個(gè)字節(jié)共64位,是DES算法的工作密鑰;Data也為8個(gè)字節(jié)64位,是要被加密或被解密的數(shù)據(jù);Mode為DES的工作方式,有兩種:加密或解密。
DES算法工作流程如下:若Mode為加密模式,則利用Key 對(duì)數(shù)據(jù)Data進(jìn)行加密, 生成Data的密碼形式(64位)作為DES的輸出結(jié)果;如Mode為解密模式,則利用Key對(duì)密碼形式的數(shù)據(jù)Data進(jìn)行解密,還原為Data的明碼形式(64位)作為DES的輸出結(jié)果。在通信網(wǎng)絡(luò)的兩端,雙方約定一致的Key,在通信的源點(diǎn)用Key對(duì)核心數(shù)據(jù)進(jìn)行DES加密,然后以密碼形式在公共通信網(wǎng)(如電話網(wǎng))中傳輸?shù)?a class="bluekey" target="_blank">通信網(wǎng)絡(luò)的終點(diǎn),數(shù)據(jù)到達(dá)目的地后,用同樣的Key對(duì)密碼數(shù)據(jù)進(jìn)行解密,便再現(xiàn)了明碼形式的核心數(shù)據(jù)。這樣,便保證了核心數(shù)據(jù)在公共通信網(wǎng)中傳輸?shù)陌踩院涂煽啃浴?br />
也可以通過(guò)定期在通信網(wǎng)絡(luò)的源端和目的端同時(shí)改用新的Key,便能更進(jìn)一步提高數(shù)據(jù)的保密性。
利用DES算法加密的步驟
(1)生成一個(gè)安全密鑰。在加密或解密任何數(shù)據(jù)之前需要有一個(gè)密鑰。密鑰是隨同被加密的應(yīng)用程序一起發(fā)布的一段數(shù)據(jù),密鑰代碼如下所示。
【生成一個(gè)密鑰代碼】
//
生成一個(gè)可信任的隨機(jī)數(shù)源
Secure Random sr
=
new
SecureRandom();
//
為我們選擇的DES算法生成一個(gè)KeyGenerator對(duì)象
KeyGenerator kg
=
KeyGenerator.getInstance (
"
DES
"
);
Kg.init (sr);
//
生成密鑰
Secret Key key
=
kg.generateKey();
//
將密鑰數(shù)據(jù)保存為文件供以后使用,其中key Filename為保存的文件名
Util.writeFile (key Filename, key.getEncoded () );
2)加密數(shù)據(jù)。得到密鑰之后,接下來(lái)就可以用它加密數(shù)據(jù)。如下所示。
【用密鑰加密原始數(shù)據(jù)】
// 產(chǎn)生一個(gè)可信任的隨機(jī)數(shù)源
SecureRandom sr = new SecureRandom();
//從密鑰文件key Filename中得到密鑰數(shù)據(jù)
Byte rawKeyData [] = Util.readFile (key Filename);
// 從原始密鑰數(shù)據(jù)創(chuàng)建DESKeySpec對(duì)象
DESKeySpec dks = new DESKeySpec (rawKeyData);
// 創(chuàng)建一個(gè)密鑰工廠,然后用它把DESKeySpec轉(zhuǎn)換成Secret Key對(duì)象
SecretKeyFactory key Factory = SecretKeyFactory.getInstance("DES" );
Secret Key key = keyFactory.generateSecret( dks );
// Cipher對(duì)象實(shí)際完成加密操作
Cipher cipher = Cipher.getInstance( "DES" );
// 用密鑰初始化Cipher對(duì)象
cipher.init( Cipher.ENCRYPT_MODE, key, sr );
// 通過(guò)讀類文件獲取需要加密的數(shù)據(jù)
Byte data [] = Util.readFile (filename);
// 執(zhí)行加密操作
Byte encryptedClassData [] = cipher.doFinal(data );
// 保存加密后的文件,覆蓋原有的類文件。
Util.writeFile( filename, encryptedClassData );(3)解密數(shù)據(jù)。運(yùn)行經(jīng)過(guò)加密的程序時(shí),ClassLoader分析并解密類文件。操作步驟如下所示。
【用密鑰解密數(shù)據(jù)】
// 生成一個(gè)可信任的隨機(jī)數(shù)源
SecureRandom sr = new SecureRandom();
// 從密鑰文件中獲取原始密鑰數(shù)據(jù)
Byte rawKeyData[] = Util.readFile( keyFilename );
// 創(chuàng)建一個(gè)DESKeySpec對(duì)象
DESKeySpec dks = new DESKeySpec (rawKeyData);
// 創(chuàng)建一個(gè)密鑰工廠,然后用它把DESKeySpec對(duì)象轉(zhuǎn)換成Secret Key對(duì)象
SecretKeyFactory key Factory = SecretKeyFactory.getInstance( "DES" );
SecretKey key = keyFactory.generateSecret( dks );
// Cipher對(duì)象實(shí)際完成解密操作
Cipher cipher = Cipher.getInstance( "DES" );
// 用密鑰初始化Cipher對(duì)象
Cipher.init( Cipher.DECRYPT_MODE, key, sr );
// 獲得經(jīng)過(guò)加密的數(shù)據(jù)
Byte encrypted Data [] = Util.readFile (Filename);
//執(zhí)行解密操作
Byte decryptedData [] = cipher.doFinal( encryptedData );
// 然后將解密后的數(shù)據(jù)轉(zhuǎn)化成原來(lái)的類文件。將上述代碼與自定義的類裝載器結(jié)合就可以做到邊解密邊運(yùn)行,從而起到保護(hù)源代碼的作用。
結(jié)束語(yǔ) 加密/解密是數(shù)據(jù)傳輸中保證數(shù)據(jù)安全性和完整性的常用方法,Java語(yǔ)言因其平臺(tái)無(wú)關(guān)性,在Internet上的應(yīng)用非常之廣泛。使用DES算法加密Java源碼在一定程度上能保護(hù)軟件的產(chǎn)權(quán)。