在客户端系统的实现中,使用了一些第三方API库:kXML和Bouncy Castle API。其中kXML是XML组装/解析的工具,而Bouncy Castle API是J2ME应用程序专用的XML加密/解密和签名/验证的工具。
客户端部分的主要模块实现如下:
1) 数据库访问模块
数据库访问模块是所有其它模块需要用到的模块,这是因为它把整个J2ME客户端需要用到的程序配置和用户设置存取到J2ME的数据库中。在J2ME MIDP中定义了一个简单的基于记录的数据库管理系统(Record Management System,RMS),在RMS中Record Store等同于一般数据库系统中的表(Table),它是记录了一系列记录的文件。
数据库访问模块对RMS进行操作,并对外部模块提供了两个存取数据的接口:
按名称保存数据到RMS的接口:public void setDataToRecordStore(String name, String data)
按名称从RMS获取数据的接口:public String getDataFromRecordStore(String name)
2) 用户界面模块
用户界面模块实现人机交互工能,接收用户输入,并把操作结果以友善的形式进行输出。除了使用J2ME提供的Display、Screen、Label、Command、Alert、Form、TextField等高级用户界面控件外,还需要使用J2ME提供的Canvas、Image等等低级用户界面API,来实现动画等特效。
3) XML加密/解密模块
这两个模块负责对服务器端传来的用RSA算法公匙加密的共享密匙进行解密,然后用共享密匙对机密信息使用Triple DES算法进行加密。
通过使用Bouncy Castle API密码术包,我们可以轻松地对所需要传输的交易请求里面的机密信息进行XML加密和解密。它所提供的org.bouncycastle.crypto包有加密/解密中需要用到的绝大部分的类,另外org.bouncycastle.util包提供了包括Base64编码转换、Hex编码转换等有用的工具类。在Bouncy Castle API中,公匙、私匙和共享密匙都是对象,在试图使用它们之前,必须要通过它们的主要参数重构出这些密匙对象。RSA的公匙有Modulus和Exponent两个主要参数,RSA私匙除了这两个参数外,还有privExp、dp、dq、p、q、qInv等几个参数,而Triple DES共享密匙只有单一的key参数。在传递这些密匙参数或加密的相关信息时,由于XML加密的很多元素指定使用Base64编码,因此还需要用到Base64这个工具类。我们定义了一个Encryptor类来处理所有加密/解密的相关的问题。定义的接口如下:
TripleDES加密接口:public byte[] encryptTripleDES (byte[] data) throws CryptoException
RSA解密接口:public synchronized byte[] decryptRSA(byte[] data) throws CryptoException
4) XML签名/验证模块
XML签名过程中,首先生成原始数据的摘要,再对摘要进行签名。生成摘要的算法一般使用SHA1算法。Bouncy Castle API包同样提供了生成签名用的摘要的SHA1Digest类,以及用于数字签名的RSAEngine、PSSSigner等类。我们定义Signature类封装所有的处理签名的功能代码。定义的接口如下:
生成摘要:private byte[] getDigest(String mesg) throws Exception
使用RSA私匙签名:public byte[] RSASign(byte[] toSign) throws Exception
5) XML组装/解析模块
为了简化问题,XML组装可以使用简单的字符串拼接来实现,而对于XML解析工作,我们使用kXML来处理。它是一个只占很小存储空间的XML语法分析程序,对于J2ME应用程序非常适合。
kXML有一个非常独特的DOM操作方法和被称为Pull的语法分析方法。DOM是一个与XML相互作用的简单方法,通常这个XML是一棵完整的XML树,被解析成一个存放在存储器中的节点结构,可以通过遍历这棵树获取所有节点信息。它非常简单易用,但是因为整棵树存在于存储器中造成存储器的负担。与DOM不同,Pull语法分析让程序员从语法分析程序中"拉"出下一个事件,Pull语法分析使处理状态改变更加容易,因为你可以发送分析器到不同的函数,维护它们自己的状态变量。此外,Pull特别适用于J2ME环境中的需要保持尽可能地少的内存占用的情况,因此我们采用Pull方法进行XML的解析。定义接口如下:
根据XML节点名称获取对应值:private String getXMLNodeValue(String nodeName)
6) 网络通信模块
在J2ME的MIDP 1.0 API中,网络通信协议支持UDP、HTTP、Socket等等。虽然从理论上说可以使用Socket或UDP协议与外界进行通信,但是一些厂商的MIDP设备可能不支持这些协议,使用这些协议进行通信可能造成程序移植上的问题。而HTTP由于是当今互联网最主要的通信协议,因此基本上所有厂商的移动终端设备都支持HTTP协议。因此我们采用HTTP协议进行通信。下面给出发送和接收数据的代码:public String sendAndReceiveByHttp(String url, String strToSend) throws Exception
{
HttpConnection hc = (HttpConnection)Connector.open(url, Connector.READ_WRITE);
hc.setRequestMethod(HttpConnection.POST);
hc.setRequestProperty(“Connection”, “Keep-Alive”);
DataOutputStream dos = hc.openDataOutputStream();
dos.writeUTF(strToSend);//向目的URL发送数据
dos.flush();
dos.close();
DataInputStream dis = hc.openInputStream();
String strReceived = dis.readUTF();//接收目的URL的响应数据
dis.close();
return strReceived;
}
4、 J2EE服务器端的实现
服务器端包含一些重要的模块,如多个对外接口,后台管理子系统,商家自服务子系统,OTA下载等等。这里我们对那些与J2ME客户端重复的功能模块如XML解析、加密、签名等等略去不提,而把重点放在服务器端的独有的实现细节上。服务器端逻辑结构图3所示。
A:由2.3描述的移动支付交易流程的各个步骤。
B:用户通过在网站或通过发送短信点播WapPush链接的方式,由OTA服务器提供MIDlet的下载。其中每个MIDlet都已经内嵌了RSA的私匙-公匙对,而这些密匙对是由RSA密匙对管理模块维护的。
C:商家登录自服务子系统进行注册帐号,发布、修改或删除商品的信息。
服务器端的主要模块的实现如下:
1) 交易接口及交易流程管理模块:交易接口是指移动支付流程中负责处理服务器端与外界交互的业务逻辑的模块,包括了用户交易接口、银行交易接口和商家交易接口。用户交易接口负责处理与J2ME客户端的交互,银行交易接口负责处理使用用户指定的银行卡扣费的业务逻辑,商家交易接口负责处理通知商家交易结果的业务逻辑。而这三个接口由交易流程管理模块进行整体上的协调管理。我们设计了一个交易记录表TradeHistory来记录必要的交易信息。
,一种基于J2ME的移动支付系统的设计与实现