前言:现在工作的主要内容是关于SDK相关方面开发,而现在的公司的业务绝大多数是关于OpenMobileAPI相关。所以工作的内容就是做关于智能卡相关的SDK项目,写下这篇文章是对近一年工作的总结也是一种记录。自己认识的不足与可能存在的错误,权当是学艺不精吧!
OMA是什么?
开放移动联盟 (OMA) 是一个为移动电话行业开发开放标准的标准机构。它不是像国际电联这样正式的政府赞助的标准组织,而是行业利益相关者就产品和服务的通用规范达成一致的论坛。
维基百科关于OMA
simalliance官网
GitHub地址
涉及场景及用途
在Android客户端主要涉及手机、Sim卡,或者其他一些带有SE安全芯片的设备。其主要应用场景是城市公交、地铁、门禁、或者是需要用到身份认证的且对安全级别有一定要求的业务。
现在智能手机上手机自带的一些交通卡方案,通过NFC进行地铁、公交、门禁等使用。其中读取的安全模块有两种,一种是eSE,也就是手机内嵌安全芯片。另外一种就是通过读取卡槽中的SIM卡上内嵌的安全芯片。这些安全芯片有独立内存、计算能力等可以进行Applet安装与个人化等一些列操作。
特别说明
特别需要说明的一点是,在Android P以后,谷歌将此API的实现纳入官方API中。所以在Android P之前需要外部引入org.simalliance.openmobileapi.jar包才能使用相关功能。Android P及以后的版本可以直接从android.se.omapi位置导入相关类。
使用过程
1.获得SEService对象;
//在org.simalliance.openmobileapi.SEService里获取
SEService mSEService = new SEService(Context context, SEService.OnConnectedListener listener);
//在android.se.omapi.SEService里获取
SEService mSEService = new SEService(Context context, Executor executor, SEService.OnConnectedListener listener);
//传入的参数略有不同。
2.通过获得的SEService对象得到Reader,既mSEService.getReaders();
Reader[] readers = mSEService.getReaders();
//获得的是一个Reader[]在这里就可以对要操作的不用种类的SE安全模块进行区分了。
String readerName = reader.getName();
//可以获取本reader的名字进而选自自己所做业务所需reader类型。
//需要注意的是
boolean b = reader.isSecureElementPresent();
//可以获取当前选择的reader是否可用,之所以需要进行判断是因为,在某些情况下卡是无法访问的。
//比如在遇到AccessControl权限问题是就是无法访问。这是因为所选。
3.通过选择的Reader获取Session,既reader.openSession();
Session mSession = reader.openSession();
4.Session开通道,也就是访问模块中指定的某些区域。
Channel mChannel = mSession.openLogicalChannel(byteAid);
//注意:这里进行开通道所传的参数不是字符串而是一个十六进制byte[],
//在做这个操作时的byte[]就是访问安全域或者是SE上应用的id。
//api使用的是十六进制byte[],也就是APDU,最小指令单元。
//为了方便开发时对所操作的指令进行查看,一般都是指令String,所以需要byte[]与String之间的切换。
5.进行指令交互,将指令依次传到所访问的模块或应用里,交给SE处理。
byte[] byteRapdu = mChannel.transmit(byteCommand);
//这里同Session开通道一样所需要的都是byte[],同样卡片吐回的也是byte[]。
//然后就是根据自己业务需要对所返回的APDU进行分析处理。
6.在一个业务完成之后需要进行关闭通道操作。
mChannel.close();
mSession.close();
//开通道时有指定id进行操作,关闭时只需要将之前的channel和session进行关闭就好。
//系统会自动关闭当前开启的通道。
//之所要做这一步操作是因为在本次业务完成之后,如果需要进行选择别的通道进行相应业务,
//而这时如果没有关闭的话会导致新的通道无法打开等异常。
7.全部业务或者是程序退出时进行SEService释放
mSEService.shutdown();
//这一步SEService释放不建议在小业务完成时就进行释放,因为这样会面临频繁的服务连接。
以上就是OMA的简要使用过程。总结一句话就是开通道、传指令、关通道。
注意事项
1.关于APDU
在进行APDU指令交互的过程中返回的APDU指令是由多部分组成,对于客户端需要注意的是最后四位也就是SW,状态字。状态字是对所传到卡里边的APDU处理之后的一个响应状态代码。
常见APDU响应状态字SW
2.关于AccessControl权限错误,无法访问所指向的卡。
出现这种错误的原因是因为,在访问卡的时候没有相应的访问卡的权限。这是一种卡应用保护机制,不是所有应用(Android APP)都可以访问卡里边某些应用(卡应用Applet)。
有些卡是AC全开放,也就是只要通过OMA就可以访问这张卡。有些是AC指定开发,这就需要在发卡的时候提前在卡里写入访问者的Hash签名值,这样在访问卡时才能进行顺利访问。
最后可以访问我的github里边有封装好的OMA使用:
ShinlookerGitHub-SmartCard
如果想了解更多关于OMA卡相关,可以下载GP规范中文版。里有关于卡的全面介绍与更详细的说明。
GP卡开发规范说明书_中文版
以上便是OMA基本的使用逻辑与注意事项,有很多不足请多多指教。
------咱们来日方长。
网友评论