1

I have been looking in the Global Platform Spec on how to define an APDU for my app which will use Host Card Emulation (HCE). My app is supposed to have one phone behaving like an NFC tag through HCE and another phone acting as the NFC reader. The arbitrary data that i am trying to transfer between the phones is just a simple string containing an ID number, but I'm not really sure how to apply it in the code. I have looked at what the different byte commands mean but I'm really not sure how to apply it.

I think I need to use the STORE DATA command but I'm not sure how to intuitively do it and don't really understand. I am currently looking at the HCE side rather than the reader side.

This is my code so far for the HCE side

public class SecondaryActivity extends HostApduService {

@Override
public void onDeactivated(int reason) {

}

@Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
    String inboundApduDescription;
    byte[] responseApdu;

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

    }
    return commandApdu;
}

private static final byte[] AID_SELECT_APDU = {
        (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
};

private static final byte[] STORE_DATA = {
        (byte) 0x00,
        (byte) 0xA4,
        (byte) 0x04,
        (byte) 0xA5, // forproprietary data according to the spec
        (byte) 0xE2,
        (byte) 0x66, (byte) 0x39, (byte) 0x41, (byte) 0x48, (byte) 0x14, (byte) 0x81, (byte) 0x00,
        (byte) 0x00
};

private static final byte[] INSTALL = {
        (byte) 0x00,
        (byte) 0x00,
};

}

How do I send the data from the HCE phone to the reader phone? What am I missing? What needs to be done?

Michael Roland
  • 39,663
  • 10
  • 99
  • 206
Hazed 2.0
  • 133
  • 2
  • 14

1 Answers1

1

You can define virtually any APDU command for HCE. Only the initial SELECT (by AID) command is required. After that, you can create your own command set (or try to follow ISO/IEC 7816-4 commands) as long as you obey the rules of ISO/IEC 7816 for command/response APDU structure, and stick to valid CLA, INS, and status word values.

Since you only want to transfer an ID, you could send this ID directly in response to the SELECT command:

private static final String ID = "1234567890"

@Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
    byte[] responseApdu = new byte[] { (byte)0x6F, (byte)0x00 };

    if ((commandApdu != null) && (commandApdu.length >= 4)) {
        if ((commandApdu[0] == (byte)0x00) && (commandApdu[1] == (byte)0xA4) && (commandApdu[2] == (byte)0x04) && (commandApdu[3] == (byte)0x00)) {
            Log.i("HCEDEMO", "Application selected");

            byte[] id = ID.getBytes(Charset.forName("UTF-8"));
            responseApdu = new byte[id.length + 2];
            System.arraycopy(id, 0, responseApdu, 0, id.length);
            responseApdu[id.length] = (byte)0x90;
            responseApdu[id.length + 1] = (byte)0x00;
        }
    }
    return responseApdu;
}
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
  • 1
    Ok, thanks so much. What is the significance of System.arraycopy(id,0,answer,0,id.length); I understand it is copying the ID string bytes array but where to ? to the 'answer' array ? But that hasn't been initialised and where does that even go ? – Hazed 2.0 Jul 06 '18 at 21:15
  • @hazed2.0 right, that's been a leftover from simplifying my answer. It should have read `responseApdu` instead of`answer`. I corrected that now. – Michael Roland Jul 06 '18 at 21:33
  • Also, is it supposed to return commandApdu, why doesn't it return responseApdu ? – Hazed 2.0 Jul 06 '18 at 23:09
  • @Hazed2.0 I was obviously way too tired when I wrote that post. Fixed now. – Michael Roland Jul 07 '18 at 06:59
  • also how do i send an apdu to the responseApdu ? Please answer my thread here https://stackoverflow.com/questions/51331045/how-to-send-a-command-apdu-to-a-hce-device – Hazed 2.0 Jul 13 '18 at 20:23
  • I haven't explicitly called the processCommandApdu() method anywhere in my code. Will it be called automatically when the correct SELECT AID has been received ? How do I check it has been received...through the Log.i? nothing seems to be printing in the console. – Hazed 2.0 Jul 14 '18 at 22:34
  • I haven't explicitly called the processCommandApdu() method anywhere in my code. Will it be called automatically when the correct SELECT AID has been received ? How do I check it has been received...through the Log.i? nothing seems to be printing in the console. It detects the tag on the other HCE phone but doesn't respond. The line byte[] result = isoDep.transceive(selectApdu(SelectAID)); does not appear to be transceiving properly. I have managed to log the full commandApdu array which contains the following values [-92, 4, 0, 7, -14, 57]. – Hazed 2.0 Jul 15 '18 at 00:59
  • @Hazed2.0 If that's the whole command APDU, then your HCE service should never be called. Could it be that this is only part of the commandApdu array? Btw. `processCommandApdu()` is called by Android to forward the command APDUs to your service. That's why you must have registered your HCE service in the manifest and in your apdu-service XML file (by its AID). – Michael Roland Jul 15 '18 at 07:36
  • Ok nevermind fixed it now because I didn't have the in my manifest. ProcessCommandApdu is now successfully being called and the data has been received by the reader, now how do I break down the bytes and convert it back to String to get the original data (the ID number)..? – Hazed 2.0 Jul 15 '18 at 12:55
  • Nevermind I have worked it out now. It finally works !!! Thank you so much for your help ! – Hazed 2.0 Jul 15 '18 at 13:24
  • One more thing, how would I transfer the ID from another activity to this HostApduService class, instead of hardcoding the ID like you have done here ? – Hazed 2.0 Jul 29 '18 at 23:43
  • @Hazed2.0 See [Passing information to a HostApduService from another Context](https://stackoverflow.com/q/25018121/2425802) – Michael Roland Jul 30 '18 at 09:35