先来看看流程图:
会发现与圈存的流程大致差不多,只不过有一个很大的差别就是mac值的生成,与圈存不同的是,消费流程中终端首先给卡片发送消费初始化命令,卡片收到命令之后并不会产生mac1的值,而只是产生一个伪随机数返回给终端,然后终端收到返回数据之后,再用这个伪随机数去产生过程密钥,进而产生mac1值,然后将这个mac1的值附带在消费命令中发给卡片,卡片收到之后,验证mac1并产生mac2和TAC的值返回给终端。上一篇忘了说MAC和TAC是什么东西,这里补充下:
其实跟计算机网络安全里面的“数据加密&&数字签名”的模式很相像,一个是内容的加密和验证,也就是信息的私密性,一个是内容完整性的验证,也就是验证发送接收方是不是真正的那个人(数字签名),没有被冒充或伪造什么的。
然后来看看消费的具体过程:
注意无论是上一篇的圈存还是这篇消费,最后返回的TAC码或者MAC码,终端都会进行验证的,所以仿真的时候也需要自己手动进行验证,不然到时候接上读卡器运行,可能会报错出bug!这里牵涉到一个脱机交易序号和联机交易序号,圈存是用联机序号,消费是用脱机序号,为什么?据TA说因为圈存需要在系统的数据库里面把你的余额的值修改掉,需要联机,而消费则脱机,脱机为何?我个人的理解是可以把消费之后的余额增减直接先反映到卡片中,当卡片再次接入在线系统时,再从卡片调入记录从而去修改系统数据库里面的个人余额数据。然后为什么消费和圈存中mac1等等的生成方式不同或者说推迟了或者说生成方不同了,TA说这是因为数据的流向问题,我个人的理解是:消费是你(终端)要拿我(卡片)的钱,那我当然要先验证你(终端)的身份,所以终端你先给我生成一个mac1,让我来验证你的身份再说。而圈存则是你(终端)要给我(卡片)存钱,那我当然是来者不拒多多益善啦,所以我来先产生mac1自表身份,你快来给我存钱吧。
在说代码之前,先把余额查询的过程也先说完:
对,余额查询就是这么简单。
然后,上消费过程的代码:
同样是先通过INS值判断是什么命令:
然后执行消费初始化或者消费或者余额查询的函数:
继续跳转到辅助函数: 然后里面的gmac4和XOR或者生成过程密钥的函数用的跟圈存的都是一样的。
然后和上一篇圈存的一样,执行仿真,自己手动验证相应的mac值或TAC值,圈存或消费的仿真时如果想省略生成过程密钥这步的手动验证(确认代码这步没问题),那可以让卡片返回数据的时候直接把过程密钥甚至mac值这些都给返回回来(注意需要修改papdu.le的值,因为我的代码实现中是完全按照papdu.le的值来返回多少byte的数据),这样手动验证就更快了,当然,在接到读卡器验收时,记得实现把相应的测试代码注释掉,把papdu.le等等的值改成正常的。
这些都搞定之后,就可以去验收了。
最后,想说,哎呀,用csdn博客来发布项目有些耗时啊,特别是没办法把整个文件放上来,目前正准备着手学习github,看起来那个会更方面管理项目,不过csdn的作用就是这样吧,你发布一些学习心得就好了,要想记录项目进展的话,有别的工具,例如github。