HCE tutorial

Post on 11-Aug-2015

120 views 4 download

Transcript of HCE tutorial

HCE tutorialA simple wallet

By Jensen

Outline

• Running environment • APDU format• Registration HCE service • Registration AID• APDU command list• Applet AID define • APDU command define• processCommandApdu• Card Reader side, APDU define • Card Reader side, send APDU• Seek-for-android

Running environment

• Card reader side • Java 8 (jre1.8.0.25)

• Android side• Android 4.4.2• Infocus M510

• IDE • Eclipse 4.4.1

• Code download• https://github.com/jensen0915/HCE_simple_wallet• https://github.com/jensen0915/HCE_simple_wallet_carder

Application protocol data unit (APDU) format

Source: http://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit

Registration HCE service

<service android:name="hce_demo.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>

Registration AID

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

<aid-group android:category="other" android:description="@string/aiddescription" > <aid-filter android:name="F0394148148100" /> </aid-group>

</host-apdu-service>

APDU command list

• Applet AID • Add money• Sub money• Check balance

Applet AID define

private static final byte[] AID_SELECT_APDU = {(byte) 0x00, // CLA (class of command)(byte) 0xA4, // INS (instruction); A4 = select(byte) 0x04, // P1 (parameter 1) (0x04: select by name)(byte) 0x00, // P2 (parameter 2)(byte) 0x07, // LC (length of data) (byte) 0xF0, (byte) 0x39, (byte) 0x41, (byte) 0x48, (byte) 0x14, (byte) 0x81, (byte) 0x00,(byte) 0x00 // LE (max length of expected result, 0 implies 256)

};

APDU command define

private boolean selectAddMoneyApdu(byte[] apdu) { //(byte) 0x80, // CLA//(byte) 0x01, // INS//(byte) 0x00, // P1//(byte) 0x00, // P2return apdu.length >= 2 && apdu[0] == (byte) 0x80 && apdu[1] == (byte) 0x01 && apdu[2] == (byte) 0x00 && apdu[3] == (byte) 0x00;

}

private boolean selectDebitApdu(byte[] apdu) { //(byte) 0x80, // CLA//(byte) 0x02, // INS//(byte) 0x00, // P1//(byte) 0x00, // P2return apdu.length >= 2 && apdu[0] == (byte) 0x80 && apdu[1] == (byte) 0x02 && apdu[2] == (byte) 0x00 && apdu[3] == (byte) 0x00;

}

APDU command define (cont.)private boolean selectCheckBalanceApdu(byte[] apdu) {

//(byte) 0x80, // CLA//(byte) 0x03, // INS//(byte) 0x00, // P1//(byte) 0x00, // P2return apdu.length >= 2 && apdu[0] == (byte) 0x80 && apdu[1] == (byte) 0x03 && apdu[2] == (byte) 0x00 && apdu[3] == (byte) 0x00;

}

processCommandApdu

@Overridepublic byte[] processCommandApdu(byte[] apdu, Bundle extras) {

String inboundApduDescription;byte[] responseApdu;

if (Arrays.equals(AID_SELECT_APDU, apdu)) {inboundApduDescription = "Application selected";Log.i("HCEDEMO", inboundApduDescription);byte[] answer = new byte[2];answer[0] = (byte) 0x90;answer[1] = (byte) 0x00;responseApdu = answer;return responseApdu;

}

else if (selectAddMoneyApdu(apdu)) {Log.i("HCEDEMO", "ADD selected");int length = apdu[4];System.out.println("length = " + length);byte[] answer = new byte[3];

walletBalance = (byte)(walletBalance + apdu[5]);answer[0] = (byte) 0x90;answer[1] = (byte) 0x00;answer[2] = walletBalance;responseApdu = answer;return responseApdu;

}else if (selectDebitApdu(apdu)) {

Log.i("HCEDEMO", "Debit selected");int length = apdu[4];System.out.println("length = " + length);byte[] answer = new byte[3];

// balance can not be negativeif ( (byte)( (byte) walletBalance - apdu[5]) < (byte) 0 ) { answer[0] = (byte) 0x01;answer[1] = (byte) 0x02;responseApdu = answer;return responseApdu;

}

else if (selectCheckBalanceApdu(apdu)) {

Log.i("HCEDEMO", "check balance selected");byte[] answer = new byte[3];answer[0] = (byte) 0x90;answer[1] = (byte) 0x00;answer[2] = walletBalance;responseApdu = answer;return responseApdu;

}

else {Log.i("HCEDEMO", "Unknown command");byte[] answer = new byte[2];answer[0] = (byte) 0x6F;answer[1] = (byte) 0x00;responseApdu = answer;return responseApdu;

}}

Card Reader side, APDU define

//walletpublic static byte[] SelectAID = new byte[]{(byte) 0x00, (byte) 0xA4, (byte) 0x04, (byte) 0x00, (byte) 0x07,(byte) 0xF0, (byte) 0x39, (byte) 0x41, (byte) 0x48, (byte) 0x14, (byte) 0x81, (byte) 0x00, (byte) 0x00};

public static byte[] addMoney = new byte[]{(byte) 0x80, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x64};

public static byte[] subMoney = new byte[]{(byte) 0x80, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x34};

public static byte[] checkBalance = new byte[]{(byte) 0x80, (byte) 0x03, (byte) 0x00, (byte) 0x00};

Card Reader side, send APDU

public static void main(String[] args) throws UnsupportedEncodingException {TerminalFactory terminalFactory = TerminalFactory.getDefault();try {

for (CardTerminal terminal : terminalFactory.terminals().list()) {System.out.println(terminal.getName());try {

Card card = terminal.connect("*");CardChannel channel = card.getBasicChannel();

System.out.println("SelectAID ");CommandAPDU command = new CommandAPDU(SelectAID);ResponseAPDU response = channel.transmit(command);byte recv[] = response.getBytes();for (int i = 0; i < recv.length; i++) {System.out.print(String.format("%02X", recv[i]));}System.out.println("");

}

Demo

• Expectation output SelectAID 9000addMoney 900028subMoney 010200check balance 900028

Seek-for-android

https://code.google.com/p/seek-for-android/

Install Open Mobile API

• The Eclipse development environment needs to be configured in order to use the official SDK from Google as described in the Google documentation. In addition, the SDK needs to have access to the Open Mobile API addon package.

https://code.google.com/p/seek-for-android/wiki/UsingSmartCardAPI

AndroidManifest.xml

• <application• Add

<uses-library android:name="org.simalliance.openmobileapi" android:required="true" />

• <manifest• Add

<uses-permission android:name="org.simalliance.openmobileapi.SMARTCARD" />

Register SEService

• Abstract function

Binding SEService

• protected void onCreate(Bundle savedInstanceState) {

Connection to SIM (secure element)

Send APDU

Face a problem

• Execution result • Reader openSession: service session is null.

• Unfortunately, we guess current open mobile API that doesn’t support HCE.