You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MIFARE Plus EV2 SL3自定义认证实现中mplus_firstAuth_f2步骤0x06错误排查求助

MIFARE Plus EV2 SL3自定义认证实现中mplus_firstAuth_f2步骤0x06错误排查求助

大家好,我是第一次接触MIFARE Plus这类卡片,最近遇到了一个棘手的问题,想请各位帮忙排查一下。

背景情况

我刚入手了一台型号为P18Q的终端,它支持MIFARE Plus卡片的多种认证方式。供应商告诉我需要自行实现加密算法来和工作在SL3模式下的卡片通信,完成指定扇区的认证。我用NXP官方库的时候,认证、读写卡片都能成功,但因为这台终端没有标准的Android NFC阅读器,只能通过APDU和外部终端通信,所以没办法用官方库,只能自己写实现。

问题现象

现在的情况是:认证第一步我能成功收到卡片返回的挑战,但在第二步(也就是调用mplus_firstAuth_f2发送我的AES密钥相关响应时),一直收到0x06错误码。我跟着步骤走,第一步检测卡片、激活卡片、PPS协商都没问题,但到发送加密后的响应就失败了。

我的实现代码

下面是我写的测试方法:

public void test_MifarePlus() {
    final int CID = 0;
    final int fsdi = PICC_FSD_256;
    int DRI = PICC_BITRATE_TXRX_106K;
    int DSI = PICC_BITRATE_TXRX_106K;

    clearLog();
    appendLog("Iniciando autenticación Mifare Plus...");

    try {
        appendLog(">>> Paso 1: Detectando tarjeta...");
        String uid = detectNfcCard();
        if (uid == null || uid.isEmpty()) {
            appendLog("Error: No se detectó tarjeta NFC");
            return;
        }
        appendLog("Tarjeta detectada. UID: " + uid);

        appendLog("\n>>> Paso 2: Activando tarjeta...");
        String ATS = activateTypeACard(fsdi, CID);
        if (ATS == null || ATS.length() < 2) {
            appendLog("Error: Fallo en activación de tarjeta");
            return;
        }
        byte[] atsBytes = ByteArrayTools.hexStringToByteArray(ATS);
        int[] rates = PICC_ParseRate(atsBytes);
        DRI = rates[0];
        DSI = rates[1];
        appendLog("ATS recibido: " + ATS);
        appendLog("Parámetros negociados - DRI: " + DRI + ", DSI: " + DSI);

        appendLog("\n>>> Paso 3: Solicitud PPS...");
        int ppsStatus = requestPPS(CID, DRI, DSI);
        if (ppsStatus != 0) {
            appendLog("Error: Fallo en PPS (Código: " + ppsStatus + ")");
            return;
        }
        appendLog("PPS exitoso");

        appendLog("\n>>> Paso 4: Configurando autenticación SL3...");
        P18QMifarePlus channel = new P18QMifarePlus();
        MifarePlus mifarePlus = new MifarePlus(channel);
        byte[] keyAES;
        try {
            keyAES = ByteArrayTools.hexStringToByteArray(AESKey);
            if (keyAES == null || keyAES.length != 16) {
                appendLog("Error: Clave AES inválida. Debe ser de 16 bytes");
                return;
            }
        } catch (IllegalArgumentException e) {
            appendLog("Error: Formato de clave AES inválido");
            return;
        }

        appendLog("\n>>> Paso 5: Autenticación F1...");
        int blockToAuth = 0x4002;
        byte[] encryptedChallenge = mifarePlus.mplus_firstAuth_f1(blockToAuth);
        if (encryptedChallenge == null || encryptedChallenge.length < 16) {
            appendLog("Error: Challenge inválido o autenticación F1 fallida");
            return;
        }
        appendLog("Challenge cifrado recibido: " + ByteArrayTools.byteArrayToHexString(encryptedChallenge));

        byte[] randB;
        try {
            randB = aesDecrypt(Arrays.copyOf(encryptedChallenge, 16), keyAES);
            if (randB == null || randB.length != 16) {
                appendLog("Error: Descifrado de RAND_B fallido");
                return;
            }
        } catch (Exception e) {
            appendLog("Error al descifrar RAND_B: " + e.getMessage());
            return;
        }
        appendLog("RAND_B descifrado: " + ByteArrayTools.byteArrayToHexString(randB));

        byte[] randB_rot = rotateLeftByte(randB);
        byte[] randA = generateSecureRandom(16);
        byte[] responseData = concatenateArrays(randA, randB_rot);
        appendLog("RAND_A generado: " + ByteArrayTools.byteArrayToHexString(randA));
        appendLog("RAND_B rotado: " + ByteArrayTools.byteArrayToHexString(randB_rot));

        appendLog("\n>>> Paso 6: Autenticación F2...");
        byte[] encryptedResponse;
        try {
            encryptedResponse = aesEncrypt(responseData, keyAES);
        } catch (Exception e) {
            appendLog("Error al cifrar respuesta F2: " + e.getMessage());
            return;
        }
        appendLog("Datos a enviar (cifrados): " + ByteArrayTools.byteArrayToHexString(encryptedResponse));

        byte[] authResponse = mifarePlus.mplus_firstAuth_f2(encryptedResponse);
        if (authResponse == null || authResponse.length == 0) {
            appendLog("Error: Respuesta de autenticación F2 inválida");
            return;
        }
        if (authResponse[0] != (byte) 0x90) {
            appendLog("Autenticación fallida. Código de error: " + String.format("%02X", authResponse[0]));
            return;
        }

        appendLog("\nAutenticación SL3 completada con éxito!");
        appendLog("Respuesta final: " + ByteArrayTools.byteArrayToHexString(authResponse));
    } catch (Exception e) {
        appendLog("Error crítico: " + e.toString());
        e.printStackTrace();
    } finally {
        try {
            int removalStatus = removeCPUCard();
            // 原代码此处截断,保留现有逻辑
        } catch (Exception e) {
            appendLog("Error al remover tarjeta: " + e.getMessage());
        }
    }
}

我的疑惑

我是不是在mplus_firstAuth_f2步骤的参数处理上出错了?比如加密的方式、发送的数据格式不对?或者是AES密钥的使用有问题?因为第一次做这类卡片的开发,实在摸不准哪里错了,希望有经验的朋友能给我一些提示,谢谢!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 07:48:04