somq / nfccard-tool

💳 🛠️ The missing toolbox for reading and writing NFC cards
23 stars 5 forks source link

Unable to read: Tag is either empty, locked, has a wrong NDEF format #3

Closed alexcastillo closed 3 years ago

alexcastillo commented 3 years ago

Thank you for the great project!

I have a Mifare Ultralight - NTAG213 tag with 1 Text NDEF record (Format: NFC Well Known 0x01), and I'm able to read it with no problem with the NFC Tools iOS App.

I'm running the read example on this repo, and I'm getting "hasNDEFMessage": false in the header and the following error:

Could not parse anything from this tag: 
 The tag is either empty, locked, has a wrong NDEF format or is unreadable.

Which is strange because I'm positive that there is 1 Text NDEF encoded. I can confirm the data format is NFC Forum Type 2.

What am I doing wrong?

Any help is appreciated 🙏

Here's the tag info.

tag info: {
  "headerValues": {
    "raw": {
      "Lock": {
        "LOCK0": 0,
        "LOCK1": 0
      },
      "capabilityContainer": {
        "MAGIC_NUMBER": 225,
        "SPEC_VERSION": 16,
        "MAX_NDEF_LENGTH": 18,
        "READ_ACCESS": 0,
        "WRITE_ACCESS": 0
      },
      "NDEFMessageHeader": {
        "HAS_NDEF": 1,
        "MESSAGE_LENGTH": 3
      }
    },
    "string": {
      "Lock": {
        "LOCK0": "0",
        "LOCK1": "0"
      },
      "capabilityContainer": {
        "MAGIC_NUMBER": "E1",
        "SPEC_VERSION": "10",
        "MAX_NDEF_LENGTH": "12",
        "READ_ACCESS": "0",
        "WRITE_ACCESS": "0"
      },
      "NDEFMessageHeader": {
        "HAS_NDEF": "1",
        "MESSAGE_LENGTH": "3"
      }
    }
  },
  "parsedHeader": {
    "isFormatedAsNDEF": true,
    "type2SpecVersion": "1.0",
    "maxNDEFMessageSize": 144,
    "hasReadPermissions": true,
    "getReadPermissionsType": "HAS_READ_ACCESS",
    "hasWritePermissions": true,
    "writePermissionsType": "HAS_WRITE_ACCESS",
    "hasNDEFMessage": false,
    "NDEFMessageLength": 3,
    "lengthToReadFromBlock4": 5
  }
}
somq commented 3 years ago

Hi Alex,

Hard to tell without seeing the tag buffer but I'd look into some missing some implementations used in your tag such as dynamic lock or per page lock.
Which version do you use btw (C, EV1, nano)?

Did you try to prepare a ndef message on a clean tag yet?

If you drop the payload I can try to give it a look with you

alexcastillo commented 3 years ago

Thank you for responding, @somq!

I didn't prepare an NDEF with this library. I've been using the NFC Tools app to write to the tags.

Here's the memory payload from the NFC Tools app:

