Posts Communication between Android Host-based Card Emulation and a microprocessor system with NFC transceiver frontend

Communication between Android Host-based Card Emulation and a microprocessor system with NFC transceiver frontend

During a thug life of an engineer it may occur that you will need to estabilish communication between Android HCE (Host-based Card Emulation) and your legacy microprocessor system. In my case it was a chinese CV520 NFC Transceiver which was feature-compatible with MFRC522 chips (or RC522 family).

Android HCE works on the level of APDU (Application Protocol Data Unit) defined by ISO/IEC 7816-4 standard. However, the aforementioned frontend doesn’t provide direct hardware support for APDU. While I was studying the topic, I found a lot of contradictory statements on the Internet. Some of them claimed that using such protocol is not possible at all when using such NFC frontend. I’ve also found some posts on various forums, where people were asking for help in communication debugging. From these posts, it looked like it is actually possible if you implement the whole protocol stack on your own. However, many developers got stuck on various layers or protocol stages while doing so. Due to that, I’ve decided to dig deeper and finally realized what’s going on after studying NFC norms for over a dozen hours (i.e. whole night).

If you use a simple NFC frontend which is capable of sending raw bytes through the air, it is actually possible to communicate with Android HCE. You have to implement the whole protocol stack according to ISO/IEC 14443-3 (lowest layer), ISO/IEC 14443-4 (middle layer) and ISO/IEC 7816-4 (higher layer).

ISO/IEC 14443-3: Initialization, anticollision and card selection

Symbols: “R” -> Reader (NFC transceiver frontend side), “C” -> Card (Android HCE side).

R -> C: 0x52 (wake up all request)
C -> R: 0x00 (exemplary ATQA)
R -> C: 0x93 0x20 (anticollision command, request card UID)
C -> R: uid0, uid1, uid2, uid3, bcc (card sends it's UID and a checksum, uid0 ^ uid1 ^ uid2 ^ uid3 == bcc)
R -> C: 0x93 0x70 uid0 uid1 uid2 uid3 bcc crclsb crcmsb
C -> R: 0x20 crclsb crcmsb (SAK - ((sak & 4) == 4 - uid not complete, (sak & 32) == 32 - uid complete, otherwise card not compliant with the norm))

Note: It’s not a full anticollision loop. For cards with double or triple length UIDs you need to issue few additional commands. It also requires some changes in order to work when multiple cards are tapped against NFC reader. Refer to the information about anticollision loop provided in the standard (or anywhere else).

Note: Provided values of ATQA and SAK are exemplary and may differ, refer to the standard to figure out what’s exactly coded in them.

Note: Bytes denoted by crclsb and crcmsb are the message CRC_A code. In case of some frontends (MRFC522 included) it’s possible to calculate CRC_A using internal coprocessor. There are also some implementations on the Internet.

ISO/IEC 14443-4: Transmission protocol

R -> C: 0xE0 0x50 + crc (Request for answer to select, lower 4 bits are CID, higher 4 bits are FSDI whcih encodes maximum size of frame accepted by the reader, in our case FSDI=5 means 64 bytes)
C -> R: 0x5 0x78 0x80 0x70 0x0 crclsb crcmsb (Answer to select, lower 4 bits are FSCI which encodes maximum size of frame accepted by the card, in this case FSCI=8 which means 256 bytes)

Note: Provided value of ATS is exemplary and may differ, refer to the standard to figure out what’s exactly coded in it.

At this point (after receiving ATS) it is possible to negotiate some transmission parameters, but this part is optional and I’m not going to describe it.

ISO/IEC 7816-4: Application Protocol Data Unit

From now, we need to comply with 14443-4 standard. When talking higher-level protocol we need to include I-Block frame header as well as the CRC_A at the end of each message. Simplest I-Block frame header consists of just one byte (called Protocol Control Byte). It’s the only byte which is mandatory in such frame headers. We are going to use the value of 0x02, disabling all optional features related to addressing. Be aware that the least significant bit stands for “block parity”, so it’s required to toggle this bit after each sent message (i.e. we send first message with 0x02, then next with 0x03, next with 0x02 and so on).

R -> C: 0x02 0x00 0xA4 0x04 0x00 0x07 0xF0 0x01 0x02 0x03 0x04 0x05 0x06 crclsb crcmsb (SELECT AID)
C -> R: 0xF2 0x01 crclsb crcmsb (wait a little more)

We’ve succesfully sent SELECT AID F0010203040506 command and received response 0xF2 0x01 which means (in simplification): “retry later, I need more time to respond to that”. In the meantime, Android is seeking the service which is subscribed to the aforementioned application ID and informing it, that communication was estabilished. We have to reply with exactly the same sequence in order to poll for the actual result:

R -> C: 0xF2 0x01 crclsb crcmsb (re-request information)
C -> R: 0x02 0x48 0x65 0x6C 0x6C 0x6F 0x20 0x44 0x65 0x73 0x6B 0x74 0x6F 0x70 0x21 crclsb crcmsb

Here we go, we’ve received PCB + answer + crclsb + crcmsb. After decoding to ASCII it turns out to be Hello desktop!. Our application is selected and we can now continue the communication using almost arbitrary APDUs. Let’s send another message, e.g. 0x00 0xB0 0x00 0x00 0x0F 0xBE 0xEF (can be anything compliant with APDU protocol). Beware that we need to toggle “block parity” bit, so now we are using 0x03 as PCB:

R -> C: 0x03 0x00 0xB0 0x00 0x00 0x0F 0xBE 0xEF crclsb crcmsb
C -> R: 0x03 0x4D 0x65 0x73 0x73 0x61 0x67 0x65 0x20 0x66 0x72 0x6F 0x6D 0x20 0x61 0x6E 0x64 0x72 0x6F 0x69 0x64 0x3A 0x20 0x30 crclsb crcmsb

Still works. Now the answer is Message from android: 0.

After finishing communication, let’s deselect the card:

R -> C: 0xC2 crclsb crcmsb (deselect)
C -> R: 0xC2 crclsb crcmsb (deselect OK)

Android HCE Application dispatch

Android HCE allows multiple applications to coexist at the same time. ISO/IEC 14443-3 and ISO/IEC 14443-4 is handled by the smartphone’s hardware and/or the operating system. After issuing SELECT AID APDU command, the system is dispatching the communication to the appropriate application, according to the AID. Each application with NFC permission can subscribe to one or more AIDs.

Exemplary Android application

We know how to perform communication from the NFC frontend (microprocessor) side. Now, how to write actual Android application which will handle the communication and send these fancy Hello Desktop! messages? For such tests, I was using a sample application grundid/host-card-emulation-sample provided on GitHub. In src/de/grundid/hcedemo/ you may find information on how to implement Android HCE service. Remember that when testing, you need to have NFC enabled with the default processing method set as “System”. When testing aforementioned application, you need to have it run in background, because it runs NFC reader mode when put in foreground.

Also, remember to provide proper manifest and a list of subscribed AIDs.


It turns out that it is possible to communicate with Android HCE using only a low level NFC transceiver, however it needs some real effort to implement the whole protocol stack. For some legacy embedded systems there is no other way to accomplish this without replacing the actual hardware.

This post is licensed under CC BY 4.0 by the author.