Host-based Card Emulation with Fixed Card ID
Android 4.4 introduced Host-based Card Emulation (HCE). As you know, all NFC cards come with a fixed card ID (NfcAdapter.EXTRA_ID
).
My office door access usually detects the NFC card ID for the authorization. After flashing my phone to KitKat, I tried to scan my phone with the access reader. But whenever the screen turns off and on again, I get a different card ID.
I did try keeping the phone screen on, and registering the emulated card ID to the door access system. It managed to grant the access to open the door. But this won't work after the screen turns off and on again.
Ever since KitKat introduced HCE mode, I have been trying to emulate my door access card using my phone.
Any ideas for making the phone emulated card ID fixed?
This is (at least with the official API) not possible:
In the first part of the exchange the HCE device will present its UID; HCE devices should be assumed to have a random UID. This means that on every tap, the UID that is presented to the reader will be a randomly generated UID. Because of this, NFC readers should not depend on the UID of HCE devices as a form of authentication or identification.
(http://developer.android.com/guide/topics/connectivity/nfc/hce.html#ProtocolParams)
According to one of the Google developers responsible for HCE:
Sorry, I realize many people wanted this, but it's not possible in the official version. (You could of course do it with some AOSP hacking). The reason is that HCE is designed around background operation. If we allow apps to set the UID, every app possibly wants to set their own UID, and there's no way to resolve the conflict. We hope that with HCE, NFC infrastructure will move to higher levels of the protocol stack to do authentication instead of relying on the UID (which is easily cloned anyway).
At least Broadcom's NFC controller (used e.g. in the Nexus 5) supports setting arbitrary values for the anticollision identifier (UID), the ATQA and the SAK byte. However, there is no API to change them, so the only way would be to modify the libnfc-nci library.
The relevant code for NFC-A is in the file nfa_dm_discover.c (starting on line 322):
UINT8_TO_STREAM (p, NFC_PMID_LA_BIT_FRAME_SDD);
UINT8_TO_STREAM (p, NCI_PARAM_LEN_LA_BIT_FRAME_SDD);
UINT8_TO_STREAM (p, 0x04);
UINT8_TO_STREAM (p, NFC_PMID_LA_PLATFORM_CONFIG);
UINT8_TO_STREAM (p, NCI_PARAM_LEN_LA_PLATFORM_CONFIG);
UINT8_TO_STREAM (p, platform);
UINT8_TO_STREAM (p, NFC_PMID_LA_SEL_INFO);
UINT8_TO_STREAM (p, NCI_PARAM_LEN_LA_SEL_INFO);
UINT8_TO_STREAM (p, sens_info);
This code currently sets the ATQA (combination of the value platform and 0x04) and the SAK byte (value of sens_info).
In order to change the UID used during NFC-A anticollision, you could add the addition parameter NFC_PMID_LA_NFCID1:
UINT8_TO_STREAM (p, NFC_PMID_LA_NFCID1);
UINT8_TO_STREAM (p, 4); // length of NFCID1 in bytes
UINT8_TO_STREAM (p, 0x12);
UINT8_TO_STREAM (p, 0x34);
UINT8_TO_STREAM (p, 0x56);
UINT8_TO_STREAM (p, 0x78);
You can find a more customizable version of libnfc-nci here (still work-in-progress though).
It is possible. There are at least two ways of getting a static UID:
Not all phones show a random UID when running stock ROM. Some phones have a static UID 01:02:03:04, i.e. LG G3, Xiaomi Mi 3 and Mi Mix 2s. But then, everyone with one of these phones could enter your room.
Use Card Emulator Pro from Google play store and you can emulate any desired UID. You can also toggle such that the UID is maintained when the screen is off.
Systems that rely on UID only are not safe. It's better to use a system with encryption.