xamarin.formsnfcreset-password

Set and Remove NFC Password Protection


I am developing an NFC test app using Xamarin.Forms and the Plugin.NFC library: https://github.com/franckbour/Plugin.NFC/

However, this library does not include a feature for setting or removing passwords, so I need to add that functionality myself.

I am adding the card information here.

My card is ISO 14443-3A
NXP - NTAG213
NfcA, MifareUltralight, Ndef
and below there is exported memory

and here is the memory dump

    [ 04:C1:FE:B3 ] Addr. 00 : UID0 - UID2 / BCC0
    [ F2:04:74:80 ] Addr. 01 : UID3 - UDI6
    [ 02:48:00:00 ] Addr. 02 : BCC1 / INT. / LOCK0 - LOCK1
    [ E1:10:12:00 ] Addr. 03 : OTP0 - OTP3
    [ 01:03:A0:0C ] Addr. 04 : DATA
    [ 34:03:0A:D1 ] Addr. 05 : DATA
    [ 01:06:54:02 ] Addr. 06 : DATA
    [ 65:6E:61:61 ] Addr. 07 : DATA
    [ 61:FE:00:00 ] Addr. 08 : DATA
    [ 63:3F:54:61 ] Addr. 09 : DATA
    [ 67:49:64:3D ] Addr. 0A : DATA
    [ 30:34:43:31 ] Addr. 0B : DATA
    [ 46:45:46:32 ] Addr. 0C : DATA
    [ 30:34:37:34 ] Addr. 0D : DATA
    [ 38:30:26:50 ] Addr. 0E : DATA
    [ 61:79:6C:6F ] Addr. 0F : DATA
    [ 61:64:3D:4D ] Addr. 10 : DATA
    [ 79:5F:49:6D ] Addr. 11 : DATA
    [ 70:6F:72:74 ] Addr. 12 : DATA
    [ 61:6E:74:5F ] Addr. 13 : DATA
    [ 4B:65:79:FE ] Addr. 14 : DATA
    [ 73:20:65:76 ] Addr. 15 : DATA
    [ 65:72:79:74 ] Addr. 16 : DATA
    [ 68:69:6E:67 ] Addr. 17 : DATA
    [ 20:6F:6B:3F ] Addr. 18 : DATA
    [ 20:79:65:73 ] Addr. 19 : DATA
    [ 20:69:74:20 ] Addr. 1A : DATA
    [ 69:73:FE:00 ] Addr. 1B : DATA
    [ 70:73:75:6D ] Addr. 1C : DATA
    [ 20:68:61:73 ] Addr. 1D : DATA
    [ 20:62:65:65 ] Addr. 1E : DATA
    [ 6E:20:74:68 ] Addr. 1F : DATA
    [ 65:20:69:6E ] Addr. 20 : DATA
    [ 64:75:73:74 ] Addr. 21 : DATA
    [ 72:79:27:73 ] Addr. 22 : DATA
    [ 20:73:74:61 ] Addr. 23 : DATA
    [ 6E:64:61:72 ] Addr. 24 : DATA
    [ 64:20:64:75 ] Addr. 25 : DATA
    [ 6D:6D:79:FE ] Addr. 26 : DATA
    [ 00:00:00:00 ] Addr. 27 : DATA
    [ 00:00:00:BD ] Addr. 28 : LOCK2 - LOCK4
    [ 04:00:00:00 ] Addr. 29 : CFG 0 (MIRROR / AUTH0)
    [ 00:05:00:00 ] Addr. 2A : CFG 1 (ACCESS)
    [ 00:00:00:00 ] Addr. 2B : PWD0 - PWD3
    [ 00:00:00:00 ] Addr. 2C : PACK0 - PACK1

I can detect whether a card is password-protected or not using the following code in Android.

  public bool CheckConfiguration()
  {
    bool passExist;
    MifareUltralight mu = null;
    try
    {
      mu = MifareUltralight.Get( _currentTag );
      mu.Connect();
      var answer = mu.ReadPages( 41 );
      byte auth0 = answer[ 3 ];
      passExist = auth0 < (byte)0xEB;

      Debug.WriteLine( "Page 41 (addr29)" );
      Debug.WriteLine( string.Join( "", answer ) );

      mu.Close();
    }
    catch( Exception e )
    {
      mu?.Close();
      passExist = true;
    }
    return passExist;
  }

The authentication status is located at address 0x29. If the last byte is 0x00, it means the card is password-protected; if the last byte is 0xFF, it means the card is not password-protected.

