How to interpret NDEF content on Mifare Classic 1K

Lucas Moretto picture Lucas Moretto · May 14, 2016 · Viewed 7.4k times · Source

I write a text to a Mifare Classic 1K tag using the NFC Tools app on my Android device (through the built-in NFC reader). This text is "moretto" (my last name).

Then, I'm trying to read this text (NDEF format) using the NFC reader ACR1255U with the library provided by ACS.

I am able to get following:

Read block 4: FF B0 00 04 10 response: 0000030ED1010A5402656E6D6F726574 9000

Read block 5: FF B0 00 05 10 response: 746FFE00000000000000000000000000 9000

I know that FE indicates the end of content and 6D6F726574746F is my text. But how do I identify where the text begins? I have difficulties to understand the TLV format described in the NXP documentation.

Answer

Michael Roland picture Michael Roland · May 14, 2016

First of all, NXP's proprietary NDEF mapping for MIFARE Classic tags is specified in these two application notes:

As you already found (Unable to authenticate to a MIFARE Classic tag used as NDEF tag), the NDEF data is stored in the data blocks of certain sectors (the NDEF sectors, marked as such by means of the MIFARE Application Directory). Thus, the data relevant for NDEF is the combination of all data from these blocks.

E.g. if your NDEF sectors are sector 1 and 2, you would need to read blocks 4, 5, 6 (= blocks 0..2 of sector 1) and blocks 8, 9, 10 (= blocks 0..2 of sector 2) to aggregate the data of the NDEF tag.

In your case, the data from blocks 4 and 5 seems to be sufficient (since the end of tag data is marked in block 5, as you correctly found yourself). The relevant tag data in your case is

0000030E D1010A54 02656E6D 6F726574
746FFE00 00000000 00000000 00000000

The tag data itself is packed into TLV (tag-length-value) structures. A TLV block consists of a mandatory tag byte, a conditional length field, and an optional data field:

  • TLVs that don't have length and data fields:
    +----------+
    | TAG      |
    | (1 byte) |
    +----------+
    
  • TLVs where the data field has a length from 0 to 254 bytes:
    +----------+----------+-----------+
    | TAG      | LENGHT n | DATA      |
    | (1 byte) | (1 byte) | (n bytes) |
    +----------+----------+-----------+
    
  • TLVs where the data field has a length from 255 to 65534 bytes:
    +----------+----------+-----------+-----------+
    | TAG      | 0xFF     | LENGHT n  | DATA      |
    | (1 byte) | (1 byte) | (2 bytes) | (n bytes) |
    +----------+----------+-----------+-----------+
    

The interesting tags in your specific case are:

  • NULL TLV: Tag = 0x00, no length field, no data field
  • Terminator TLV: Tag = 0xFE, no length field, no data field
  • NDEF Message TLV: Tag = 0x03, has field, has data field (may have zero length though)

Consequently, in your case the data decodes to:

00    NULL TLV (ignore, process next byte)
00    NULL TLV (ignore, process next byte)
03    NDEF Message TLV (contains your NDEF message)
    0E                              Lenght = 14 bytes
    D1010A5402656E6D6F726574746F    Data = NDEF Message
FE    Terminator TLV (stop processing the data)

An NDEF message can consist of 0, 1 or more NDEF records. In your case, the NDEF message decodes to the following:

D1    Record header (of first and only record)
          Bit 7 = MB = 1: first record of NDEF message
          Bit 6 = ME = 1: last record of NDEF message
          Bit 5 = CF = 0: last or only record of chain
          Bit 4 = SR = 1: short record length field
          Bit 3 = IL = 0: no ID/ID length fields
          Bit 2..0 = TNF = 0x1: Type field represents an NFC Forum
                                well-known type name
    01    Type Length = 1 byte
    0A    Payload length = 10 bytes
    54    Type field (decoded according to the setting of TNF)
              "T" (in US-ASCII) = binary form of type name urn:nfc:wkt:T
    02656E6D6F726574746F    Payload field (decoded according to the value of the Type field)

Therefore, your NDEF message consists of one Text record (NFC FOrum well-known type with the data payload 02656E6D6F726574746F. This record payload decodes to:

02    Status byte
          Bit 7 = 0: Text is UTF-8 encoded
          Bit 6 = 0: Not used
          Bit 5..0 = 0x02: Length of IANA language code field
656E    IANA language code field
            "en" (in US-ASCII) = Text is in English
6D6F726574746F    Text
                      "moretto" (in UTF-8)