read files on MIFARE DESFire EV2 NFC card with transceive and react-native-nfc-manager

52 Views Asked by At

How I could correctly retrieve data from x01 and x02 files on MIFARE DESFire EV2 cards?

I'm trying to read two files on MIFARE DESFire EV2 cards, but I'm not receiving the expected information. Also, I can't find any documentation on these MIFARE DESFire EV2 cards.

Here's my code based on some infos I've found on Google and on this question Android NFC IsoDep read file content :

const readNfc = async () => {
if (isReadingNfc) {
    return;
}
setIsReadingNfc(true);
let response = null;
try {
    await NfcManager.requestTechnology(NfcTech.NfcA);// IsoDep returns the same
    console.warn("1: requestTechnology");

    // select application (AID: 0xFFFFFF)
    await NfcManager.transceive([
        0x90, 0x5a, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x00,
    ]);
    console.warn("2: application selected");

    // read file 0x01
    const fileX01 = await NfcManager.transceive([
        0x90, 0xbd, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00,
    ]);
    console.warn("3: fileX01", fileX01);

    const data1 = fileX01.slice(0, fileX01.length - 2).toString("ascii");


    // read file 0x02
    const fileX02 = await NfcManager.transceive([
        0x90, 0xbd, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00,
    ]);

    console.warn("4: fileX02", fileX02);

    const data2 = fileX02.slice(0, fileX02.length - 2).toString("ascii");

    response = {data1,data2,};

    console.warn("5: response ", response);

    setNfcTagData(response);
} catch (error) {
    setNfcError(error);
} finally {
    await NfcManager.cancelTechnologyRequest();

setIsReadingNfc(false);
}

return response; };

The logs always return this: '5: fileX01', [ 145, 157 ] '6: fileX02', [ 145, 157 ]

I assume 145 and 157 are hexadecimal 91 and 9D, and they're probably error codes, but what do they mean?

Here's a report of the card I'm trying to read from the NFC Taginfo app:

** TagInfo Scan (version 5.0.0) 20-mars-24 15:10:49 **
Report Type: -- IC INFO ------------------------------
# IC Manufacturer:
Probably Genuine - AES OC couldn't be performed
NOTE: To perform AES Originality check, enable the option "Originality Check" from settings if not done, and make sure internet connection is active.
# IC Type:
MIFARE DESFire EV2 (MF3D22)
# DESFire Applications:
General issuer info
-- NDEF ------------------------------
# No NDEF Data Storage Populated:
-- EXTRA ------------------------------
# Memory information:
Size: 2 kB
Available: 2.0 kB
# IC Information:
Capacitance: 17 pF
# Version information:
Vendor ID: Probably Genuine - AES OC couldn't be performed
Hardware info:
* Type/subtype: 0x01/0x01
*  Major Version: 0x12
*  Minor Version: 0x00
* Storage size: 2048 bytes
* Protocol: ISO/IEC 14443-4
Software info:
* Type/subtype: 0x01/0x01
*  Major Version: 0x02
*  Minor Version: 0x01
* Storage size: 2048 bytes
* Protocol: ISO/IEC 14443-4
Production date: week 27, 2018
# Authentication Information:
Default PICC master key
# Originality Check (asymmetric):
Signature verified with NXP public key
# TagInfo Version:
Version :5.0.0
# Device Info:
Device Model :HMD Global ( Nokia G42 5G )
Android OS Version :14
-- FULL SCAN ------------------------------
# Technologies Supported:
ISO/IEC 7816-4 compatible
Native DESFire APDU framing
ISO/IEC 14443-4 (Type A) compatible
ISO/IEC 14443-3 (Type A) compatible
ISO/IEC 14443-2 (Type A) compatible
# Android Technology Information:
Tag description:
* TAG: Tech [android.nfc.tech.IsoDep, android.nfc.tech.NfcA, android.nfc.tech.NdefFormatable]
* Maximum transceive length: 65279 bytes
* Default maximum transceive time-out: 2000 ms
* Extended length APDUs supported
* Maximum transceive length: 253 bytes
* Default maximum transceive time-out: 618 ms
# Detailed Protocol Information:
ID: 04:36:1F:12:AD:5F:80
ATQA: 0x4403
SAK: 0x20
ATS: 0x067577810280
* Max. accepted frame size: 64 bytes (FSCI: 5)
* Supported receive rates:
    - 106, 212, 424, 848 kbit/s (DR: 1, 2, 4, 8)
* Supported send rates:
    - 106, 212, 424, 848 kbit/s (DS: 1, 2, 4, 8)
* Different send and receive rates supported
* SFGT: 604.1 us  (SFGI: 1)
* FWT: 77.33 ms  (FWI: 8)
* NAD not supported
* CID supported
* Historical bytes: 0x80 |.|
# Memory Content:
Application ID 0x000000 (PICC)
* Default master key
* Key configuration:
  - 1 (3)DES key
  - Key type of active keyset: 2TDEA
  - Master key changeable
  - Master key required for:
    ~ directory list access: no
    ~ create/delete files: no
  - Configuration changeable
