Reputation: 41
I try to emulate emv card on Android device. And it will be read on acr1252 over some software. It's work fine, software can read card but identifies like token, but in emv answer I set it like physical card.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.ptks.cardEmulator">
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.nfc.hce" android:required="true" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-feature android:name="android.hardware.nfc" android:required="false" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Android_CardEmulator"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:directBootAware="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/usb_device_filter" />
</activity>
<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" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/apduservice" />
</service>
<service
android:name=".UsbService"
android:enabled="true">
</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/service_description"
android:requireDeviceUnlock="false">
<aid-group
android:description="@string/aid_group_description"
android:category="payment">
<aid-filter android:name="A0000000041010" />
<aid-filter android:name="A0000000031010" />
</aid-group>
</host-apdu-service>
Please, help, how to correct sent that I "use" physical card? Thanks!
P.S. HostApduService:
package com.cardEmulator;
import static com.cardEmulator.MainActivity.changeNfcEnabled;
import android.nfc.cardemulation.HostApduService;
import android.os.Bundle;
import android.util.Log;
public class MyHostApduService extends HostApduService {
private byte[] hexToBinary(String s) {
byte[] data = new byte[s.length()/2];
for( int i=0, j=0;
i<s.length() && j<data.length;
i+=2, j++)
{
if ((byte)Integer.parseInt(s.substring(i, i+2), 16) >=0 && (byte)Integer.parseInt(s.substring(i, i+2), 16)<16)
data[j] = (byte) (0 + (byte)Integer.parseInt(s.substring(i, i+2), 16));
else
data[j] = (byte)Integer.parseInt(s.substring(i, i+2), 16);
}
return data;
}
@Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
Log.d("chrome", "Get command from card: ");
String getReq = "";
for (int i = 0; i<=commandApdu.length-1; i++)
getReq+=String.format("%02x", commandApdu [i]);
Log.d("chrome", getReq);
if (getReq.toLowerCase().contains("00A4040007A00000000".toLowerCase())) {
Log.d("chrome", "Send first answer");
sendResponseApdu(hexToBinary("6F23840E325041592E5359532E4444463031A511BF0C0E610C4F07A00000000410108701019000"));
}
if (getReq.toLowerCase().contains("80a8000002830000".toLowerCase())) {
sendResponseApdu(hexToBinary("771282021980940C0000000000000000000000009000"));
}
Globals.curCard = "5167803202840547";
if (getReq.toLowerCase().contains("00b2000400".toLowerCase()))
sendResponseApdu(hexToBinary("7081A657135167803202840547D24112010000000001960F5A0851678032028405475F24032411305F25031911015F280208045F3401018C279F02069F03069F1A0295055F2A029A039C019F37049F35019F45029F4C089F34039F21039F7C148D0C910A8A0295059F37049F4C088E0E000000000000000042031E031F039F0702FFC09F080200029F0D05B4508400009F0E0500000000009F0F05B4708480009F420209809F4A01829000"));
if (getReq.toLowerCase().contains("00b2011400".toLowerCase()))
sendResponseApdu(hexToBinary("7081A657135167803202840547D24112010000000001960F5A0851678032028405475F24032411305F25031911015F280208045F3401018C279F02069F03069F1A0295055F2A029A039C019F37049F35019F45029F4C089F34039F21039F7C148D0C910A8A0295059F37049F4C088E0E000000000000000042031E031F039F0702FFC09F080200029F0D05B4508400009F0E0500000000009F0F05B4708480009F420209809F4A01829000"));
if (getReq.toLowerCase().equals("80ca9f7f00".toLowerCase()))
sendResponseApdu(hexToBinary( "9F7F08425032729000" ));
return null;
}
@Override
public void onDeactivated(int reason) {
Log.d("chrome", "Communication with the card reader is interrupted!!!");
}
}
Upvotes: 0
Views: 153