让主机卡模拟技术用于支付

5
我已经使用StackOverflow多年了,总是在提问之前就能找到答案,但今天我卡住了。
由于我恰好有一个工作的POS终端(EMV Chip&Pin类型),我想研究主机卡模拟。
终端可以使用最新版本的Tapp,所以我知道终端是好的,我的N7配备了Kitkat,实际上可以进行付款(或者至少终端会发出一系列良好的哔哔声,平板电脑启动了Tapp的注册屏幕)。 因此,我阅读了手册并编写了一堆代码,目的是在我的HostApduService上看到一些东西。 它部分地起作用,因为我可以在平板电脑的Tap&Pay设置中找到我的虚拟“卡”。
但是“支付”部分不起作用:只有来自POS终端的两个高音哔哔声,平板电脑上没有任何内容。我的HostApduService没有被调用。
我尝试了各种不同的AID:真实的和愚蠢的,短的和长的,但都没有效果。
当使用Tapp时,LogCat会显示:
11-17 14:51:47.690: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x18
11-17 14:51:47.690: D/HostEmulationManager(3183): notifyHostEmulationActivated
11-17 14:51:47.690: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x17
11-17 14:51:47.690: D/BrcmNfcJni(3183): RoutingManager::stackCallback: NFA_CE_DATA_EVT; h=0x302; data len=20
11-17 14:51:47.690: D/HostEmulationManager(3183): notifyHostEmulationData
11-17 14:51:47.700: D/HostEmulationManager(3183): Service already bound as payment service.
11-17 14:51:47.700: D/HostEmulationManager(3183): Binding to existing service
11-17 14:51:49.932: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x19
11-17 14:51:49.932: D/HostEmulationManager(3183): notifyHostEmulationDeactivated
11-17 14:51:49.932: E/BrcmNfcNfa(3183): UICC[0x0] is not activated

使用我的代码,LogCat输出为:

11-17 14:41:52.079: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x18
11-17 14:41:52.079: D/HostEmulationManager(3183): notifyHostEmulationActivated
11-17 14:41:52.089: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x17
11-17 14:41:52.089: D/BrcmNfcJni(3183): RoutingManager::stackCallback: NFA_CE_DATA_EVT; h=0x302; data len=20
11-17 14:41:52.089: D/HostEmulationManager(3183): notifyHostEmulationData
11-17 14:41:53.340: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x19
11-17 14:41:53.340: D/HostEmulationManager(3183): notifyHostEmulationDeactivated
11-17 14:41:53.340: E/BrcmNfcNfa(3183): UICC[0x0] is not activated

很明显,我的代码没有让操作系统将HCE意图绑定到我的服务上。为什么呢?
以下是我的清单文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.remolagi.hcetestbanque2"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="19"
    android:targetSdkVersion="19" />

<uses-permission android:name="android.permission.NFC" />

<uses-feature
    android:name="android.hardware.nfc.hce"
    android:required="true" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="net.remolagi.hcetestbanque2.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <service
        android:name=".MyHCEService"
        android:exported="true"
        android:permission="android.permission.BIND_NFC_SERVICE" >
        <intent-filter>
            <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
            <category android:name="android.intent.category.DEFAULT" />
       </intent-filter>

        <meta-data
            android:name="android.nfc.cardemulation.host_apdu_service"
            android:resource="@xml/apduservice" />
    </service>
</application>

</manifest>

我的apduservice.xml:

<?xml version="1.0" encoding="UTF-8"?>

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/servicedesc" 
    android:requireDeviceUnlock="true"
    android:apduServiceBanner="@drawable/payment_banner">
<aid-group android:description="@string/aiddescription"
           android:category="payment">
    <aid-filter android:name="A0000000031010"/>
    </aid-group>
</host-apdu-service>

为了更好的效果,该服务(目前只能看到它记录日志):

package net.remolagi.hcetestbanque2;

import android.nfc.cardemulation.HostApduService;
import android.os.Bundle;
import android.util.Log;

public class MyHCEService extends HostApduService {


    private static final String TAG = "MyHCEService";

    @Override
    public void onDeactivated(int arg0) {

        Log.i(TAG, "OnDeactivated - arg0 : " + String.valueOf(arg0));
        // TODO Auto-generated method stub

    }

    @Override
    public byte[] processCommandApdu(byte[] arg0, Bundle arg1) {

        Log.i(TAG, "Hooza ! processCommandApdu");

        return arg0;
    }

}

如果您对为什么它不起作用有任何想法,我将永远感激。目前我被难住了。

敬礼

Philippe


你是否有这个应用程序的开源版本?或者能否告诉我们进展情况? - MichaelH
5个回答

5

EMV终端首先选择的是PPSE小应用,因此您可以尝试将其添加到您的AID过滤器中:

<aid-filter android:name="325041592E5359532E4444463031"/>

我不知道你为什么想要使用HCE来模拟付款,但这是不会被Visa和MasterCard批准的,因为对于EMV交易,需要将加密密钥存储在安全环境中。在最好的情况下,HCE只能用于卡不在场的交易。

