The xNT and the mysterious 46/48 byte problem

Sometimes, when customers first scan their xNT or flexNT, the app they are using (usually NFC Tools) will indicate the chip is an Ultralight and only has 46 bytes or 48 bytes of storage space, and it will not write any data.

This kind of error can occur for several reasons, none of which has to do with the actual NTAG216 chip inside the xNT or flexNT. In short, most NFC applications use a complex series of guessing games with the tag in order to detect what type of tag it is, and how much memory space it has.

For example, let’s say the chip is a Mifare Ultralight, which is the most common type of NFC Type 2 transponder out there. The memory schema looks identical to the NTAG family of tags, with far less storage space (64 bytes, with 48 bytes available for NDEF data). The NTAG is essentially the next generation of Ultralight chip, though both are still sold and made into new NFC tags. An NFC reader has a few methods it can use to properly identify the chip it is talking to;

  • Read the capability container. You see, when you format an NFC Type 2 compliant RFID tag like an NTAG or Ultralight, there is a special memory page (page 03) which contains 4 bytes which are OTP (one time programmable) that, when formatted for use with NFC, contains what’s known in the NFC specification as the “capability container” or CC. It is a header of sorts, which is supposed to act like a shortcut for the NFC reader device, informing it of a few things about the NFC tag it is reading. Byte 02 of the CC informs the reader about the amount of memory space available on the tag to store NDEF messages (NFC data). In hexidecimal values, a value of 0x12 means 144 bytes, 0x3E means 496 bytes, and 0x6D means 872 bytes. It is possible, for example, that an RFID tag chip like an NTAG216 which has 872 bytes available for NFC data storage, may only want to use the first 144 bytes for NDEF message data. In this case, it would write the CC such that byte 02 had a hex value of 0x12… however we never see this, and it is irrelevant anyway because I’ve never actually seen an NFC application read the CC or honor it… because software developers are usually lazy.

  • Chips like the NTAG have a “GetVersion” command which literally tells the NFC reader exactly what chip it is talking to as well as it’s storage size. Older chips like the Ultralight do not have such a command and must be probed and inspected to make an educated guess as to what chip it is. I’ve never seen any NFC app use this feature, because software developers are usually lazy.

  • Some chips will have a “factory default” set of binary data (non-NDEF data) written to the first user memory page (Page 04 for ultralight and ntag chips), which can also indicate the chip type being talked to. For example, an NTAG216 ships with 03h 00h FEh 00h as the first 4 bytes of user data, stored in page 04. However, I’ve never seen any NFC apps read or do anything with this data, because software developers are usually lazy.

  • Sometimes developers will just rely on the NDEF library of the operating system to tell the app what’s going on, specifically in terms of size. See, NDEF data is formatted in such a way that the payload is encapsulated in multiple containers. The outermost container is the NDEF message, which can be strung together as a series of messages, but there is typically only one. That message then can contain one or more records within it. If the data on the tag is null (all blocks are 0x00) or contain that default binary data I was talking about earlier, then it can cause havoc with certain phones, NFC reader chips inside the phones, Android OS NFC libraries handling the NFC tag scan event, and even the NFC app trying to scan (or write to) the tag. For example, at the time of this writing, if you tell Android’s NDEF library to write to a tag, it basically expects to perform an update to the records stored within an existing NDEF message. This is obviously problematic, because more often than not, a new chip will not contain an NDEF message until it is “formatted” or “erased” or whatever terminology is used by whatever NFC app you’re using… but again, often those commands simply “update” the NDEF message to contain an empty NDEF record… which fails because there is no NDEF message to begin with. So why not handle these situations properly by skipping the NDEF library all together is issue APDU commands directly to the tag to read, parse, and interpret things correctly? Well, because software developers are usually lazy.

  • Probe the chip by reading a single memory page to find out how many blocks are returned. This informs the reader that each block is 4 bytes. Then the application will read as many memory pages as it can to attempt to find out how many memory pages there are. From this information an educated guess can be made to identify the chip. This is the least reliable, most difficult way to do it… and I’m not even sure app developers do this, because it would require doing what I suggested previously - skipping the NDEF library and sending APDU commands directly to the chip to read memory pages… so if they are doing this in their apps, then they are doing a really shitty job because they should also be sending the GetVersion command (the best option) or at least reading the capability container to check the NDEF data storage size, then make some guesses from there… but this is obviously not happening, because software developers are usually lazy.

In the end, I have no idea what NFC app developers are doing… but whatever they are doing, it’s shit… and xNTs (and flexNTs) are sometimes being detected as 48 byte Ultralight tags.

The first thing you should try is use whatever NFC app you’re using to “erase” or “format” your tag. This should fix the “46/48 byte” problem. Basically it should write an NDEF message with a blank NDEF record to your tag, then afterward it should be detected normally.

If that fails, you can try our Dangerous Things Support Tool to write a blank NDEF record to your tag. We do this by directly issuing commands to your tag, rather than asking the Android NDEF library to do it. After that, it should be detected properly by your phone.

If you try both of these things and they don’t work, completely power-cycle your phone. Yes, the classic “turn it off and back on again”. I have no idea why this works, but I’ve seen it work (only after you try the other two things first).