摘 要:為了防止Java Web系統的非授權使用,開發者需要對軟件進行必要的保護。論文基于AES加密算法和嵌入式數據庫Derby,介紹了硬件保護基本原理,設計了綁定保護處理流程,給出了具體技術方案。論文提出了一種將固定設備硬件標識和移動設備硬件標識相結合的硬件綁定保護方案。實踐表明,該方案成本低廉、使用靈活、安全性高。
關鍵詞:AES;加密算法;Java Web;硬件綁定;Derby數據庫
中圖分類號:TP311 文獻標識碼:A 文章編號:2095-2163(2014)02-
Java Web Hardware Binding Preservation Technology based on AES Encryption Algorithm
CHEN Gang
(School of Management, Wuhan Textile University, Wuhan 430073,China)
Abstract: In order to prevent Java Web systems non-authorized use, developers need to protect software. This paper, based on the AES encryption algorithm and embedded database Derby, introduces the basic principle of hardware protection, designs binding protection process, and gives details technical methods. The paper proposes a hardware binding protection scheme combining fixed equipment hardware marking with mobile equipment hardware. The practice shows that the scheme has low cost and flexible uses, and the security is very high.
Keywords: AES; Encryption Algorithm; Java Web; Hardware Binding; Derby Database
0 引 言
保護軟件、防止盜版一方面需要法律法規的不斷完善、公民版權意識的不斷提高,另一方面技術手段也是其不可或缺的關鍵環節。在Java Web軟件保護過程中,目前更多地采用了機器的硬件標識符,例如硬盤的物理(或者邏輯)序列號[1-3]、CPU序列號、網卡MAC地址等等。由于硬件序列號通常與特定機器綁定,軟件在其他計算機上就無法使用,從而達到保護軟件的目的。但是這些信息中有的不可靠,有的則不穩定,例如:某些硬盤的物理序列號難以獲取,硬盤的邏輯序列號不穩定(與分區有關),CPU序列號容易被人為屏蔽、網卡MAC地址容易被更改等等。
針對上述問題,需要尋求一種更安全有效的方法。論文研究了一種基于固定設備(安裝Java Web系統的計算機)硬件標識和移動設備(例如移動U盤、移動硬盤等)硬件標識相結合的硬件綁定保護方案。該方案將固定設備的硬件標識(硬盤物理序列號+CPU序列號+網卡MAC地址)與移動設備硬件標識(論文采用U盤的物理序列號)相結合,采用高強度AES加密算法,并使用了嵌入式Derby數據庫。即使用戶非法處理了固定設備的硬件標識,由于缺少U盤,軟件仍然無法使用,因而較好地解決了這一問題。
1硬件綁定保護原理
1.1 AES加密算法
AES(Advanced Encryption Standard)新一代高級加密標準是由美國國家標準與技術研究所于2001年11月26日發布,并在2002年5月26日得到美國聯邦政府采用的一種區塊加密標準[4-5]。這個標準用來替代原先的DES,現已在全世界得到廣泛使用。AES大大增加了軟件系統的可靠性和安全性,獲得了廣泛認可,是迄至目前可獲得的最安全的對稱加密算法。AES區塊加密基本原理如圖1所示。
圖1 AES加密原理
Fig.1 The principle of AES Encryption
AES 設計有三個密鑰長度,分別是:128、192、256比特,其128比特密鑰比DES的56比特密鑰強1 021倍[6]。AES加密算法的全過程分別經過密鑰擴展(KeyExpansion)、輪密鑰加(AddRoundKey)、S 盒變換(SubBytes)、行變換(ShiftRows)、列變換(MixColumns)等步驟[7-9]。具體算法實現過程,請參閱相關文獻,這里不再贅述。
在Java Web系統中,考慮到字節碼文件(class)容易被反編譯的特點,以及基于系統運行效率的考慮,運用C語言代碼編寫實現AES算法,并封裝為本地DLL文件,具體函數聲明如下:
int AES_Encrypt(char *plain, char *keyStr, char *cipher);//加密,參數:明文,密鑰,返回的密文
int AES_Decrypt(char *cipher, char *keyStr, char *plain, int cipherLen); //解密,參數:密文,密鑰,返回的明文,密文長度
Java Web系統則通過JNI調用相應DLL文件中的AES_Encrypt()、AES_Decrypt()接口函數。
1.2 JNI技術
JNI(Java Native Interface)指的是Java本地程序接口,隸屬于JDK。通過使用JNI[10],運行于不同平臺的Java虛擬機就可以操作用C/C++(或其他語言)編寫的應用程序或庫,并調用相應的接口函數。
本解決方案中,通過JNI調用AES加密算法的原理如圖2所示。
圖2 JNI調用原理
Fig.2 The principle of calling JNI
圖2 中,native byte[] GetEncodingString(String plain)為Java Web中用于加密數據的方法,該方法調用DLL中的AES_Encrypt()方法。而native String GetDecodingString(byte[] cipher)則用于數據的解密處理。
解決方案中本地DLL接口函數的C語言代碼,著重要考慮兩個問題:不限制長度的字符串加密;中文字符的加解密容易亂碼問題。關鍵代碼如下:
JNIEXPORT jbyteArray JNICALL Java_DllUtils_GetEncodingString(JNIEnv *env, jobject obj, jstring jplain) {
const char *plain = (*env)->GetStringUTFChars(env, jplain, 0);//獲取UTF明文
int plen = strlen(plain);
char pTmp[plen + 1];
memset(pTmp, 0, plen + 1);
memmove(pTmp, plain, plen); //拷貝到pTmp
pTmp[plen] = '\0';//加字符串結束標志\0
char cipher[plen * 2 + 1];//存放密文的數組
int cipherLen = 0;
cipherLen = AES_Encrypt(pTmp, KEYSTR, cipher);//加密
(*env)->ReleaseStringUTFChars(env, jplain, plain);
jbyteArray cipherbytes = (*env)->NewByteArray(env, cipherLen);//轉換為字節碼
//將密文拷貝到cipherbytes中
(*env)->SetByteArrayRegion(env, cipherbytes, 0, cipherLen, (jbyte*) cipher);
return cipherbytes;
}
對應的解密函數為:
JNIEXPORT jstring JNICALL Java_wzhks_sys_dlls_DllUtils_GetDecodingString( JNIEnv *env, jobject obj, jbyteArray jcipher, jint tag) {
jsize srclen = (*env)->GetArrayLength(env, jcipher);
jbyte *tempb = (*env)->GetByteArrayElements(env, jcipher, JNI_FALSE);
char cipher[srclen + 1];
memset(cipher, 0, srclen + 1);
memmove(cipher, tempb, srclen);
cipher[srclen] = '\0';
(*env)->ReleaseByteArrayElements(env, jcipher, tempb, 0);
char plain[srclen];
memset(plain, 0, srclen);
if (tag == 0)
DES_Decrypt(cipher, WZHKS_ISEXAMDBKEY, plain, srclen);
else if (tag == 1)
DES_Decrypt(cipher, WZHKS_NOTEXAMDBKEY, plain, srclen);
return (*env)->NewStringUTF(env, plain);
}
加密函數:傳入明文,返回加密后的字節碼;解密函數:傳入字節碼,返回解密后的明文。上述處理方法的優勢在于:可以很好地解決超長字符串的加解密,以及實踐中常見的加解密后導致中文亂碼的問題。
1.3 Derby數據庫
Derby是Apache Group組織推出的開源數據庫產品。Derby是多用戶、標準驅動的關系數據庫系統,占用內存少,基于商業數據庫Cloudscape內核。Derby有一個沖中的特點:可以作為單獨的數據庫服務器使用,也可以作為嵌入式數據庫進行應用[11]。
論文使用Derby作為移動設備的嵌入式數據庫,保存加密后的系統授權特征碼。其運行原理如圖3所示。
圖3 Derby嵌入式數據庫
Fig.3 Derby embedded database
嵌入式Derby的連接方式:
Class.forName(“org.apache.derby.jdbc.EmbeddedDriver”);
DriverManager.getConnection(“jdbc:derby:MyDerbyDB", “username”,”password”);
1.4 設計流程
完整的解決方案是由三部分組成:Java Web系統、授權管理中心、U盤。而整個系統則基于MVC模式[12]進行處理,其處理流程如圖4所示。
圖4 系統處理流程
Fig.4 The processing flow of the system
Java Web系統啟動后,工作流程的關鍵步驟如下:
(1)系統獲取機器硬件組合特征碼(硬盤物理序列號+CPU序列號+網卡MAC地址),用AES加密,生成用戶識別碼,而后使用Email(或其他方式)傳送給軟件授權管理中心;
(2)授權管理中心解密接收到的用戶識別碼,再與獲取的U盤特征碼(物理序列號)組合進行AES加密,據此生成用戶授權碼,存入U盤嵌入式數據庫Derby。同時,將MD5加密后的密鑰一并存入,再將U盤下發給用戶;
(3)系統業務處理的運行,需要先根據機器硬件組合特征碼和U盤特征碼,進行AES加密處理。然后再與U盤嵌入數據庫中保存的用戶授權碼進行比對。如果二者吻合,則允許系統處理業務邏輯;否則,禁止處理。
2關鍵技術實現
2.1 生成用戶識別碼
系統使用WMIC(Windows Management Instrumentation)管理規范來獲取系統硬件特征碼,主要是通過exeCommandLine()方法來進行,例如:
String hdid = exeCommandLine("wmic path win32_physicalmedia get","SerialNumber");//硬盤序列號
String cpuid = exeCommandLine("wmic cpu get", "ProcessorId");//CPU序列號
String uid = exeCommandLine("wmic Win32_USBHub get", "PNPDeviceID");//U盤序列號
圖5為根據硬件特征生成的用戶識別碼。
圖5 用戶識別碼
Fig.5 Users identification code
2.2 exeCommandLine()方法核心代碼
該方法用于執行獲取硬件特征碼命令并返回執行結果。關鍵代碼如下:
Executor executor = new DefaultExecutor();
executor.setExitValue(1);
ExecuteWatchdog watchdog = new ExecuteWatchdog(50000);//創建線程狗
executor.setWatchdog(watchdog);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
executor.setStreamHandler(new PumpStreamHandler(outputStream));//命令輸出流
CommandLine cmdline = CommandLine.parse(command + " " + param); //解析命令行
DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
executor.execute(cmdline, resultHandler); //執行命令行
resultHandler.waitFor();//等待當前線程結束
//獲取命令運行的結果
id = outputStream.size() == 0 ? id : outputStream.toString().replaceAll(param, "");
這里的id,即為返回的序列號。進一步說明的是,獲取U盤物理序列號[13]時,需要特別處理一下:在resultHandler執行返回的數據流中,截取包含“USB\VID”的字符串數據,例如“USB\VID_0781&PID_5567\200517388116A8C061D9”,其中“USB\VID”代表U盤設備,而“200517388116A8C061D9”則為U盤物理序列號。注意:最后一個斜杠“/”后包含“&”字符的,則不是當前插入的U盤,而是系統保存的U盤插入記錄的數據,例如這樣返回的數據流“USB\VID_090C&PID_937B\5&844D9B1&0&3”,“5&844D9B1&0&3”并不代表U盤序列號。
2.3生成用戶軟件授權碼
根據前面獲得的用戶特征識別碼,生成軟件授權碼。關鍵代碼如下:
String usrAuthorizedKey = request.getParameter("usrauthorizedkey");
Pattern p = Pattern.compile("\t|\r|\n");
Matcher m = p.matcher(usrAuthorizedKey);
usrAuthorizedKey = m.replaceAll("").trim();
request.setAttribute("usrauthorizedkey", usrAuthorizedKey);
if (usrAuthorizedKey != null) {
String sourceData = SysUtils.INSTANCE.getDecodeString( EncryptedKey.INSTANCE.getExameePaperKeyFile(),SysUtils.INSTANCE.parseHexString2String(usrAuthorizedKey));
String authorizedKey = "";
String[] skey = sourceData.split(";");
if (skey.length == 4) {
request.setAttribute("unitname", skey[3]);
authorizedKey = skey[0] + ";" + skey[1] + ";" + skey[2] + ";"+ skey[3];
authorizedKey = SysUtils.INSTANCE.parseString2HexString(SysUtils.INSTANCE.getEncodeString(EncryptedKey.INSTANCE
.getExamdbKeyFile(), authorizedKey));//加密并轉換為16進制字符串
}
request.setAttribute("genauthorizedkey", authorizedKey);
}
圖6為根據用戶識別碼生成的軟件授權碼。圖中的“授權認證考點名”是從用戶識別碼中提取出來的數據,用于生成軟件授權碼時校驗使用。
圖6 用戶授權碼
Fig.6 Users authorization code
2.4 應用軟件授權碼
實際應用時,只需要在系統ServletContextListener監聽器的初始化事件中對用戶進行授權認證攔截,即可達到保護軟件的目的,例如:
@WebListener
public class SysConfigListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
sysConfig();// 初始化配置
DBFactory.INSTANCE.pooledInit();// 初始化連接池
generateKey();//初始化密鑰
SysConfig.IS_AUTHORIZED = SysUtils.INSTANCE.isAuthorizedSystem(Constants.AUTHORIZEDKEY_PROPERTIES); // 軟件是否授權
…// 其他業務處理
}
}
3 結束語
論文中采用的方法成本低廉,使用方便,安全性較高,可有效地防止Java Web系統的非授權使用。經實踐檢驗,效果良好。當然,基于Java字節碼本身容易被反編譯的特性,與智能卡加密狗相比仍存在一定風險。如果再進一步將Java Web系統有關Class文件進行代碼混淆(或加密)處理,對于數據加密強度要求不是非常高的場合,且基于其低成本優勢,將具有非常廣闊的應用前景。
參考文獻:
[1] 矯桂秋,覃一寧,李矞前,等.共享軟件的硬盤序列號保護機制的實現[J].計算機工程與應用,2003,(29):156-158.
[2] 孫敬先,李長星,鄭敏.基于硬盤序列號和RSA算法的軟件加密方法[J].電腦知識與技術,2010,(26):7267-7269.
[3] 基于硬盤序列號的序列密碼算法設計與實現 鄭海; 余勝超; 瞿學林; 鐘云海 計算機應用2003(S1):299-301.
[4] Wikipedia.Advanced Encryption Standard[EB/OL]. http://en.wikipedia.org/wiki/Advanced_Encryption_Standard,2013-10-25
[5] "Announcing the ADVANCED ENCRYPTION STANDARD (AES)". Federal Information Processing Standards Publication 197.United States National Institute of Standards and Technology (NIST). November 26, 2001.
[6] NIST. Advanced Encryption Standard (AES) [M].Federal Information Processing Standards Publication, 2001.
[7] 張月華,張新賀,劉鴻雁.AES算法優化及其在ARM上的實現[J].計算機應用,2011,(6):1539-1542.
[8] 覃曉草,李樹國.一種AES算法中S盒和逆S盒替換的表達式方法[J].微電子學與計算機,2014,(01):112-115.
[9] 蘇陽. AES加密引擎并行化設計與實現[J]. 武漢大學學報(理學版),2013,(5):471-475.
[10] 周強,樂小虬,李曦. JNI技術在桌面搜索工具中的應用[J].計算機技術與發展,2013,(2):170-172.
[11] 宋麗紅. 基于嵌入式開源數據庫Derby實現信息服務平臺[J]. 計算機工程與應用,2007,(3):87-89.
[12] 陳岡. Java開發入行真功夫[M]. 北京:電子工業出版社,2009-03.
[13] 王永國. 基于U盤物理序列號的軟件保護與注冊方法研究[J].計算機應用與軟件,2011,(5):281-282.