【译】基于主机的卡仿真(Host-based Card Emulation)
基于主机的卡仿真(Host-based Card Emulation)
能提供NFC功能很多Android手机已经支持NFC卡模拟。在大多数情况下,该卡是由设备中的单独的芯片仿真,所谓的安全元件。由无线运营商提供了许多的SIM卡还包含一个安全元件。
安卓4.4引入卡仿真的附加方法,该方法不涉及安全元件,称为基于主机的卡模拟。这允许任何Android应用程序来模拟卡,并直接与NFC读取器。本文档介绍了如何基于主机的卡仿真( HCE )适用于Android和如何使用这种技术开发的应用程序,模拟的NFC卡。
带安全元件的卡仿真(Card Emulation with a Secure Element)
当采用安全元件提供的NFC卡仿真,要被仿真的卡是通过Android应用程序配置到该设备上的安全元件。然后,当用户将设备放在一个NFC终端上,在设备安卓设备上的NFC控制器转发所有数据直接从读卡器到安全元件。图1示出了这一概念。
图1.卡仿真与安全元件
安全元件本身进行与NFC终端的通信,安卓应用程序并没有参与通信,通信结束后,安卓应用程序可以直接查询安全元件的通信状态,并通知用户。
基于主机的卡仿真(Host-based Card Emulation)
当使用基于主机的卡仿真模拟的NFC卡,这些数据被传输到运行在安卓应用程序上的主机CPU,而不是NFC协议的帧传输到安全元件上,图2说明了如何基于主机的卡仿真
图2,NFC卡仿真没有安全元件。
支持NFC卡和协议(Supported NFC Cards and Protocols)
NFC标准提供了许多不同协议的支持,并且不同类型的卡可以仿真。
安卓4.4支持现在在市场上普遍的许多协议,许多现有的非接触卡是基于这些协议,如非接触式支付卡。这些协议也被目前市场上许多NFC读卡器所支持,包括Android NFC设备充当读卡器(见IsoDep类)。这使您可以构建和只使用Android的设备周围HCE部署一个终端到终端的NFC解决方案。
具体来说,安卓4.4支持模拟卡是基于NFC-Forum的ISO-DEP规范(基于ISO / IEC 14443-4)和过程应用协议单元(APDU)在ISO / IEC 7816-4规范中定义,Android的授权只在NFC-A(ISO-IEC 14443-3 A型)技术上仿效ISO-DEP。支持NFC-B(ISO/IEC14443-4类型B)的技术是可选的。所有这些规范的分层显示在图3中。
图3.安卓的HCE协议栈
HCE服务
在安卓上HCE架构师基于安卓的服务组件(称为“HCE services”)。一个服务的主要优点是,运行在后台没有任何用户界面。对于许多HCE应用这是很适合的,如忠诚或公交卡,用户不需要启动应用程序来使用它,相反,NFC读卡器启动相应的服务(如果尚未运行),并在后台执行通信,当然,你可以自由地从服务启动额外的用户界面(如用户通知),如果是有意义的。
服务选择(Service selection)
当用户点击一个设备的NFC读卡器,安卓系统需要知道NFC读卡器实际上想要那些服务通信,这就是ISO / IEC 7816-4规范进来:它定义了一种方法来选择应用,围绕应用ID(AID )为中心。一个AID最多由16个字节,如果你仿真卡用一个现有的NFC读卡器设备,这些读卡器都在寻找通常是众所周知的公开注册的(例如如Visa和MasterCard的AIDS)。
如果你想要为了你的应用程序部署新的读卡器设备,你需要注册自己的AID(s),AIDs注册程序在ISO / IEC 7816-5规范中定义。谷歌建议注册一个AID按7816-5 ,如果你正在部署为Android一HCE应用程序,它会避免与其他应用程序冲突。
AID组(AID groups)
在某些情况下, HCE服务可能需要注册多个设备,以实现一个特定的应用程序,它需要确保它是默认的处理程序,对于所有的这些AIDs(如在一个组的一些AIDs到其他的服务)。
一个AID组是一个AIDs清单,应视为属于在一起的操作系统,对于一个组的所有AID,安卓保证以下几点:
*该组的所有AIDs能被连接到这个HCE 服务上
*本组中没有AIDs连接到这个HCE服务上(例如,因为用户首选了其他的服务,这个服务请求了在你的组里的一个或多个AIDS)
换句话说,没有中间状态,中间状态指的是组中的一些AIDs被连接到一个HCE服务中,一些连接到其他的HCE服务中。
AID组和类别(AID groups and categories)
每个AID组能够和一个类别关联起来,这样就允许安卓把HCE服务按照类别组织在一起,而这又使用户可以在类级别而不是AID级别设置的默认值。一般情况下,避免在你的应用中的任何面向用户部分提及AIDs:AIDs对于普通用户而言没有意义的。
安卓4.4支持两种类别:CATEGORY_PAYMENT(包括行业标准的支付应用程序)和CATEGORY_OTHER (所有其他HCE应用程序) 。
注意:在CATEGORY_PAYMENT类别中仅有一个AID组可在系统中的任何给定时间被激活。通常情况下,这将是一个应用程序,解析主要的信用卡支付protcols并可以在任何商家合作。
对于闭环支付应用程序,只能在一个商家(如储值卡) ,你应该使用CATEGORY_OTHER 。在这一类的AID组可以始终处于活动状态,并且通过NFC读写器中的AID选择,如果有必要可以优先考虑。
实现一个HCE服务(Implementing an HCE Service)
要使用基于主机的卡仿真模拟的NFC卡,您需要创建一个处理NFC通信服务组件。
检查HCE支持
您的应用程序可以检查设备是否支持HCE通过检查FEATURE_NFC_HOST_CARD_EMULATION功能。您应该使用<uses-feature>标记在你的应用程序的清单中声明你的应用程序使用HCE功能,以及它是否是必需的应用程序功能或没有。
服务实现
安卓4.4自带的,可以用来作为实现HCE服务的基础便利服务类:HostApduService类。因此,第一步是要继承HostApduService 。
1 public class MyHostApduService extends HostApduService { 2 @Override 3 public byte[] processCommandApdu(byte[] apdu, Bundle extras) { 4 ... 5 } 6 @Override 7 public void onDeactivated(int reason) { 8 ... 9 } 10 }
HostApduService 声明了两个需要重写和实现的抽象方法,如上面代码所示。
processCommandApdu ()被调用当一个NFC读卡器发送一个应用协议数据单元(APDU)到你的服务里。APDU是在ISO / IEC 7816-4规格中定义。APDU是应用程序级的数据包被用来NFC读卡器与你的HCE服务交换。应用层协议时半双工:在NFC读卡器将发送给您一个APDU命令,它会等待你的发送一个响应APDU。
注:ISO / IEC 7816-4规范还定义了多个逻辑通道,在那里你可以有不同的逻辑通道多路并行的APDU交换的概念。Android的HCE但是实现只支持一个单一的逻辑通道,所以有APDU的只有单线程交流。
正如前面提到的,Android设备使用AID确定读卡器想要与哪个HCE服务通信,通常情况下,NFC读卡器发送到您的设备的第一个APDU是一个“SELECT AID ” APDU,这个APDU包含了NFC读卡器想要通信的AID,安卓从APDU提前AID,解析到HCE服务,然后转发该APDU的解决服务。
您可以通过返回从processCommandApdu响应APDU (的字节)发送一个响应APDU。请注意,这个方法就会被调用应用程序的主线程,它不应该被阻塞。所以,如果你不能计算,并立即返回一个响应APDU ,则返回null 。你可以在另外的线程做必要的工作。并使用在HostApduService类中定义的sendResponseApdu ( )方法发送响应。
安卓将继续转发新的APDU从读卡器到你的服务。直至:
1、NFC读卡器发送另一个“SELECT AID ” APDU ,其中操作系统解析到不同的服务;
2、在NFC读卡器和设备之间的NFC链路断开。
在这两种情况下,你的类的onDeactivated ( )执行被调用的参数表明这两者的发生。
如果您正在使用现有的读卡器设备,你需要在你的HCE服务里面实现现有的读卡器期望的应用级协议。
如果你要部署你控制的新的读卡器设备,你可以定义你自己的协议和APDU序列。一般来说尽量限制的APDU的数量和需要交换的数据的大小:这可以确保您的用户将只需要保持他们的设备在NFC读卡器很短的时间。一个上限大小为1K的数据,通常可在300毫秒交换。
服务清单申报和AID注册(Service manifest declaration and AID registration)
您的服务必须在manifest像往常一样进行声明,但一些额外的块必须被添加到服务声明。
首先,要告诉大家,这是一个HCE服务实现HostApduService接口的平台,为您服务声明必须包含一个意图过滤器的SERVICE_INTERFACE action。
另外,告诉平台,AIDs被服务所要求,一个SERVICE_META_DATA <meta-data>标签必须包含在服务的声明,指向与有关HCE服务的附加信息的XML资源。
最后,你必须设置android:exported属性为true,在你的服务声明中需要 "android.permission.BIND_NFC_SERVICE"权限,前者保证了服务可以通过外部应用程序绑定到。后者则强制要求持有的“ android.permission.BIND_NFC_SERVICE ”只允许外部应用程序可以绑定到你的服务。由于“ android.permission.BIND_NFC_SERVICE ”是一个系统的权限,这有效地强制执行,只有Android操作系统可以绑定到你的服务。
这里有一个HostApduService清单声明的例子:
<service android:name=".MyHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"> <intent-filter> <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/> </intent-filter> <meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/apduservice"/> </service>
这个元数据标签指向一个apduservice.xml文件。如下:
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/servicedesc" android:requireDeviceUnlock="false"> <aid-group android:description="@string/aiddescription" android:category="other"> <aid-filter android:name="F0010203040506"/> <aid-filter android:name="F0394148148100"/> </aid-group> </host-apdu-service>
该<host-apdu-service>标签必须包含一个含有可能在用户界面显示该服务的用户友好描述一个<android:description>属性。该requireDeviceUnlock属性可以用来指定该设备必须解锁之前,这项服务可以被调用来处理APDU的。
<host-apdu-service>必须包含一个或多个<aid-group>标记。每个<aid-group>标签要求:
*包含一个android:description属性,包含一个用户友好描述适,合在UI显示description属性。
*用android:category 属性设置为显示类的AID组所属,如通过CATEGORY_PAYMENT或CATEGORY_OTHER定义的字符串常量。
*每个<aid-group>必须包含一个或多个<aid-filter>标签,其中每个都包含一个单一的AID,AID必须以十六进制格式指定,并包含偶数个字符。
AID冲突的解决(AID Conflict Resolution)
多个HostApduServicez组件可以安装在一台设备上并在同一AID可以由一个以上的服务进行注册。安装平台解决AID冲突依赖于AID属于哪个类别。每个类别都可能有不同的冲突解决策略。
例如,对于某些类别(如付款) ,用户可能能够在Android用户界面的设置选择默认服务。对于其他类别的政策,就应该总是问哪个服务是在发生冲突时要调用的用户。要查询某一类的冲突解决策略,请参阅getSelectionModeForCategory ( ) 。
检查如果你的服务是默认(Checking if your service is the default)
应用程序可以检查自己的HCE服务是否是某一类的默认服务使用isDefaultServiceForCategory (单元名,字符串)的API 。
如果你的服务是不是默认的,你可以要求它作出的默认值。见ACTION_CHANGE_DEFAULT 。
支付应用(Payment Applications)
安卓认为,有“payment”类别的一个已宣布的AID组作为支付应用服务。而Android 4.4版本包含所谓的“挖掘与支付”顶层设置菜单项,其中列举了所有此类支付应用程序。在这种设置菜单,用户可以选择当一个支付终端被触发,将调用默认的支付应用。
支付应用程序所需的资源
为了提供更视觉吸引力的用户体验,HCE支付应用程序必须为他们的服务提供一个额外资源:所谓服务的一面旗帜。
该资资源大小应260x96 DP ,并且可以在你的元数据的XML文件中加入了android指定: apduServiceBanner属性到<host-apdu-service>标记,它指向可绘制资源。一个例子如下所示:
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/servicedesc" android:requireDeviceUnlock="false" android:apduServiceBanner="@drawable/my_banner"> <aid-group android:description="@string/aiddescription" android:category="payment"> <aid-filter android:name="F0010203040506"/> <aid-filter android:name="F0394148148100"/> </aid-group> </host-apdu-service>
屏幕关闭和锁屏行为(Screen Off and Lock-screen Behavior)
当该设备的屏幕被关闭时,目前安卓实现NFC控制器和应用处理器完全关闭,当屏幕关闭的时候,HCE服务将要不起作用。
然而HCE服务可以从lock-screen功能:这是由android:< host-apdu-service >标记的requireDeviceUnlockattribute HCE服务。默认情况下,设备不需要解锁,你的服务将调用即使设备被锁定。
如果你对你的HCE服务设置了android:requireDeviceUnlock 属性为TURE,安卓将提示用户解锁设置,当你点击一个NFC读卡器来选择一个AID为了解决你的服务。解锁后,安卓将显示一个对话框提示用户再次点击完成通信,这是必要的,因为用户可能已经远离NFC读卡器设备为了解锁它。
与安全元件共存卡(Coexistence with Secure Element Cards)
本节感兴趣的开发人员已经部署的应用程序依赖于一个安全元件卡模拟,安卓的HCE实现并行设计工作与其他的方法实现卡模拟,包括使用安全元件。
注意:安卓不提供APIs对于直接与一个安全元件直接通信。
这种共存是基于一个原则称为:“AID routing”:NFC控制器保持一个路由表,由一个(有限)的路由规则列表,每个路由规则包含一个AID和目的,目标可以是主机CPU ( Android应用程序正在其上运行) ,或连接的安全元件。
当NFC读卡器发送一个含有“SELECT AID”的APDU,NFC控制器解析它并检查这个AIDs是否与它的路由表中的AID匹配,这个APDU和跟随它之后的所有APDU将要发送到与这个AID相关联的的目的地。直到另一个“SELECT AID ” APDU被接收或在NFC链路断开。
注意:而ISO / IEC 7816-4定义“部分匹配”的概念,这是目前没有被HCE的Android设备支持。
这种体系结构示于图4中。
图4.安卓操作安全元件盒host-card仿真
NFC控制器通常还包含一个默认的APDUs路由,如果一个AID在路由表中没有发现,这个默认的路由表被使用。从安卓4.4开始,默认的路由需要设置到主机CPU中。这意味着,路由表通常只包含需要到一个安全元件的AIDs。
实现一个HCE服务或使用一个安全元件的Android应用程序不必担心配置路由表,它由安卓自动实现。安卓仅仅需要知道哪个AIDs可以通过HCE服务处理以及哪些可以通过安全元件来处理。根据该服务的安装和用户已经配置为优选的,路由表被自动配置。
我们已经描述了如何声明AIDs对于HCE服务,接下来部分解释对于用一个安全元件的卡仿真的应用如何声明AIDs.
安全元件AID注册(Secure element AID registration)
使用一个安全元件来卡仿真的应用程序可以再其清单中声明一个所谓的“off host service”,这种服务的声明几乎和声明一个HCE服务一样,不同点:
*在意向过滤器中使用的动作必须设置为SERVICE_INTERFACE 。
*元数据的name属性必须设置为SERVICE_META_DATA
*元数据的XML文件必须使用<offhost-apdu-service>根标签。
<service android:name=".MyOffHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"> <intent-filter> <action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"/> </intent-filter> <meta-data android:name="android.nfc.cardemulation.off_host_apdu_ervice" android:resource="@xml/apduservice"/> </service>
相应的apduservice.xml文件注册AID的一个例子:
<offhost-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/servicedesc"> <aid-group android:description="@string/subscription" android:category="other"> <aid-filter android:name="F0010203040506"/> <aid-filter android:name="F0394148148100"/> </aid-group> </offhost-apdu-service>
android:requireDeviceUnlock 属性不适合于关主机服务,因为主机CPU不参与交易。因此不能防止安全元件从执行交易时,该设备已被锁定。
android:apduServiceBanner 属性必须被支付应用的关主机服务使用,以及为了能够选择作为默认的支付应用。
关闭主机服务调用(Off host service invocation)
Android的本身永远不会启动或绑定到声明为“关主”的服务。这是因为实际的交易由安全元件,并且不执行安卓服务本身。这个服务声明只是允许应用程序在安全元件上注册AIDs。
HCE和安全(HCE and Security)
HCE架构本身提供一个核芯片的安全性:因为你的服务是由BIND_NFC_SERVICE系统权限保护,只有操作系统可以结合并与您的服务进行通信。这可以确保您收到任何APDU实际上是由操作系统从NFC控制器收取的。你回发的任何APDU仅会去操作系统,这反过来又直接转发的APDU到NFC控制器。
核心剩下的部分是,你得到你的数据,你的应用程序发送到NFC阅读器,这是故意去耦在HCE设计:它并不关心其中的数据从何而来,它只是确保它安全地运到了NFC控制器和出了NFC读写器。
为安全地存储和检索您想要发送的数据从你HCE服务,你可以,例如,依赖于Android应用程序沙箱,隔离应用程序从其他应用程序的数据。为更多的细节在Android上安全、阅读安全提示 .
协议参数和细节(Protocol parameters and details)
这部分是对于开发人员,想了解协议参数HCE设备使用期间防撞和NFC的激活阶段协议。这允许建立一个基础设施,与安卓HCE设备兼容。
Nfc-A(ISO / IEC 14443 A型)协议防撞和激活(Nfc-A (ISO/IEC 14443 type A) protocol anti-collision and activation)作为Nfc-A协议的一部分,激活、多帧交换。
交换的第一部分,HCE设备将要生成它自己的UID,HCE设备应被假定为有一个随机的UID,这意味着,在每一个抽头,即呈现给读卡器的UID将是随机产生的UID。正因为如此, NFC读写器不应该依赖于HCE设备身份验证或识别的一种形式的UID 。
在NFC读取器可以通过发送SEL_REQ命令后选择HCE设备。HCE的SEL_RES响应设备将至少有6位(0 x20),表明该设备支持ISO-DEP。SEL_RES可能集中注意,其他部分,例如支持NFC-DEP指示(p2p)协议。因为其他可能,想要与HCE设备交互的读卡器应该显式地检查第六位,和没有比较完整的SEL_RES 0x20的值。
ISO-DEP激活(ISO-DEP activation)
之后, NFC -A协议被激活时,ISO -DEP协议激活由NFC读取器启动。它发出一个"RATS" (Request for Answer To Select) 命令,RATS响应,该ATS ,完全由NFC控制器产生,而不是由HCE服务配置。然而, HCE实现都必须满足ATS服务响应NFC格式的要求,因此NFC读写器可以对这些参数按照任何HCE设备NFC规定被设置计数。
下面的部分提供了一个HCE设备上提供的NFC控制器的ATS响应的单个字节的详细信息:
TL:ATS响应的长度,表示的长度不能大于20个字节。
T0:5、6和7位必须在所有的HCE设备设置,显示TA(1), TB(1) 和 TC(1) 包含在ATS响应中。1到4位表示FSCI,编码的帧的最大尺寸,对HCE设备FSCI的值必须是0H和8h之间。
T(A ) 1 :读写器和仿真器之间定义了比特率,以及他们是否可以不对称。没有比特率要求或担保HCE设备。
T( B) 1 :位1到4表示启动帧保护时间整数( SFGI ) 。在HCE设备, SFGI必须< = 8小时。位5至8表示帧等待时间整数( FWI)的原理和代码的帧等待时间( FWT ) 。在HCE设备, FWI必须< = 8小时。
T(C)1:第5位表示为“高级协议功能”的支持。 HCE设备可能会或可能不支持“高级协议功能” 。位2表示为DID支持。 HCE设备可能会或可能不支持DID 。位1表示的NAD支持。 HCE设备必须不支持NAD和设置位1至零。
历史字节: HCE设备可以返回多达15个历史字节。 NFC读写器愿与HCE服务互动不应对历史字节或它们的存在内容的假设。
注意许多HCE设备可能符合协议要求支付网络联合EMVCo指定在“非接触通信协议规范。特别是:
FSCI在T0必须是2小时和8小时之间。
T(A ) 1必须设置为0x80 ,表示只支持106 kbit / s的比特率,并且不支持阅读器和仿真器之间的不对称比特率。
FWI在T( B) 1必须< = 7小时。
APDU的数据交换(APDU data exchange)
如前所述, HCE实现只支持一个单一的逻辑通道。尝试选择不同的逻辑通道的应用将不是一个HCE设备上工作。