Search code examples
androidnfcuniqueidentifierapduhce

How to define an APDU for STORE DATA for Host Card Emulation?


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?


Solution

  • 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;
    }