基于AES加密算法的Java Web硬件绑定保护技术
2014-04-29陈冈
摘 要:为了防止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.