我已经尝试过"2PAY.SYS.DDF01"作为AID,但我会尝试字节版本。这是一个很好的想法。这更像是一项研究努力而不是其他任何事情。我喜欢了解事物的工作原理... - Philippe
我可以向您推荐MasterCard的这个工具:https://www.terminalsimulator.com/ 它非常适合研究工作,因为它可以显示通信的完整日志以及每个步骤的解释。您所需的唯一硬件是PC/SC读卡器。 - Kamen Goranchev
你的建议非常准确。以十六进制格式提供的AID将与NFC绑定。我有点惊讶,因为我原以为Android会管理PPSE的构建,并用apdu_service.xml中提供的AID填充它。谢谢 - Philippe
@KamenGoranchev 这个链接已经失效了:( - Tamim Attafi
@TamimAttafi 抱歉,这是很久以前的事情了 :(. 现在看起来已经变了:http://terminalsimulator.com/ - Kamen Goranchev
@KamenGoranchev,你能帮我们提供一些帮助吗?我们正在尝试制作一个类似于Google Pay的支付应用程序,但我们之前没有使用NFC的经验。我们了解到有关令牌化的内容,但我们正在使用虚拟卡来学习这项技术,那么我们如何使用卡信息而不是令牌进行付款呢? - Tamim Attafi

1

主机APDU服务结构示例:

对于HCE应用程序,包含PPSE AID条目确实是必要的:

apduservice.xml文件:

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/servicedesc"
    android:requireDeviceUnlock="false" >

    <aid-group
        android:category="payment"
        android:description="@string/aiddescription" >

        <!-- Visa Proximity Payment System Environment - PPSE (2PAY.SYS.DDF01) -->
        <aid-filter android:name="325041592E5359532E4444463031" />

        <!-- VISA Debit/Credit (Classic)  -->
        <aid-filter android:name="A0000000031010" />

        <!-- VISA Credit -->
        <aid-filter android:name="A000000003101001" />

        <!-- VISA Debit -->
        <aid-filter android:name="A000000003101002" />

        <!-- VISA Electron (Debit) -->
        <aid-filter android:name="A0000000032010" />

        <!-- V PAY -->
        <aid-filter android:name="A0000000032020" />

        <!-- VISA Interlink -->
        <aid-filter android:name="A0000000033010" />

        <!-- MasterCard PayPass -->
        <aid-filter android:name="A00000000401" />

        <!-- MasterCard Credit -->
        <aid-filter android:name="A0000000041010" />

        <!-- American Express -->
        <aid-filter android:name="A000000025" />

        <!-- BRADESCO -->
        <aid-filter android:name="F0000000030001" />

    </aid-group>

</host-apdu-service> 

1
在2013年,最佳答案说:“我不知道你为什么要用HCE来模拟支付,但Visa和MasterCard永远不会批准这种方式。”那么,MasterCard就不会有官方的SDK来开发HCE支付应用程序了,对吗?你怎么能如此确定呢?对于现在阅读这篇文章的人来说,当然可以开发Android HCE应用程序,MasterCard有大量关于最佳实践的文档。然而,它并不是公开向所有人开放的。我不知道是否有一种方法可以在没有与发行商合作的情况下获得SDK和文档。您可以使用EMVCo Books,这些书籍对公众开放,但仅使用这些指南可能难以实现整个系统。
关于安全环境,例如,RSA公钥是两个大质数的乘积。如果您可以及时找到这些质数,您就可以成为整个世界的主人。但是,根据今天的计算能力,在尝试多年后(取决于密钥大小),您无法找到这些数字,这已经被比本文中某些人更具洞察力的数学家所证明。整个互联网都使用公钥加密,您并不总是需要安全硬件来保护数据的隐私。总会有一种方法,因为您无法达到无限。当您这样做时,它变得有限,这毫无意义,哈哈。
最后,"有人可以在一个没有人知道的地方知道一切"(F.Y.)

0
一个包含PPSE、Mastercard和Visa的列表:
<aid-group android:description="paymentGroup" android:category="payment">  
    <aid-filter android:name="325041592E5359532E4444463031" android:description="ppse"/> 
    <aid-filter android:name="A0000000041010" android:description="MasterCard"/> 
    <aid-filter android:name="A0000000031010" android:description="Visa"/>
</aid-group>

0
我在实验中发现POS设备会尝试选择其支持的卡方案的AID。您可以通过查看诸如“Visa”、“Mastercard”等符号来检查设备上支持的方案。这些方案的AID列表在http://en.wikipedia.org/wiki/EMV页面下方有列出。例如,如果POS支持Mastercard信用卡/借记卡,您可以尝试在apduservice.xml中注册mastercard:A0000000041010作为aid-filter而不注册PPSE的AID。请尝试并告诉我是否有效。
编辑:请注意,我一直在使用Vivo技术的POS读卡器。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接