如何使用 NfcA class 读取 Mifare Classic 标签?

How to read the Mifare Classic tag using the NfcA class?

我有一个支持 NfcAMifareClassic 技术的 NFC 标签。固件更新后,我的 phone 不再支持 MifareClassic 技术。在旧固件上,读取 MifareClassic 标签工作正常。

是否可以使用 NfcA class 读取 Mifare Classic 标签?这怎么能做到?

Mifare Classic A0A1A2A3A4A5技术认证密钥(举例)

public static String[] readTag(Tag tag) {
    byte[] readedData;
    byte[] PASSWORD = new byte[]{(byte) 0xA0, (byte) 0xA1, (byte) 0xA2, (byte) 0xA3, (byte) 0xA4, (byte) 0xA5};
    NfcA nfca = NfcA.get(tag);
    try {

        nfca.connect();
        readedData = nfca.transceive(new byte[]{
                (byte) 0x30,
                (byte) (0 & 0x0ff),PASSWORD // (for example)
        });
    } catch (Exception e) {
    }
}

Commands for transceive

首先,为了与 MIFARE Classic 标签进行通信(即验证、执行 read/write 操作),您将需要具有支持 MIFARE Classic 的 NFC 硬件的设备。由于恩智浦的许可政策,这通常只能在配备恩智浦 NFC 芯片组的设备上实现。其他 NFC 芯片组通常只允许您执行 anti-collision 和枚举(即检测标签并读取其 (N)UID)。

由于您指出访问 MIFARE Classic 的能力(通过 MifareClassic 标记技术对象)由于固件更新而丢失,我假设您的 NFC 芯片组能够访问 MIFARE Classic .

NXP 的 NFC 控制器使用 MIFARE reader 命令(plain-text 用于身份验证、二进制 read/write 和值块操作的命令)透明地抽象对 MIFARE Classic 标签的访问。芯片组自动负责将这些抽象命令转换为实际的 MIFARE Classic 命令、相互身份验证和会话加密。 MifareClassic 标记技术对象执行以下命令:

  • authenticateSectorWithKeyA(sectorIndex, key):
    +----------+-------------+--------------------+-------------------+
    |   0x60   | BLOCK_INDEX | UID (last 4 bytes) |       KEY_A       |
    | (1 byte) |  (1 byte)   |     (4 bytes)      |     (6 bytes)     |
    +----------+-------------+--------------------+-------------------+
    
  • authenticateSectorWithKeyB(sectorIndex, key):
    +----------+-------------+--------------------+-------------------+
    |   0x61   | BLOCK_INDEX | UID (last 4 bytes) |       KEY_B       |
    | (1 byte) |  (1 byte)   |     (4 bytes)      |     (6 bytes)     |
    +----------+-------------+--------------------+-------------------+
    
  • readBlock(blockIndex):
    +----------+-------------+
    |   0x30   | BLOCK_INDEX |
    | (1 byte) |  (1 byte)   |
    +----------+-------------+
    
  • writeBlock(sectorIndex, data):
    +----------+-------------+--------------------+
    |   0xA0   | BLOCK_INDEX |        DATA        |
    | (1 byte) |  (1 byte)   |     (16 bytes)     |
    +----------+-------------+--------------------+
    
  • increment(blockIndex, value):
    +----------+-------------+-------------------+
    |   0xC1   | BLOCK_INDEX |       VALUE       |
    | (1 byte) |  (1 byte)   |     (4 bytes)     |
    +----------+-------------+-------------------+
    
  • decrement(blockIndex, value):
    +----------+-------------+-------------------+
    |   0xC0   | BLOCK_INDEX |       VALUE       |
    | (1 byte) |  (1 byte)   |     (4 bytes)     |
    +----------+-------------+-------------------+
    
  • transfer(blockIndex):
    +----------+-------------+
    |   0xB0   | BLOCK_INDEX |
    | (1 byte) |  (1 byte)   |
    +----------+-------------+
    
  • restore(blockIndex):
    +----------+-------------+
    |   0xC2   | BLOCK_INDEX |
    | (1 byte) |  (1 byte)   |
    +----------+-------------+
    

对于当前的 NFC 控制器(使用 NCI 的控制器;不适用于例如 PN544),这些命令被 Android NFC 系统服务(参见 phNxpExtns.c and phNxpExtns_MifareStd.c)包装到特殊的 NCI 命令中。

根据您的设备无法枚举 MifareClassic 标签技术的原因,您可能很幸运,并且您设备的 NFC 堆栈已经处理了该包装。在这种情况下,您应该能够使用 NfcA 标记对象发送上述命令。

但是,您的设备可能无法枚举 MifareClassic 标签技术,因为它只是将标签检测为常规类型 2 标签(或其他 NFC-A 标签)。在那种情况下,NativeNfcTag.cpp 将不会执行额外的包装。您仍然可以通过遵循 phNxpExtns.c and phNxpExtns_MifareStd.c 中执行的相同策略来实际创建包装命令。但是,我不确定其他 side-effects 不正确的检测可能还有什么(例如不同的接口初始化)。