Application ID 0xFFFFFF (General issuer info)
* Key configuration:
  - 2 AES keys
  - Max no. of keys: 2
  - Key type of active keyset: AES
  - Master key changeable
  - Master key required for:
    ~ directory list access: no
    ~ create/delete files: yes
  - Configuration changeable
  - Master key required for changing a key
  - Key versions:
    ~ Master key: 0
    ~ Key #1: 0
  - File ID 0x00: Standard data, 32 bytes
    ~ Communication: encrypted
    ~ Read key: free access
    ~ Write key: key #1
    ~ Read/Write key: master key
    ~ Change key: master key
    ~ Contents:
[0000] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0010] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
  - File ID 0x01: Standard data, 128 bytes
    ~ Communication: encrypted
    ~ Read key: free access
    ~ Write key: key #1
    ~ Read/Write key: master key
    ~ Change key: master key
    ~ Contents:
[0000] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0010] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0020] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0030] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0040] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0050] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0060] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0070] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
  - File ID 0x02: Standard data, 32 bytes
    ~ Communication: encrypted
    ~ Read key: free access
    ~ Write key: key #1
    ~ Read/Write key: master key
    ~ Change key: master key
    ~ Contents:
[0000] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0010] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
  - File ID 0x03: Standard data, 32 bytes
    ~ Communication: encrypted
    ~ Read key: free access
    ~ Write key: key #1
    ~ Read/Write key: master key
    ~ Change key: master key
    ~ Contents:
[0000] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0010] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
  - File ID 0x04: Standard data, 32 bytes
    ~ Communication: encrypted
    ~ Read key: free access
    ~ Write key: key #1
    ~ Read/Write key: master key
    ~ Change key: master key
    ~ Contents:
[0000] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0010] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
  - File ID 0x05: Standard data, 32 bytes
    ~ Communication: encrypted
    ~ Read key: free access
    ~ Write key: key #1
    ~ Read/Write key: master key
    ~ Change key: master key
    ~ Contents:
[0000] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[0010] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
--------------------------------------

I've hidden the data here but there is other information than 00 on the cards! From what I understand from the report, and if I'm correct, reading the files doesn't require a key and they are in the 0xFFFFFF application.

So How I could correctly retrieve data from x01 and x02 files?

1

There are 1 best solutions below

0
Pepito On

Here's what I came up with, and I retrieved all the necessary data with error handling:

    // Reads the remaining NFC data fragments following an initial response.
    // This function continues to request additional NFC data frames until the NFC tag indicates no more frames.
    const readRemainingNfcData = async (initialResponse) => {
        let response = initialResponse;
        let keepReading = true;

        while (keepReading) {
            const status = response.slice(-2);

            // 0xAF(175) says Additional data frame is expected to be sent
            if (status[0] === 0x91 && status[1] === 0xaf) {
                // Get the continuation of the response.
                const rBlockResponse = await NfcManager.transceive([
                    0x90, 0xaf, 0x00, 0x00, 0x00,
                ]);

                if (rBlockResponse && rBlockResponse.length > 2) {
                    response = response
                        .slice(0, -2)
                        .concat(rBlockResponse.slice(0, -2));
                } else {
                    throw new Error("Failed to read remaining NFC data");
                }
            } else {
                keepReading = false;
            }
        }

        return response;
    };

    // Check for error codes from the response received from the NFC card.
    // Here is a list of status:
    // https://www.eftlab.com/knowledge-base/complete-list-of-apdu-responses
    const handleResponse = (response) => {
        const status = response.slice(-2);

        if (
            !(status[0] === 0x91 && status[1] === 0) && // OK
            !(status[0] === 0x91 && status[1] === 0xaf) && // Additional data frame is expected to be sent
            !(status[0] === 0 && status[1] === 0)
        ) {
            throw new Error(
                `NFC read error with status: ${status[0].toString(16)} ${status[1].toString(16)}`,
            );
        }
    };

    const readNfc = async () => {
        if (isReadingNfc) {
            return;
        }

        setIsReadingNfc(true);
        let tag = null;
        let response = null;

        try {
            await NfcManager.requestTechnology(NfcTech.IsoDep);
            // tag = await NfcManager.getTag();

            // Select application FFFFFF
            const selectApplication = await NfcManager.transceive([
                0x90, 0x5a, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x00,
            ]);

            handleResponse(selectApplication);

            // Read the file 2
            const fileX02 = await NfcManager.transceive([
                0x90, 0xbd, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00,
            ]);

            handleResponse(fileX02);

            // Read the file 1
            let fileX01 = await NfcManager.transceive([
                0x90, 0xbd, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00,
            ]);

            handleResponse(fileX01);

            // File 1 is longer than maximum transceive max data transfer
            fileX01 = await readRemainingNfcData(fileX01);

            handleResponse(fileX01);

            response = {
                badgeData: decodeAscii(fileX01),
                badgeType: decodeAscii(fileX02),
            };

            setNfcTagData(response);
        } catch (error) {
            setNfcError(error);
        } finally {
            await NfcManager.cancelTechnologyRequest();

            setIsReadingNfc(false);
        }

        return response;
    };