【问题标题】:How to set and unset password on a MIFARE Ultralight EV1 tag?如何在 MIFARE Ultralight EV1 标签上设置和取消设置密码?
【发布时间】:2017-11-07 18:45:51
【问题描述】:

我希望能够在 Android 上使用 NfcA? 标签技术在 MIFARE Ultralight EV1 (MFOUL21) 标签上设置和取消设置密码保护。

我知道我会为此使用 nfcA.transceive() 方法,但我不确定该方法的参数是什么,所以任何人都可以提供代码 sn-ps 来设置和取消设置密码吗?

更新:

关于 TapLinx 库,我基本上希望 nfcA.transceive(...) 代码 sn-ps 相当于:

  1. ultralightEV1.programPwd(passwordBytes);
  2. ultralightEV1.programPack(packBytes);
  3. ultralightEV1.enablePasswordProtection(enabled, fromPageNum);
  4. ultralightEV1.authenticatePwd(passwordBytes);

【问题讨论】:

    标签: android authentication tags nfc mifare


    【解决方案1】:

    认证

    ultralightEV1.authenticatePwd(passwordBytes);

    为了使用 MIFARE Ultralight EV1 标签(或 NTAG21x)的密码进行身份验证,您需要发送 PWD_AUTH (0x1B) 命令(并可能验证 PACK 响应是否符合您的期望):

    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.)
        }
    }
    

    设置密码和密码确认

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

    对于 MF0UL11,密码在 0x12 页,密码确认 (PACK) 在 0x13 页(配置页从 0x10 开始)。对于 MF0UL21,密码在 0x27 页,密码确认 (PACK) 在 0x28 页(配置页从 0x25 开始)。

    为了动态确定您的标签是 MF0UL11 还是 MF0UL21,您可以发送 GET_VERSION (0x60) 命令:

    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;
                    }
                }
            }
        }
    }
    

    找到配置页面的开头后,您可以使用 WRITE (0xA2) 命令更新这些页面的值(假设您使用当前密码进行身份验证,而配置页面不受保护):

    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)
    });
    

    启用密码保护

    ultralightEV1.enablePasswordProtection(enabled, fromPageNum);

    为了启用密码保护,您需要配置需要密码的第一个页面(AUTH0,MF0UL11 的第 0x10 页上的字节 3/MF0UL21 的第 0x25 页上的字节)并且您需要配置保护模式(PROT,第 7 位) MF0UL11 的第 0x11 页上的字节 0/MF0UL21 的第 0x26 页)。

    您通常会首先读取(READ (0x30) 命令)这些页面的旧值,更新受影响的位和字节,然后将新值写入标签:

    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
        });
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用 NXP 的 TapLinx 库(可在 https://www.mifare.net/en/products/tools/taplinx/ 获得)以抽象方式与 MIFARE Ultralight EV1 通信。

      要使用“收发器”,根据http://www.advanide.com/wp-content/uploads/products/rfid/UltraLight%20EV1_MF0ULX1.pdf 提供的数据表,需要使用 WRITE 命令 (A2),地址为 25-28h。

      更新: 要发送的命令应该是(对于 MFOUL21):

      1. ultralightEV1.programPwd(passwordBytes); A227AABBCCDD(用于密码 AABBCCDD)

      2. ultralightEV1.programPack(packBytes); A228EEFF0000(适用于 PACK 0000)

      3. ultralightEV1.enablePasswordProtection(启用, fromPageNum); A225xx0000yy(其中 xx 是调制模式;00..strong mod. disabled;01..strong mod. enabled;yy = 密码保护开始的页面)

      4. ultralightEV1.authenticatePwd(passwordBytes); 1BAABBCCDD

      【讨论】:

      • 我在使用 TapLinx 库时遇到了问题,所以现在需要手动进行NfcA 编码。我也查看了数据表,但我仍然对如何编写代码感到困惑。你能给我提供sn-ps吗?谢谢。
      • 您对 TapLinx 有什么问题?我宁愿解决这个问题……我希望您通常需要使用相同的命令序列。
      • 它在我的设备上运行良好,但我的客户在他的设备上遇到了糟糕的性能。我发现 NXP 的技术支持非常缓慢和令人沮丧,所以我恢复到 NfcA。
      猜你喜欢
      • 1970-01-01
      • 2021-08-31
      • 1970-01-01
      • 1970-01-01
      • 2015-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多