Android NFC communication with Mifare DESFire EV1
Asked Answered
H

1

6

Using a Nexus 4 and the latest Android API level 18 to communicate with a Mifare DESFire EV1 AES tag is giving me a headache. Following the NXP native protocol in order to write and read this type of tag, these steps must be followed:

  1. Select application
  2. Authenticate
  3. Write or Read

To do it so, I use Android's IsoDep class which provides access to ISO 14443-4 properties and I/O operations. The very weird thing about it is that once I send the select application native command I get an unexpected response. Imagine I have the AID F4013D so I send:

-> 5AF4013D
<- 6E00

All possible responses must be one byte length (success 0x00 or error_code) and never two or more. Thus, the 0x6E before the success response is absolutely unexpected. It does not happen always, and when it does not and works fine, the select application and authentication processes work fine. However once authenticated the write command does not have a correct behavior, all write commands finishes with a 0xAF from the PICC instead of a success 0x00. It seems like the PICC expect some extra data when it should not (I send the correct length payload). If I send any other command I get a 0xCA (Command Aborted) error code.

-> 5AF4013D
<- 00 /*Success*/
-> AA01
<- AFA8394ED57A5E83106B4EE72FD2BB0CC4
-> AF148F525E1DDE0AD6AB60B4B615552475C91F2E8D89B8523E4465113DD5BD19C6 
<- 0066D255C93F2F492AFE3715C88964F1BD /*Authentication success*/
-> 3D02000000030000222222 /*Write 3 bytes to file nº2*/
<- AF /*Unexpected, 0x00 was expected*/

As it is normal, if I send these type of commands with a personal reader (non Android NFC) it always works fine. It seems that something in the Android NFC API is going strange, when it should just be a raw data transporter which never interprets or modifies data.

I have also tried with ISO 7816-4 APDU structure with the same result. As a curiosity, with a Galaxy Nexus does not happen the select application strange response, but yes the write command one always.

Haemal answered 25/10, 2013 at 12:11 Comment(0)
C
9

(1) For the first part concerning the status code 6E00:

6E 00 is not a "strange byte 0x6E + success status code 0x00". Instead it is a response APDU status word 6E 00 ("Class not supported"). This indicates that there was previous communication with the card using APDU-based access (e.g. Android itself tried to read the card as Type 4 tag and did not reset the connection afterwards). Thus, the card will expect all further communication to be in ISO 7816-4 APDUs. In that case (i.e. if you receive an ISO 7816-4 status code like 6E 00), you could continue using DESFire APDU wrapped commands by simply wrapping your native commands.

EDIT: In fact, this is somewhat expected behavior on an NFC device. The idea is that an NFC device will automatically scan detected tags for NDEF messages. In the case of a DESFire card, the NFC device will detect the card as potential Type 4 tag. Thus the NFC device will send ISO 7816-4 APDUs as it would send to any other Type 4 tag. Hence, if the NFC device doesn't reset the communication with the tag before handing the detected tag to the app, the app can only communicate using ISO 7816-4 APDUs. Note, however, that I would consider it a bug that this happens only for some activations on the same device. In my opinion, the behavior on one specific device model should be consistent.

EDIT: While I would not consider this behavior a bug, it is actually caused by a known bug (#58773) in Android's NFC stack for devices with Broadcom NFC controller. On affected devices, the automatic presence check sends ISO 7816-4 APDUs at timed intervals that cause DESFire cards to switch into ISO 7816-4 APDU mode.


(2) For the second part concerning the (unexpected) response code 0xAF:

Could it be that your file's communication settings are setup for either "plain communication secured by MACing" or "fully enciphered communication"? In that case, simply sending the three data bytes would not be enough. Instead you would need to send either the plain data plus MAC or the padded, CRCed and encyrypted data. Hence the 0xAF indicating that the card expects further data.

EDIT: So to summarize the comments below. After sending further bytes (one byte at a time for each received 0xAF status code: AF FF) it turned out that exactly 8 more bytes were expected by the card. 8 bytes is exactly the size of the CMAC for AES authentication. Thus, the communication settings were set to "plain communication secured by MACing".

Chainman answered 25/10, 2013 at 15:3 Comment(9)
Thanks for the answer.(1) If I'm not wrong, the PICC will always response in a communication type you establish by the first command. In my case, if I send a 5AF4013D command it will be native and no wrapped communication. In this scenario the answer will always be 1 byte long. In case of Android had stablished a previous contact with the PICC in wrapped format (apart from being an huge error),IMHO It would never understand my native command, and less answer with a success.(2)That would make sense, but I have set the communication settings to plain since the beginning.Haemal
Regarding (1): Actually does not send wrapped commands but standard ISO 7816-4 commands to try to communicate with the (potential) Type 4 tag. Thus, if the communication is not reset before you send your native command, the card will respond with an ISO 7816-4 error code. In fact, 6E00 is not a strange byte+native success. Instead it is a "Class not supported" error (in ISO 7816-4) that indicates that the class byte 5A is not valid.Chainman
Regarding (2): That's odd. Other than that, I don't really have an idea what might be wrong there. Have you tried responding to the AF status code with an empty AF command?Chainman
(1) So it should be considered as an Android bug of trying to read a tag and not resetting the communication? (2) Yes I did, and it enters to an infinite loop of AF's.Haemal
(1) Android trying to read the tag as a Type 4 tag is certainly expected behavior, after all it's an NFC device and not a dedicated DESFire/contactless smartcard reader. Even the device not resetting the communication afterwards is not really unexpected. The unexpected part (which I would consider a bug, is the inconsistency between several activations on the same device).Chainman
(2) So now we know that the card is actually expecting further data. As a next debugging step I would try to send more bytes (one byte at a time; i.e. AF 00) to find out how many further bytes the card expects -- and what error code it replies afterwards.Chainman
Yeap, I did already, is one of the first things I thought. It gets after the first received AF: -> AFFF <- AF -> AFFF <- AF -> AFFF <- AF -> AFFF <- AF -> AFFF <- AF -> AFFF <- AF -> AFFF <- AF -> AFFF <- 1E -> AFFF <- 1C. So it expects 8 bytes more before giving the 1E integrity error (CRC or MAC does not match data, Padding bytes not valid) and in the next one 1C Illegal Command Code. Emphasise that the comm settings are in plain.Haemal
Still 8 bytes is exactly the length of the CMAC. So something might have gone wrong when setting the comm settings...Chainman
You were right, I was mistaken when I said it was just plain, it was plain with MAC so it was expecting as you said the MAC after the write data. It only remains to know what's exactly going on with Android and the question (1). Anyway, I'll give you the correct answer as you guide me to the solution, thanks for all!Haemal

© 2022 - 2024 — McMap. All rights reserved.