保护MIDP应用里的数据文件

摘要
开发者开发MIDP应用时经常面临如何保护分布在JAR中的数据的困境,通过保护数据, 其他人便不能偷窃或使用它去创造另一个与之竞争的应用。JCP正在引入新的JSR来解决这个问题。可是,传统的方法依靠密码计算,它很消耗CPU资源并且不向后兼容的,因此对那些不支持新的API 的电话是很不方便的。这也让那些希望通过简单机制来防止版权侵犯的开发者感到不便。本文描述了一个在压缩和保护MIDP应用里的数据的方法。

随着OTA技术的持续成熟,一个新的市场对软件开发者开放了。目前,机智的蜂窝电话用户会购买一个来自Handango.com 的J2ME MIDP应用并在数秒内下载到他们的手机上。在刚刚过去的几年里,无线软件产业从铃声跳跃到了成熟(羽毛丰满)的游戏应用。

许多消费者更加认识到他们可以为他们的手机承受多少钱;他们经常联想带有无意义游戏的J2ME应用。然而,随着用户升级到新一代的手机,一种带有实际使用价值的基于MIDP应用的新知识受到关注。在Handango的最佳J2ME软件出售名单上都是基于应用的知识,如多语词典,词汇训练,圣经,记事本,甚至有鸡尾酒配方。名单上的一个字典程序在不到一年的时间里已经有将近26,000次下载!考虑到数千的无线订户愿意花费3美圆在一个铃声上,实际J2ME应用的市场潜力是巨大的。

不像游戏程序,基于知识的应用程序的价值在于数据。由于MIDP应用硬件利用的简单性,如果数据文件被折衷的话,可以很容易就提出一个与之竞争的应用。尽管将数据放在后台服务器的客户端-服务器模式可以阐释这种关系,这样的模式对大多数无线应用来讲被证明是不切实际的。除非等到无线数据传播费用降低,同时无线连接变得更加可靠和普遍,目前来说将数据文件嵌入MIDP JAR 是唯一的选择。因此,保护数据文件不受版权侵犯变得势在必行。

该问题的一个普遍解决办法是加密数据文件。实际上,几个JSRs正在筹备提供一套加密解密的标准API。但是,密码系统即使对于桌面J2SE应用来说也是 CPU密集的。而且,如果要等到新的手机都会支持这样的API,至少还有很多年时间。此外,基于新API的代码不向后兼容目前的手机。这导致了一个灰色时代,某个应用可以在一些手机上运行但在另外一些上不可以。一个可选择的方法是使用第三方的支持J2ME的密码库。一个流行的开源工具是Bouncy Castle的轻量级密码支持API。但是,注意:这个库超过400KB。考虑到市场上大多数的Nokia Java手机有64KB JAR的大小限制,这个方法又是不可行的。

我提出一个简单的解决该问题的方法。增加一行额外的代码,忽略JAR的大小限制。它有两个状态。首先,整理并压缩数据文件。然后,混淆压缩文件让它不能轻易被解压缩。

整理数据文件:许多Windows编辑器用\n\r避开了新行。特别是在你从Excel导出数据的情况下。"\r"是多余的,既然"\n"是足够来显示新一行的。在换行前消除"\r"和不用的空白可以节省很多字节。
注意不是所有的文本编辑器都可以探测到"\r";UltraEdit是有效的编辑器之一。如果数据文件很大,把它拆成几个小的文件以便快速的搜寻。但谨记小的文本文件不像大的压缩得那么高效。

 压缩数据文件:压缩算法的选择受到J2ME压缩执行的可用性限制。尽管压缩API已经与J2ME CDC(其目标是至少有2MB内存的设备)绑定,大部分目前的蜂窝电话设备仅仅支持CLDC和建立在其之上的MIDP标准。CLDC的最小内存要求是 128KB。因此,开发者必须寻找第三方的库或者写自己的代码。我发现了三个:     

