隔了好久没更新了,前一篇创建好了文件系统,那现在就可以实现使用电子钱包了,这篇首先讲电子钱包的圈存,其实就是存款进去的意思。
首先看一个灰常重要的流程图:
首先,终端(连着主机,他们的另一边是卡片)给卡片发送圈存初始化命令,命令格式如下表:
卡片收到这个初始化命令之后,首先是根据密钥标识符找出相应的圈存密钥,并做一系列的判断(比如没找到或者啥的),反映到代码就是根据判断抛出异常,然后如果找到了密钥而且没什么问题的话,就继续往下处理,首先生成一个随机数,然后用刚才查找到的圈存密钥生成一个过程密钥(为什么不直接用圈存密钥而要弄个新的过程密钥?因为直接用圈存密钥容易被破解啊,网络安全方面的知识,同个密钥一直重复用就更容易被破解,所以要把它结合一个随机数产生一个每次都变化的过程密钥)。过程密钥的生成方式:其输入的数据为伪随机数||电子钱包联机交易序号||8000,密钥为所查找到的圈存密钥。(||这个符号表示的是字符串连接而不是代码中的或)。然后IC卡利用所生成的过程密钥产生MAC1。其输入的数据为电子钱包余额(交易前)||交易金额||交易类型标识(圈存是02)||终端机编号,密钥为过程密钥。在进行这些操作后,IC卡将返回相应的数据给终端:
继而终端讲命令传送给主机,主机程序验证mac1,如果验证通过,则同意交易进行,主机从持卡人账户扣除相应的金额。接下来终端再给卡片发送圈存命令,格式如下:
然后就是(以下是直接复制粘贴文档的,所以说按文档和ppt一步步来基本就可以实现功能了,只是这个项目细节方面比较恼人):
1、I C卡收到圈存命令后,利用过程密钥生成MAC2。其输入数据为交易金额||交易类型标识(圈存的都是02)||终端机编号||交易日期(主机)||交易时间(主机)。密钥为过程密钥。与圈存命令传送的MAC2进行比较,如果相同,则MAC2有效
2、 IC卡将电子钱包联机交易序号加1,并且把交易金额加在电子钱包的余额上。
3、 IC卡生成TAC码。TAC码的生成方式和MAC码的生成方式一致。其输入的数据:电子钱包余额(交易后)||电子钱包联机交易序号(加1前)||交易金额||交易类型标识(圈存是02)||终端机编号||交易日期(主机)||交易时间(主机)。密钥为TAC密码最左8个字节与TAC密码最右8个字节异或的结果。
IC卡将TAC码返回给终端。至此,IC卡端的圈存交易已经完成了。
猴,好累,一大串文字,对,做这个项目就是要不断翻这一大堆文字查询,这个挺累的一个地方,但最累的还是写代码时要注意的细节,因为出了个bug就麻烦了,而且java card仿真器原因,并不能像写C++项目那样就轻松设啥端点调试的,调试方法是一个用抛出异常的方法,但这个方法貌似只能抛出最长2个字节的内容,比如lc的值,方法二是直接返回相应的数据内容给终端,在仿真器里看返回内容,进行比对。之前自己没掌握好两个调试方法的时候,就真是一行行去检查代码的,结果花了半天时间都没检查出来bug在哪,所以测试和debug对于软件开发是多么重要的一个流程啊。
这里没啥好说的,就是执行圈存初始化和圈存的函数,判断一些异常,然后执行辅助函数,得到返回值,根据返回值再做一些异常判断。如题,(short)0x18和(short)18这个十进制和十六进制的问题困扰过我很久!逗比了啊,被这个弱智问题害我debug了半天。
这里牵涉到两个重要的辅助函数,一个是用来生成过程密钥的3DES加密函数,流程如下:
另一个是用来生成MAC和TAC的gmac4函数,进行多轮DES加密,流程图如下:
这里还有两个辅助函数,XOR异或和padding填充数据函数:
运行这个脚本,最后初始化圈存命令发出去之后,会返回一个随机数,然后用des.exe去生成过程密钥,进而生成mac1,自己手动验证下,然后继续生成mac2,作为数据一部分放到仿真器运行返回给卡片,卡片就会去验证mac2,验证通过就返回4byte数据的tac码给终端。详细过程代码和注释都说得比较清楚了。
另外,如果没有读卡器和卡片的话,只能在eclipse执行JCOP的仿真器,所以就需要把自己当做终端和主机,去手动产生或验证MAC/TAC值,然后圈存和消费命令都是要根据这些手动生成的值去补充命令的某一块,因为这些值/过程密钥牵涉到随机数或者就是由随机数衍变而来,所以它是变化的,每次仿真都需要自己手动去算并替换命令,这个是比较费时间的,我感觉应该能写一些诸如python的脚本去自动执行测试,而不用自己一个个去输入输出这么麻烦。下面是一些指令,有一些输入数据或一些密钥直接复制到des.exe就好了,另外一些需要根据des.exe生成的结果来填充: