6

I would like to be able to set and unset password protection on a MIFARE Ultralight EV1 (MFOUL21) tag using the NfcA? tag technology on Android.

I understand I would use the nfcA.transceive() method for this, but I'm not sure what the arguments to that method would be, so could anyone provide code snippets to set and unset the password?

Update:

With respect to the TapLinx library, I would basically like the nfcA.transceive(...) code snippets equvalent to:

  1. ultralightEV1.programPwd(passwordBytes);
  2. ultralightEV1.programPack(packBytes);
  3. ultralightEV1.enablePasswordProtection(enabled, fromPageNum);
  4. ultralightEV1.authenticatePwd(passwordBytes);
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
ban-geoengineering
  • 18,324
  • 27
  • 171
  • 253

2 Answers2

4

Authenticate

ultralightEV1.authenticatePwd(passwordBytes);

In order to authenticate with the password to a MIFARE Ultralight EV1 tag (or NTAG21x), you would need to send the PWD_AUTH (0x1B) command (and possibly verify if the PACK response matches your expectations):

byte[] pass = { (byte)0x12, (byte)0x34, (byte)0x56, (byte)0x78 };
byte[] pack = { (byte)0x9A, (byte)0xBC };

byte[] response = nfc.transceive(new byte[] {
    (byte) 0x1B, // PWD_AUTH
    pass[0], pass[1], pass[2], pass[3]
});
if ((response != null) && (response.length >= 2)) {
    // success
    byte[] packReceived = Arrays.copyOf(response, 2);
    if (Arrays.equal(packReceived, pack)) {
        // PACK verified, so tag is authentic (not really, but that whole
        // PWD_AUTH/PACK authentication mechanism was not really meant to
        // bring much security, I hope; same with the NTAG signature btw.)
    }
}

Set password and password-acknowledge

ultralightEV1.programPwd(passwordBytes); ultralightEV1.programPack(packBytes);

For MF0UL11, the password is on page 0x12 and the password-acknowledge (PACK) is on page 0x13 (configuration pages start at 0x10). For MF0UL21, the password is on page 0x27 and the password-acknowledge (PACK) is on page 0x28 (configuration pages start at 0x25).

In order to dynamically find out if your tag is MF0UL11 or MF0UL21, you could send a GET_VERSION (0x60) command:

int cfgOffset = -1;

byte[] response = nfc.transceive(new byte[] {
    (byte) 0x60 // GET_VERSION
});
if ((response != null) && (response.length >= 8)) {
    // success
    if ((response[0] == (byte)0x00) && (response[1] == (byte)0x04)) {
        // tag is from NXP
        if (response[2] == (byte)0x03) {
            // MIFARE Ultralight
            if ((response[4] == (byte)0x01) && (response[5] == (byte)0x00) {
                // MIFARE Ultralight EV1 (V0)
                switch (response[6]) {
                    case (byte)0x0B:
                        // MF0UL11
                        cfgOffset = 0x010;
                        break;
                    case (byte)0x0E:
                        // MF0UL11
                        cfgOffset = 0x025;
                        break;

                    default:
                        // unknown
                        break;
                }
            }
        }
    }
}

Once you found the begin of the configuration pages, you can use a WRITE (0xA2) command to update the values of those pages (assuming you are authenticated with the current password otr the configuration pages are unprotected):

byte[] response = nfc.transceive(new byte[] {
    (byte) 0xA2, // WRITE
    (byte)((cfgOffset + 2) & 0x0FF),    // page address
    pass[0], pass[1], pass[2], pass[3]  // new page data
});
response = nfc.transceive(new byte[] {
    (byte) 0xA2, // WRITE
    (byte)((cfgOffset + 3) & 0x0FF),          // page address
    pack[0], pack[1], (byte)0x00, (byte)0x00  // new page data (always need to write full page)
});

Enable password protection

ultralightEV1.enablePasswordProtection(enabled, fromPageNum);

In order to enable password protection, you need to cofigure the first page that requires the password (AUTH0, byte 3 on page 0x10 for MF0UL11/page 0x25 MF0UL21) and you need to configure the protection mode (PROT, bit 7 of byte 0 on page 0x11 for MF0UL11/page 0x26 MF0UL21).

You would typically first read (READ (0x30) command) the old value of those pages, update the affected bits and bytes, and write the new value to the tag:

int fromPageNum = 4;
boolean enableProtection = true;
boolean enableReadProtection = true;
byte[] response = nfc.transceive(new byte[] {
    (byte) 0x30, // READ
    (byte)(cfgOffset & 0x0FF)  // page address
});
if ((response != null) && (response.length >= 16)) {
    // success
    // NOTE that READ will return *4 pages* starting at page address
    byte auth0 = (byte)0xFF;
    if (enableProtection || enableReadProtection) {
        auth0 = (byte)(fromPageNum & 0x0FF);
    }
    byte[] writeResponse = nfc.transceive(new byte[] {
        (byte) 0xA2, // WRITE
        (byte)((cfgOffset + 0) & 0x0FF),              // page address
        response[0], response[1], response[2], auth0  // new page data
    });
    byte access = (byte)(response[4] & 0x07F);
    if (enableProtection && enableReadProtection) {
        access |= (byte)0x80;
    }
    byte[] writeResponse = nfc.transceive(new byte[] {
        (byte) 0xA2, // WRITE
        (byte)((cfgOffset + 1) & 0x0FF),                // page address
        access, response[5], response[6], response[7],  // new page data
    });
}
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
1

You can use the TapLinx Library from NXP (available at https://www.mifare.net/en/products/tools/taplinx/) to communicate with MIFARE Ultralight EV1 in an abstracted manner.

To use "transceive", according to the datasheet available at http://www.advanide.com/wp-content/uploads/products/rfid/UltraLight%20EV1_MF0ULX1.pdf the WRITE Command (A2) needs to be used, with addresses 25-28h.

UPDATE: The commands to be sent should be (for MFOUL21):

  1. ultralightEV1.programPwd(passwordBytes); A227AABBCCDD (for Password AABBCCDD)

  2. ultralightEV1.programPack(packBytes); A228EEFF0000 (for PACK 0000)

  3. ultralightEV1.enablePasswordProtection(enabled, fromPageNum); A225xx0000yy (where xx is the modulation mode; 00..strong mod. disabled; 01..strong mod enabled; yy = page where password protection starts)

  4. ultralightEV1.authenticatePwd(passwordBytes); 1BAABBCCDD

ErikM
  • 591
  • 1
  • 4
  • 13
  • I have run into problems using the TapLinx library, so now need to do the `NfcA` coding manually. I have looked through the datasheet, also, but I am still stumped as to how to code this up. Could you provide me with the snippets? Thanks. – ban-geoengineering Jun 08 '17 at 17:20
  • What's your issue with TapLinx? I would rather get this fixed ... I expect that generally you need to use the same command sequence. – ErikM Jun 08 '17 at 17:28
  • It worked fine on my devices, but my client experienced awful performance on his device. I found NXP's technical support to be very slow and frustrating, so I reverted to NfcA. – ban-geoengineering Jun 08 '17 at 17:35