Addr. 00 : UID0 - UID2 / BCC0 >> [ 04:70:1F:E3 ] Read-Only
Addr. 01 : UID3 - UDI6 >> [ D2:65:60:80 ] Read-Only
Addr. 02 : BCC1 / INT. / LOCK0 - LOCK1 >> [ 57:48:00:00 ] Readable & Writable
Addr. 03 : OTP0 - OTP3 >> [ E1:10:12:0F ] Readable & Writable
Addr. 04 : DATA >> [ 01:03:A0:0C ] Readable & Writable
Addr. 05 : DATA >> [ 34:03:27:D1 ] Readable & Writable
Addr. 06 : DATA >> [ 01:23:54:02 ] Readable & Writable
Addr. 07 : DATA >> [ 65:6E:39:61 ] Readable & Writable
Addr. 08 : DATA >> [ 61:63:32:36 ] Readable & Writable
Addr. 09 : DATA >> [ 30:31:62:61 ] Readable & Writable
Addr. 0A : DATA >> [ 37:35:38:37 ] Readable & Writable
Addr. 0B : DATA >> [ 62:33:32:33 ] Readable & Writable
Addr. 0C : DATA >> [ 35:39:64:62 ] Readable & Writable
Addr. 0D : DATA >> [ 61:31:32:37 ] Readable & Writable
Addr. 0E : DATA >> [ 65:35:39:35 ] Readable & Writable
Addr. 0F : DATA >> [ 38:61:FE:00 ] Readable & Writable
Addr. 10 : DATA >> [ 23:54:02:65 ] Readable & Writable
Addr. 11 : DATA >> [ 6E:39:61:61 ] Readable & Writable
Addr. 12 : DATA >> [ 63:32:36:30 ] Readable & Writable
Addr. 13 : DATA >> [ 31:62:61:37 ] Readable & Writable
Addr. 14 : DATA >> [ 35:38:37:62 ] Readable & Writable
Addr. 15 : DATA >> [ 33:32:33:35 ] Readable & Writable
Addr. 16 : DATA >> [ 39:64:62:61 ] Readable & Writable
Addr. 17 : DATA >> [ 31:32:37:65 ] Readable & Writable
Addr. 18 : DATA >> [ 35:39:35:38 ] Readable & Writable
Addr. 19 : DATA >> [ 61:51:01:11 ] Readable & Writable
Addr. 1A : DATA >> [ 54:02:65:6E ] Readable & Writable
Addr. 1B : DATA >> [ 74:65:73:74 ] Readable & Writable
Addr. 1C : DATA >> [ 20:64:65:76 ] Readable & Writable
Addr. 1D : DATA >> [ 69:63:65:20 ] Readable & Writable
Addr. 1E : DATA >> [ 69:64:FE:00 ] Readable & Writable
Addr. 1F : DATA >> [ 00:00:00:00 ] Readable & Writable
Addr. 20 : DATA >> [ 00:00:00:00 ] Readable & Writable
Addr. 21 : DATA >> [ 00:00:00:00 ] Readable & Writable
Addr. 22 : DATA >> [ 00:00:00:00 ] Readable & Writable
Addr. 23 : DATA >> [ 00:00:00:00 ] Readable & Writable
Addr. 24 : DATA >> [ 00:00:00:00 ] Readable & Writable
Addr. 25 : DATA >> [ 00:00:00:00 ] Readable & Writable
Addr. 26 : DATA >> [ 00:00:00:00 ] Readable & Writable
Addr. 27 : DATA >> [ 00:00:00:00 ] Readable & Writable
Addr. 28 : LOCK2 - LOCK4 >> [ 00:00:00:BD ] Readable & Writable
Addr. 29 : CFG 0 (MIRROR / AUTH0) >> [ 04:00:00:FF ] Readable & Writable
Addr. 2A : CFG 1 (ACCESS) >> [ 00:05:00:00 ] Readable & Writable
Addr. 2B : PWD0 - PWD3 >> [ 00:00:00:00 ] Write-Only

Here's the Record 0 - Text value from the NFC Tools app:

NFC Record

Type:
Text record: T (0x54)

Format:
NFC Well Known (0x01)
Defined by RFC 2141, RFC 3986

Value:
Encoding: UTF-8
Language: EN
Text: 9aac2601ba7587b32359dba127e5958a

Raw value:
en9aac2601ba7587b32359dba127e5958a

Payload: 35 bytes
0x02 0x65 0x6E 0x39 0x61 0x61 0x63 0x32 0x36 0x30 0x31 0x62 0x61 0x37 0x35 0x38 0x37 0x62 0x33 0x32 0x33 0x35 0x39 0x64 0x62 0x61 0x31 0x32 0x37 0x65 0x35 0x39 0x35 0x38 0x61 

And here are the tag detail screen shots from the NFC Tools app:

IMG_6477

IMG_6478

IMG_6479

I'm pretty new to NFC, so please tell me if I didn't provide the information that you need.

somq commented 3 years ago

Can you log NDEFRawMessage?
Maybe a length issue?

Might also be a parse issue because I can see that your NDEF has been written multiple times (the last one overwriting the other ones):

# NDEF Start (ascii T= text type)
54
# NDEF terminator
FE:00

I would highly suggest you to make cross-tests to find out what's happening.

