Search code examples
androidauthenticationxamarinnfcmifare

Setting password for NTAG213


I am trying to set and check a password in a NFC Tag (type: NTAG213) but I always receive an IOException (Transceive failed) when I am trying to set it.

I don't understand which page I have to set for password and ACK pack. This is my code written in C# with Xamarin. Please feel free to reply in native Android Java code.

var tag = intent.GetParcelableExtra (NfcAdapter.ExtraTag) as Tag;

String password = "pass";
byte[] array = System.Text.Encoding.ASCII.GetBytes (password);
MifareUltralight mifare = MifareUltralight.Get (tag);
mifare.Connect ();

byte[] result1 = mifare.Transceive(new byte[] {
        (byte)0xA2,  /* CMD = WRITE */
        (byte)0x2C,  /* PAGE = 44 */
        array[0], array[1], array[2], array[3] 
});

byte[] result2 = mifare.Transceive(new byte[] {
        (byte)0xA2,  /* CMD = WRITE */
        (byte)0x2A,  /* PAGE = 42 */
        (byte)array[0], (byte)array[1], (byte)0, (byte)0 
});

Solution

  • With NTAG213, the correct pages for the password (PWD) and the password acknowledge (PACK) are:

    • PWD: 43 (0x2B)
    • PACK: 44 (0x2C)

    Hence, you are trying to write to the wrong pages. More specifically, you are trying to write non-zero values to RFUI bytes (page 44, bytes 2-3 and page 42, bytes 1-3) which may cause the write operations to fail.

    So you would typically want to do something like this:

    byte[] pwd = new byte[] { (byte)0x70, (byte)0x61, (byte)0x73, (byte)0x73 };
    byte[] pack = new byte[] { (byte)0x98, (byte)0x76 };
    
    // write PACK:
    byte[] result = mifare.Transceive(new byte[] {
            (byte)0xA2,  /* CMD = WRITE */
            (byte)0x2C,  /* PAGE = 44 */
            pack[0], pack[1], 0, 0
    });
    
    // write PWD:
    result = mifare.Transceive(new byte[] {
            (byte)0xA2,  /* CMD = WRITE */
            (byte)0x2B,  /* PAGE = 43 */
            pwd[0], pwd[1], pwd[2], pwd[3]
    });
    

    Note that it does not make much sense to let PACK be a subset of PWD since an attacker would then be able to obtain the PACK value from the PWD value. The PACK value is typically used as a shared secret that only you and the tag "know" and that the tag sends in response to a successful authentication attempt in order to prove that it is a genuine tag. (Though there are quite a lot of security issues with this approach.)

    Further note that setting the PWD/PACK values will fail (possibly with an IOException) if the tag is already protected (password set and authentication configuration set to protect PWD/PACK). In those cases, you would need to authenticate with the current password first.