I was able to send a basic command and receive a result successfully.


    private void TestReadBlock(MifareUltralight mfu)
    {
        try
        {
            if (!mfu.IsConnected)
                mfu.Connect();
    
            // Read block 4 as a test
            byte[] readCommand = { 0x30, 0x04 }; // Read block 4
            byte[] response = mfu.Transceive(readCommand);
    
            if (response != null)
            {
                Debug.WriteLine($"Read successful. Response: {BitConverter.ToString(response)}");
            }
            else
            {
                Debug.WriteLine("Read failed. Response is null.");
            }
        }
        catch (Java.IO.IOException ex)
        {
            Debug.WriteLine($"IOException during read: {ex.Message}");
        }
        finally
        {
            try
            {
                if (mfu.IsConnected)
                    mfu.Close();
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Failed to close connection: {ex.Message}");
            }
        }
    }

I can get a result.

However, when I attempt authentication with the 0x1B command, I always receive the error "Tag was lost."

For example, I get an exception when calling the Transceive method the first time.

    private bool RemovePasswordProtection(MifareUltralight mfu)
    {
        try
        {
            if (!mfu.IsConnected)
                mfu.Connect();
    
            byte[] pwdAuthCommand = { 0x1B, 0x00, 0x00, 0x00, 0x00 };
            byte[] response = mfu.Transceive(pwdAuthCommand);
    
            byte[] writeCommand = { 0xA2, 0x29, 0xFF, 0x00, 0x00, 0x00 };
            mfu.Transceive(writeCommand);
    
            return true;
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"Error removing password protection: {ex.Message}");
            return false;
        }
        finally
        {
            try
            {
                if (mfu.IsConnected)
                    mfu.Close();
            }
            catch { }
        }
    }

I am not sure if the command is incorrect or if there is another underlying issue. One thing to note is that I call this authentication method after detecting a tag.

EDIT:

It seems that the password is not in the memory dump. When I set a password and then remove it, there is only on difference as follow

EDIT 2:

I add my password to the auth command however I get always the "Tag was lost" exception while executing mfu.Transceive( pwdAuthCommand );

 private async Task<bool> TryRawAuthentication( MifareUltralight mfu )
  {
    try
    {
        if( !mfu.IsConnected )
        mfu.Connect();

        byte[] pwdAuthCommand = {
              0x1B,   // PWD_AUTH command
              0x31,   // '1'
              0x32,   // '2'
              0x33,   // '3'
              0x34    // '4'
          };

        Debug.WriteLine( $"Sending PWD_AUTH command: {BitConverter.ToString( pwdAuthCommand )}" );
        byte[] response = mfu.Transceive( pwdAuthCommand );
        Debug.WriteLine( $"NfcA Auth Response: {BitConverter.ToString( response )}" );
        return true;
    }
    catch( Exception ex )
    {
      Debug.WriteLine( $"Raw authentication error: {ex.Message}" );
      return false;
    }
  }

Solution

  • Most likely that { 0x00, 0x00, 0x00, 0x00 } is not the password.

    As per the Datasheet Section 8.8.1

    The PWD and PACK bytes can never be read out of the memory. Instead of transmitting the real value on any valid READ or FAST_READ command, only 00h bytes are replied.

    You need to know the real password, you cannot read the password from the Dump.

    If you try and authenticate with the wrong password the Tag will go in to HALT state and hence the Tag lost error.

    So Transceive with the right values for the password you set.

    byte[] pwdAuthCommand = { 0x1B, 0x01, 0x02, 0x03, 0x04 };
    

    Once successfully authenticated you can then change the password/pack and password config.

    Also always check the byte[] response from the Transceive as that can give you more info on what went wrong with a command.

    Update:

    I've had a look at the NFC Plugin and on Android it uses an older NFC API that because of user behaviour and how it works is more prone to generate a lot more "Tag Lost" error messages when doing any other operation than reading Ndef Messages. e.g. writing or password auth commands.

    I don't know if there is a better Plugin that uses a better Android NFC API.

    Thus it is possible that the "Tag Lost" message are really because the Tag has gone out of range before you try the password auth. If you are very careful as a user about the Tag placement it should not be a problem.

    Otherwise the Standard response to a wrong password will be usually "Tag Lost".

    I would double check the byte[] has the right content, I note that sometimes people cast the hex values to byte with (byte). I'm also note sure when you set it with NFC tools if it used the data entered as Hex values or as you have shown converted them to the ASCII hex values. May be use code to write a password to another Tag so you know exactly the hex values used.

    From your Dump it does not look like you have set a limit on the number of password attempts, if you had then too many bad attempts would lock the card and can also produce "Tag Lost" on non read commands.