Btw, do you really need Mifare crypto capabilities?

alexcastillo commented 3 years ago

I just used a fresh tag of the same model with your write example, and it was able to write:

tag info: {
  "headerValues": {
    "raw": {
      "Lock": {
        "LOCK0": 0,
        "LOCK1": 0
      },
      "capabilityContainer": {
        "MAGIC_NUMBER": 225,
        "SPEC_VERSION": 16,
        "MAX_NDEF_LENGTH": 18,
        "READ_ACCESS": 0,
        "WRITE_ACCESS": 0
      },
      "NDEFMessageHeader": {
        "HAS_NDEF": 1,
        "MESSAGE_LENGTH": 3
      }
    },
    "string": {
      "Lock": {
        "LOCK0": "0",
        "LOCK1": "0"
      },
      "capabilityContainer": {
        "MAGIC_NUMBER": "E1",
        "SPEC_VERSION": "10",
        "MAX_NDEF_LENGTH": "12",
        "READ_ACCESS": "0",
        "WRITE_ACCESS": "0"
      },
      "NDEFMessageHeader": {
        "HAS_NDEF": "1",
        "MESSAGE_LENGTH": "3"
      }
    }
  },
  "parsedHeader": {
    "isFormatedAsNDEF": true,
    "type2SpecVersion": "1.0",
    "maxNDEFMessageSize": 144,
    "hasReadPermissions": true,
    "getReadPermissionsType": "HAS_READ_ACCESS",
    "hasWritePermissions": true,
    "writePermissionsType": "HAS_WRITE_ACCESS",
    "hasNDEFMessage": false,
    "NDEFMessageLength": 3,
    "lengthToReadFromBlock4": 5
  }
}
Data have been written successfully.

Then I used your read example and it was able to read it for the first time!

tag info: {
  "headerValues": {
    "raw": {
      "Lock": {
        "LOCK0": 0,
        "LOCK1": 0
      },
      "capabilityContainer": {
        "MAGIC_NUMBER": 225,
        "SPEC_VERSION": 16,
        "MAX_NDEF_LENGTH": 18,
        "READ_ACCESS": 0,
        "WRITE_ACCESS": 0
      },
      "NDEFMessageHeader": {
        "HAS_NDEF": 3,
        "MESSAGE_LENGTH": 86
      }
    },
    "string": {
      "Lock": {
        "LOCK0": "0",
        "LOCK1": "0"
      },
      "capabilityContainer": {
        "MAGIC_NUMBER": "E1",
        "SPEC_VERSION": "10",
        "MAX_NDEF_LENGTH": "12",
        "READ_ACCESS": "0",
        "WRITE_ACCESS": "0"
      },
      "NDEFMessageHeader": {
        "HAS_NDEF": "3",
        "MESSAGE_LENGTH": "56"
      }
    }
  },
  "parsedHeader": {
    "isFormatedAsNDEF": true,
    "type2SpecVersion": "1.0",
    "maxNDEFMessageSize": 144,
    "hasReadPermissions": true,
    "getReadPermissionsType": "HAS_READ_ACCESS",
    "hasWritePermissions": true,
    "writePermissionsType": "HAS_WRITE_ACCESS",
    "hasNDEFMessage": true,
    "NDEFMessageLength": 86,
    "lengthToReadFromBlock4": 88
  }
}
NDEFMessage: [
  {
    "NDEFLibRecord": {
      "LanguageCode": null,
      "text": null,
      "_typeNameFormat": 1,
      "_type": [
        84
      ],
      "_id": [],
      "_payload": [
        2,
        101,
        110,
        73,
        39,
        109,
        32,
        97,
        32,
        116,
        101,
        120,
        116,
        32,
        109,
        101,
        115,
        115,
        97,
        103,
        101
      ]
    },
    "type": "text",
    "text": "I'm a text message",
    "language": "en"
  },
  {
    "NDEFLibRecord": {
      "RawUri": [],
      "Uri": "",
      "_typeNameFormat": 1,
      "_type": [
        85
      ],
      "_id": [],
      "_payload": [
        4,
        103,
        105,
        116,
        104,
        117,
        98,
        46,
        99,
        111,
        109,
        47,
        115,
        111,
        109,
        113
      ],
      "type": "U"
    },
    "type": "uri",
    "uri": "https://github.com/somq"
  },
  {
    "NDEFLibRecord": {
      "packageName": "",
      "_typeNameFormat": 4,
      "_type": [
        97,
        110,
        100,
        114,
        111,
        105,
        100,
        46,
        99,
        111,
        109,
        58,
        112,
        107,
        103
      ],
      "_id": [],
      "_payload": [
        104,
        116,
        116,
        112,
        115,
        58,
        47,
        47,
        103,
        105,
        116,
        104,
        117,
        98,
        46,
        99,
        111,
        109,
        47,
        115,
        111,
        109,
        113
      ],
      "type": "android.com:pkg"
    },
    "type": "aar",
    "packageName": "https://github.com/somq"
  }
]

