Android NFC IsoDep read file content

Vilius picture Vilius · Oct 10, 2013 · Viewed 9.7k times · Source

I'm trying to read some information out of an ISO/IEC 14443 Type A card.

After analysing the card with the android app NFC TagInfo, I found out, that the application (AID: 15845F) has the particular file (File ID: 01) that I need.

I already managed to connect to the card and to select the application.

String action = getIntent().getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action))
{
    Tag tagFromIntent = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);  
    Log.i(TAG, Arrays.toString(tagFromIntent.getTechList()));

    IsoDep isoDep = IsoDep.get(tagFromIntent);
    try
    {
        isoDep.connect();

        byte[] SELECT = { 
            (byte) 0x00, // CLA = 00 (first interindustry command set)
            (byte) 0xA4, // INS = A4 (SELECT)
            (byte) 0x04, // P1  = 04 (select file by DF name)
            (byte) 0x0C, // P2  = 0C (first or only file; no FCI)
            (byte) 0x06, // Lc  = 6  (data/AID has 6 bytes)
            (byte) 0x31, (byte) 0x35,(byte) 0x38,(byte) 0x34,(byte) 0x35,(byte) 0x46 // AID = 15845F
        };

        byte[] result = isoDep.transceive(SELECT);
        Log.i(TAG, "SELECT: " + bin2hex(result));

        if (!(result[0] == (byte) 0x90 && result[1] == (byte) 0x00))
            throw new IOException("could not select application");

        byte[] GET_STRING = { 
            (byte) 0x00, // CLA Class
            (byte) 0xB0, // INS Instruction
            (byte) 0x00, // P1  Parameter 1
            (byte) 0x00, // P2  Parameter 2
            (byte) 0x04  // LE  maximal number of bytes expected in result
        };

        result = isoDep.transceive(GET_STRING);
        Log.i(TAG, "GET_STRING: " + bin2hex(result));
    }
}

But my second query fails with the error code: 6A86 (Incorrect parameters P1-P2). I already googled a lot and found different documentations (for example: http://bit.ly/180b6tB), but I just could not understand, how I can implement the right values for P1 and P2.


EDIT

Tag type of the card using NFC TagInfo: ISO/IEC 14443-4 Smart Card, Mifare DESFire EV1 (MF3ICD81)

The SELECT command as used in the source code actually did not fail, but instead it returned a 9000 response. So this is why I assumed that everything is working fine.

You mentioned that NFC TagInfo does not provide the correct values for DF-names etc. Is the value 0x313538343546 correct and how did you find it out?

Can you provide me a short description, how I could get the data I want? Are there any other android apps that I can use to read the right DF-names, AIDs etc.? I basically need to get ONE file out of ONE application. I could also provide some screenshots of the information gathered with NFC TagInfo, if needed.


EDIT 2

I have rewritten the commands, but (as you proposed) kept them in the APDU wrapper. Therefore I ended up having two different commands, one for the selection of the application and the other one for the selection of the file.

private final byte[] NATIVE_SELECT_APP_COMMAND = new byte[]
{
    (byte) 0x90, (byte) 0x5A, (byte) 0x00, (byte) 0x00, 3,  // SELECT
    (byte) 0x5F, (byte) 0x84, (byte) 0x15, (byte) 0x00      // APPLICATION ID
};
private final byte[] NATIVE_SELECT_FILE_COMMAND = new byte[]
{
    (byte) 0x90, (byte) 0xBD, (byte) 0x00, (byte) 0x00, 7,  // READ
    (byte) 0x01,                                            // FILE ID
    (byte) 0x00, (byte) 0x00, (byte) 0x00,                  // OFFSET
    (byte) 0x00, (byte) 0x00, (byte) 0x00,                  // LENGTH
    (byte) 0x00
};

The search for a tutorial for native Mifire-Desfire commands was not successful, so I stick to the following tutorial: http://noobstah.blogspot.de/2013/04/mifare-desfire-ev1-and-android.html

This tutorial provides a card authentification, which I disabled, and also uses the transceive method, which for my understanding is not a proper way for executing native commands? Which method, purhaps even code snippit, is used for executing native commands? Which Android-Class should I use?

I have rewritten the class provided in the tutorial and uploaded it to pastebin. After executing the class I've got following results.

Select APPLICATION: 9100
Read DATA: 91AE

At this point I am quite stuck and do not know what steps I should do next. Was is actually the error or rather what changes in the queries should I perform, to get the data I want?

Answer

Michael Roland picture Michael Roland · Oct 10, 2013

Given the information you extracted from NFC TagInfo and the commands you are trying to use, I assume the card is MIFARE DESFire EV1. Correct?

Regarding your selection command: NFC TagInfo does not currently read the DF name value used in the ISO command set for DESFire EV1. Thus, I assume that the DF-name that's setup for this application is actually 0x313538343546, otherwise the SELECT command should fail. Note, however, that this value is by no means derivable from the DESFire AID shown in NFC TagInfo! In fact the DF-name is a seperate value defined during application creation. (This is different from the previous DESFire version.)

Regarding your READ BINARY command: The command you used would imply that you previously selected a file. However, you only selected the application. Thus, you would either need to issue a SELECT command for the data file or use a short file ID within the READ BINARY command:

byte[] READ_BINARY = { 
        (byte) 0x00, // CLA Class
        (byte) 0xB0, // INS Instruction
        (byte) 0x80, // P1  (indicate use of SFI)
        (byte) 0x01, // P2  (SFI = 0x01)
        (byte) 0x04  // LE  maximal number of bytes expected in result
};

However, when it comes to DESFire (EV1) I suggest that you rather stick to the DESFire native command set (either direct or wrapped) instead of using ISO 7816-4 APDUs.

With the native command set, you get the full functionality of MIFARE DESFire. Command wrapping is done by embedding native DESFire commands into a ISO 7816-4 APDU structure. The wrapping command looks like this:

0x90 CMD 0x00 0x00 LEN CMD-PARAM 0x00

Where CMD is the native DESFire command and CMD-PARAM are the commands parameters. The response is:

[DATA] 0x91 STATUS

Where status is the native DESFire status code. If STATUS is 0xAF, you can get the remaining response data by issuing this command:

0x90 0xAF 0x00 0x00 0x00

So in your case, you would issue a select application command for your application 0x15845F (mind the different byte order!):

0x90 0x5A 0x00 0x00 3 0x5F 0x84 0x15 0x00
   |SELECT|          |APPLICATION ID|

Then, you want to read the data file 0x01 (whole file, starting at offset 0):

0x90 0xBD 0x00 0x00 7 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
    |READ|           |FILE|    OFFSET    |    LENGTH    |

Regarding your question how to get the ISO DF names and ISO FIDs for your application, you can try the following commands:

Select master application:

905A00000300000000

Get applications including their DF names:

906D000000

Select your application:

905A0000035F841500

Get DESFire FIDs:

906F000000

Get ISO FIDs:

9061000000

You can always use the transceive() method of the IsoDep object. IsoDep (i.e. ISO/IEC 14443-4) is used anyways (for native DESFire commands, for wrapped native commands and for ISO 7816-4 commands).

The error code you received from the card (0xAE) indicates an authentication error (see this datasheet for further information: DESFire). Thus, the file allows authenticated read only (see the access conditions shown in NFC TagInfo).

Thus, in order to read this file, you will need to implement the authentication procedure.