MIFARE卡读取失败后鉴权

Authentication after a read failure of a MIFARE card

一个arduino和一个mfrc522 rfid reader 好用读写mifare卡

我的目的是在一个扇区中使用卡的两个密钥,有些块可以用密钥A读取,有些块只能用密钥B读取。

正确设置访问位允许这种行为。为了在第二个扇区(块 4 5 6 7)上尝试它,我将访问位 g0 [0 0 0]、g1 [1 0 1]、g2 [0 0 0]、g3 [1 0 1] 设置为用 {,0xF5,0xA5,0xA0,0x38,} 写块 7 cf。 https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf 的第 8.7 节。现在块 5 不能用 keyA 读取,但可以用 keyB 读取(g1),并且 keyB 不再可读(g3)。因此,当我使用 keyA 进行身份验证时,尝试读取块 5 会导致错误。此时 others 验证失败,并且无法读取 others 块,尽管访问位允许它。

我尝试用第 5 块的密钥 B 和其他代码的密钥 A 读取第二个扇区,它正在工作。但是,如果我尝试使用密钥 A 进行读取,然后使用密钥 B 进行读取,以防万一失败,则无法正常工作。

代码摘录:

// The sector of interest is the second one : blocks 4 5 6 7
Serial.println("\nAuthenticate block 0x05 with key B");
for (i = 4; i < 8; i++) {
      // Block 5 is readable with key B
      status = readblock(i==5?MF1_AUTHENT1B:MF1_AUTHENT1A, i, i==5?keyB:keyA, serial);
      if ( status == MI_ERR) {
           Serial.print(" - Unable to read block nb. 0x");
           Serial.println(i, HEX);
      }
}

Serial.println("\nAuthenticate with key A then key B if failed");
for (i = 4; i < 8; i++) {
       // Try to authenticate each block first with the A key.
       status = readblock(MF1_AUTHENT1A, i, keyA, serial);
       if ( status == MI_ERR) {
            Serial.print(" - Try keyB - ");
            status = readblock(MF1_AUTHENT1B, i, keyB, serial);
            if ( status == MI_ERR) {
                 Serial.print(" - Unable to read block nb. 0x");
                 Serial.println(i, HEX);
            }
        }
}

readblock函数(鉴权和读取)

byte readblock(byte mode, byte block, byte *key, byte *serial)
{
int j;
 byte data[MAX_LEN];
byte status = MI_ERR;

// Try to authenticate the block first
status = nfc.authenticate(mode, block, key, serial);
if ( status == MI_OK) {
    Serial.print("Authenticated block nb. 0x");
    Serial.print(block, HEX);
    // Reading block i from the tag into data.
    status = nfc.readFromTag(block, data);
    if (status == MI_OK) {
        // If there was no error when reading; print all the hex
        // values in the data.
        Serial.print(" : ");
        for (j = 0; j < 15; j++) {
            Serial.print(data[j], HEX);
            Serial.print(", ");
        }
        Serial.println(data[15], HEX);
    } else
        Serial.print(" - Read failed");
  } else {
    Serial.print("Failed authentication block nb. 0x");
Serial.print(block, HEX);
}
  return status;
}

结果是

Authenticate block 0x05 with key B
Authenticated block nb. 0x4 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Authenticated block nb. 0x5 : AB, CD, EF, 1, 23, 45, 67, 89, 98, 76, 54, 1A, 10, FE, DC, BA
Authenticated block nb. 0x6 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Authenticated block nb. 0x7 : 0, 0, 0, 0, 0, 0, F5, A5, A0, 38, 0, 0, 0, 0, 0, 0

Authenticate with key A then key B if failed
Authenticated block nb. 0x4 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Authenticated block nb. 0x5 - Read failed - Try keyB - Failed authentication block nb. 0x5 - Unable to read block nb. 0x5
Failed authentication block nb. 0x6 - Try keyB - Failed authentication block nb. 0x6 - Unable to read block nb. 0x6
Failed authentication block nb. 0x7 - Try keyB - Failed authentication block nb. 0x7 - Unable to read block nb. 0x7

所以我想知道是否可以尝试使用坏密钥读取块,然后继续使用其他密钥读取块,依此类推。

可以在 https://www.nxp.com/docs/en/application-note/AN1304.pdf 第 24 页找到解释

Each time an Authentication operation, a Read operation or a Write operation fails, the MIFARE Classic or MIFARE Plus remains silent and it does not respond anymore to any commands. In this situation in order to continue the NDEF Detection Procedure the MIFARE Classic or MIFARE Plus needs to be re-activated and selected.

因此您必须在失败后重新激活 select,例如将这些行添加到您的代码中:

     Serial.println("\nAuthenticate with key A then key B if failed");
        for (i = 4; i < 8; i++) {
            // Try to authenticate each block first with the A key.
            status = readblock(MF1_AUTHENT1A, i, keyA, serial);
            if ( status == MI_ERR) {
                Serial.print(" - Try keyB - ");
/** RE ACTIVATE AND SELECT ------------------------------- **/
                nfc.haltTag();
                status = nfc.requestTag(MF1_REQIDL, data);
                if (status == MI_OK) {
                    status = nfc.antiCollision(data);
                    memcpy(serial, data, 5);
                    nfc.selectTag(serial);
                }
/** ------------------------------------------------------ **/
                status = readblock(MF1_AUTHENT1B, i, keyB, serial);
            if ( status == MI_ERR) {
                    Serial.print(" - Unable to read block nb. 0x");
                    Serial.println(i, HEX);
                }
            }
        }