The NFC Tools app was also able to read it and parse it with no issues:

IMG_45B932D96237-1

I only own Mifare Ultralight NTAG213. I'm not sure about the crypto capabilities, is that the difference between NTAG213 and standard tags?

By the time I get my tags, they will already be encoded with 1 Text NDEF and the tag will be locked (like the one I shared in earlier comments). I guess I'd like to figure out how your encoding is different from the one I'm getting?

What do you suggest I do next?

Thank you much!

alexcastillo commented 3 years ago

I also prepared a clean tag with the NFC Tools app and I'm getting the same original error:

Could not parse anything from this tag: 
 The tag is either empty, locked, has a wrong NDEF format or is unreadable.

So my guess is that there must be a difference in encoding between this lib and the NFC Tools app.

somq commented 3 years ago

Hmm weird one, can you try cross-tests with another app (write/read app <=> lib)?
The NXP app is one of the best.
My guess is that your first tag had overlapping NDEF messages and the lib got somewhat lost for some reason but I might be wrong?

About tags, here is a great summarize
Mifare tags are specific because they are the only tags that support encryption.

alexcastillo commented 3 years ago

I downloaded the NXP App and tested with both tags:

The NXP App and the NFC Tools App are able to read all tags and show exactly the same information including payload data, payload length, TNF (NFC Well Known), Type (T), Encoding type (UTF-8) and language (en).

I'm not sure the issue can be an overlapping NDEF message since I also tested with clean tags.

To summarize:

I'm not sure where to go from here.

Any chance the issue could be related to this? https://github.com/somq/nfccard-tool/blob/master/lib/nfccard-tool.js#L260-L263

alexcastillo commented 3 years ago

I've been doing some digging and I was able to get the lib to parse by using the following code:

async function read(reader) {
  // Starts reading in block 0 for 20 bytes long
  const cardHeader = await reader.read(0, 20);
  const tag = nfcCard.parseInfo(cardHeader);

  if (
    nfcCard.isFormatedAsNDEF() && nfcCard.hasReadPermissions()
    // && nfcCard.hasNDEFMessage() // 👀 notice how I commented this out since it is always false
  ) {
    let NDEFRawMessage = await reader.read(5, 42); // 👀
    NDEFRawMessage = NDEFRawMessage.slice(1); // 👀

    const NDEFMessage = nfcCard.parseNDEF(NDEFRawMessage);

    return NDEFMessage;
  }
}

Does this make sense to you?

somq commented 3 years ago

Hi @alexcastillo, sorry for the late response, I've been very busy lately... Yes, it makes sense because it depends on the tag size and the message(s) you have on the card, maybe you have multiple NDEF messages written on the tag for instance?

You should check what you got from nfcCard.getNDEFMessageLengthToRead(), this method should be able to parse NDEF terminators and return the length of the message. If it matches you manual approximations then you are good. If not, maybe there are some missing conditions in the way the parsing works in the lib?

alexcastillo commented 3 years ago

Hi @somq,

Thanks for your reply. I don't have multiple NDEF messages, and it is still not clear why it works with some apps and not with others.

I think I'm good for now. The code above works great if I stick to 1 NDEF.

You can close this, thank you!

somq commented 3 years ago

Okey! Your welcome @alexcastillo, and sorry again for the delay. Do not hesitate if you think I can help you