Write and read data to Mifare Classic 1k NFC tag

13,098

You first authenticate to sector 2:

boolean authA = mfc.authenticateSectorWithKeyA(2, MifareClassic.KEY_NFC_FORUM);
boolean authB = mfc.authenticateSectorWithKeyB(2, MifareClassic.KEY_DEFAULT);

Then, you try to write and read block 0:

mfc.writeBlock(0, bWrite);
byte[] bRead = mfc.readBlock(0);

There are several problems with this:

  1. It does not make sense to authenticate using both key A and key B. Only the last authentication determines the authentication state of the tag. Since all sectors seem to be writable using key B, you can safely use the second line (mfc.authenticateSectorWithKeyB() only).

  2. You authenticate to sector 2, which consists of blocks 8, 9, 10, and 11. Writing and reading block 0 does not make sense in that authentication state. Note that read/write operations typically use global block numbering. Sectors are only used as logical units for authentication/access control purposes. You can easily calculate block numbers from sector numbering using mfc.sectorToBlock() and mfc.getBlockCountInSector().

  3. Block 0 (in sector 0) is a special block, the manufacturer block. It typically contains the UID, SAK and manufacturer information burned into the tag during the production process. This block is read-only and cannot be changed. Consequently, writing to that block does not have any effect.

Share:
13,098

Related videos on Youtube

Tonher
Author by

Tonher

Slt les amis

Updated on June 04, 2022

Comments

  • Tonher
    Tonher almost 2 years

    I am trying to read and write data on a Mifare Classic 1k NFC tag.

    I found the keys and the access conditions of the card thanks to this app :

    Keys:

    Keys

    Access Conditions:

    Access Conditions

    <uses-permission android:name="android.permission.NFC" /> is present in my manifest.

    Here is my code:

    Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    
    if(tag != null) {
        Log.i("hey", Arrays.toString(tag.getTechList()));
        MifareClassic mfc = MifareClassic.get(tag) ;
    
        try {
            mfc.connect();
            boolean authA = mfc.authenticateSectorWithKeyA(2, MifareClassic.KEY_NFC_FORUM) ;
            boolean authB = mfc.authenticateSectorWithKeyB(2, MifareClassic.KEY_DEFAULT) ;
            Log.i("hey", "authA : " + authA) ;
            Log.i("hey", "authB : " + authB) ;
    
            if (authB && authA) {
                byte[] bWrite = new byte[16];
                byte[] hello = "hello".getBytes(StandardCharsets.US_ASCII);
                System.arraycopy(hello, 0, bWrite, 0, hello.length);
                mfc.writeBlock(0, bWrite);
                Log.i("hey", "write : " + Arrays.toString(bWrite));
    
                byte[] bRead = mfc.readBlock(0);
                String str = new String(bRead, StandardCharsets.US_ASCII);
                Log.i("hey", "read bytes : " + Arrays.toString(bRead));
                Log.i("hey", "read string : " + str);
                Toast.makeText(this, "read : " + str, Toast.LENGTH_SHORT).show();
                Log.i("hey", "expected : " + new String(bWrite, StandardCharsets.US_ASCII));
            }
    
    
    
            mfc.close();
    
        } catch (IOException e) {
            Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
            e.printStackTrace();
            Log.i("hey", "Error") ;
        }
    
    
    }
    

    When I try to write and read like that, what I read is not what I wrote.

    Here is the logcat:

    I/hey: [android.nfc.tech.NfcA, android.nfc.tech.MifareClassic, android.nfc.tech.NdefFormatable]
    I/hey: authA : true
        authB : true
    I/hey: write : [104, 101, 108, 108, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    I/hey: read byte : [-78, 0, 0, 0, 0, 0, -1, 7, -128, 105, -1, -1, -1, -1, -1, -1]
        read string : �������������i������
    I/hey: expected : hello����������������������
    

    I tried with different charsets but it didn't change anything.

    I also tried to only read the Sector 0 by commenting the write part and changing authentication key A to MifareClassic.KEY_MIFARE_APPLICATION_DIRECTORY and this time I get this Logcat:

    I/hey: [android.nfc.tech.NfcA, android.nfc.tech.MifareClassic, android.nfc.tech.NdefFormatable] 
    I/hey: authA : true
            authB : true 
    I/hey: read bytes : [-123, -121, 0, 16, 18, 8, 4, 0, 1, -64, 62, -70, 74, 124, 78, 29]
            read string : �������>�J|N
    

    Any idea about how can I fix it to write and display text properly?

  • Tonher
    Tonher about 6 years
    I figured point 1 and 3 by myself, but I thought that blocks number were 0, 1, 2, and 3 in each sector. Thanks a lot Michael!
  • Michael Roland
    Michael Roland about 6 years
    @Tonher Blocks are indeed numbered starting at 0 when looking at each sector. However, due to the nature of the linear memory layout of MIFARE Classic, a pure block-based numbering is often used for memory access and sectors are only considered as logical units for authentication and access control purposes. Btw. you can easily convert from sectors to blocks using Android's built-in methods MifareClassic.sectorToBlock() and MifareClassic.getBlockCountInSector().
  • Tonher
    Tonher about 6 years
    Thanks for the insight