hce tutorial
TRANSCRIPT
![Page 1: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/1.jpg)
HCE tutorialA simple wallet
By Jensen
![Page 2: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/2.jpg)
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
![Page 3: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/3.jpg)
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
![Page 4: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/4.jpg)
Application protocol data unit (APDU) format
Source: http://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit
![Page 5: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/5.jpg)
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>
![Page 6: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/6.jpg)
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>
![Page 7: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/7.jpg)
APDU command list
• Applet AID • Add money• Sub money• Check balance
![Page 8: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/8.jpg)
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)
};
![Page 9: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/9.jpg)
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;
}
![Page 10: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/10.jpg)
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;
}
![Page 11: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/11.jpg)
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;
}
![Page 12: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/12.jpg)
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;
}
![Page 13: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/13.jpg)
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;
}}
![Page 14: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/14.jpg)
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};
![Page 15: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/15.jpg)
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("");
}
![Page 16: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/16.jpg)
Demo
• Expectation output SelectAID 9000addMoney 900028subMoney 010200check balance 900028
![Page 17: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/17.jpg)
Seek-for-android
https://code.google.com/p/seek-for-android/
![Page 18: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/18.jpg)
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
![Page 19: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/19.jpg)
![Page 20: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/20.jpg)
AndroidManifest.xml
• <application• Add
<uses-library android:name="org.simalliance.openmobileapi" android:required="true" />
• <manifest• Add
<uses-permission android:name="org.simalliance.openmobileapi.SMARTCARD" />
![Page 21: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/21.jpg)
Register SEService
• Abstract function
![Page 22: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/22.jpg)
Binding SEService
• protected void onCreate(Bundle savedInstanceState) {
![Page 23: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/23.jpg)
Connection to SIM (secure element)
![Page 24: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/24.jpg)
Send APDU
![Page 25: HCE tutorial](https://reader030.vdocuments.pub/reader030/viewer/2022020208/55c9a5cdbb61eb024c8b4741/html5/thumbnails/25.jpg)
Face a problem
• Execution result • Reader openSession: service session is null.
• Unfortunately, we guess current open mobile API that doesn’t support HCE.