利用zlib压缩算法的JCraft压缩库。它是开源的,文档良好,并且有大量跟随者;但是,库有点大。

Java4Ever有一个gzip (GNU zip)执行(3.27 KB)。它在LGPL的许可下,也是开源的。

我喜欢TinyLine的GZIPInputStream,因为它扩展了java.io.InputStream并且追随了同样的装饰模式,作为另一个 Java流类。它支持skip(), mark(),和其他基本I/O函数。

工具的作者对问题的响应很迅速,并且库的使用方法很直接:

InputStream in = getClass().getResourceAsStream(db);
in = new GZIPInputStream (in, 256);

 

有一个使用压缩的弱点:解压缩不可避免的增加了应用程序的内存覆盖区。TinyLine没有发布该库需要的额外堆的大小,但是按我的测试,我必须增加我的堆大小35到40KB。一个MIDP应用最初运行在Palm Zire(2 MB)上,现在需要4MB的RAM(随机存储寄存器)来运行。这在轻微地增加所需地内存覆盖区,对于大部分的应用程序和设备来说,不会让人担忧,但是还是推荐你们进行回朔测试。

压缩只是防御的第一线;软件盗贼仍可以轻易取得MIDP的JAR并利用正确的算法解压缩数据文件。我门可以混淆一下已压缩的数据文件。首先,我重命名数据文件为.res(或其他伪文件扩展名,如.xls或.mdb),如此一来压缩算法便不能轻易被发觉。然后,用 UltraEdit在HEX模式下打开压缩数据文件(或任何HEX编辑器),在压缩文件开头插入(不是覆盖)N字节数(如#!wx)。
最后,我改变了I/O代码,在读GZIPInputStream之前跳过N个字节:

      InputStream in = getClass().getResourceAsStream(db);
         in.skip(N);
         in = new GZIPInputStream (in, 256);

 

我们跳过的N个字节变成了应用程序和数据文件之间的秘密代码,修正过的压缩数据文件是除了你的代码之外的任何解压缩软件都无法识别的。当然了,一个意志坚定的电脑黑客可以反编译类文件并通过混淆代码费力的去寻找跳过的字节树。但这种安全措施应该足够阻止大部分的窃贼了。

移动设备能够支持所有的J2SE API栈的日子也不远了。但是那天到来之前,开发者们开发独立的MIDP应用仍必须坚持不懈的与JAR的大小限制和数据文件安全性进行战斗。本文的解决方法试图改进这个问题。我承认它有点笨拙并费事;将来,我希望有一个工具可以利用来自动进行数据压缩和混淆处理。

关于作者
Simon Ru 是Ebay的一个高级软件工程师。他有六年多的开发java和J2EE应用的经验。在2001年,他开始研究J2ME技术,是基于J2ME的六商业教育软件项目的创造者。该软件在Handango上有数千的下载次数。他是伯克利加州大学的研究生,是通过Sun认证的J2EE开发者。

资源
Tools to compress data using the gzip algorithm:
http://www.gzip.org/
Tools to compress and read data using the zlib algorithm:
http://www.jcraft.com/jzlib/
Library to read a gzip file using GZIPInputStream:
http://tinyline.com/download.html
Java4Ever:
http://www.java4ever.com/index.php?section=j2me&project=apime&menu=download&lang=
Over The Air User Initiated Provisioning 1.0:
http://java.sun.com/products/midp/OTAProvisioning-1.0.pdf
Lightweight crypto APIs for J2ME CDC:
http://www.bouncycastle.org/latest_releases.html
Optimizing MIDP size:
http://www.javaperformancetuning.com/tips/j2me.shtml
Security and Trust Services API for J2ME (JSR 177):
http://java.sun.com/products/satsa/
Handango:
http://www.handango.com/home.jsp?siteId=1

作者:Amydeng(作者的blog:http://blog.matrix.org.cn/page/Amydeng)
原文:http://www.matrix.org.cn/resource/article/44/44334_MIDP+DATA.html
关键字:MIDP;DATA