Skip to content
This repository has been archived by the owner on Oct 22, 2023. It is now read-only.

maxieds/MCTLibraryDemo

Repository files navigation

MCTLibraryDemo Application

Demo Android application for the Mifare Classic Tool library. Note that for the most part this demo application should serve as documentation for how to use the library in client applications. Other main documentation is provided in this README below.

Documentation for the MCTLibrary

Descriptions of files in the library

The following files form the core implementation of the library:

  • MCTUtils.java: Utility functions from the MCT app. Includes operations for converting arrays of bytes to hex strings and vice versa.
  • MifareClassicDataInterface.java: The interface that must be implemented by client applications using the library. See below for description.
  • MifareClassicLibraryException.java: Custom exception class for exceptions thrown by the library. See the top of the file for the types of custom exceptions supported (and to add new ones).
  • MifareClassicTag.java: Implementation, storage and parsing routines for new MFC1K tags. Also includes many undocumented (except for in the source code) helper functions. Much of this code was derived from the MCT reader functions.
  • MifareClassicToolLibrary.java: The library class which includes helper functions for scanning tags and reading in the extended key sets.
  • MifareClassicUtils.java: MFC1K tag helper functions. Includes routines for writing blank tags with Android and for loading a new tag from a dump image file.

Key library settings

The following settings are used to configure the library:

public class MifareClassicToolLibrary {
     public static int RETRIES_TO_AUTH_KEYAB = 1;
     public static boolean AUTORECONNECT = false;
     // ...
}

Data interface implementations

All client applications (activities) using the library need to provide an implementation of the following interface:

public interface MifareClassicDataInterface {

     void RegisterNewIntent(Intent mfcIntent);
     Context GetApplicationContext();
     Activity GetApplicationActivity();

     void PostTagScanKeyMapProgress(int position, int total);
     void PostTagScanSectorReadProgress(int position, int total);

}

Before using the library, the client application implementing the above data interface should make a call to the next library function:

public class MifareClassicToolLibrary {
     public static boolean InitializeLibrary(MifareClassicDataInterface mfcDataIface);
}

How to read a new MFC1K tag

Enabling tag scanning in the application

Once the library is inititalized as in the last section by calling MifareClassicToolLibrary.InitializeLibrary, you can enable automatic tag scanning by implementing the following in your client activity:

// call this to start live tag scanning:
MifareClassicToolLibrary.StartLiveTagScanning(this);

// implement these functions in the client activity:
@Override
public void onResume() {
     super.onResume();
     if(currentlyTagScanning) {
          MifareClassicToolLibrary.StartLiveTagScanning(this);
     }
}

@Override
public void onPause() {
     if(currentlyTagScanning) {
          MifareClassicToolLibrary.StopLiveTagScanning(this);
     }
     super.onPause();
}

You will also need to add the following to the activity tag in the client application's Manifest file:

           <intent-filter android:priority="1000">
                <action android:name="android.nfc.action.TECH_DISCOVERED" />
                <action android:name="android.nfc.action.TAG_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

            <meta-data
                android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />
            <meta-data
                android:name="android.nfc.action.TAG_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />

The xml/nfc_tech_filter.xml file is found in the res/ directory and contains the following information:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.MifareClassic</tech>
        <tech>android.nfc.tech.NfcA</tech>
    </tech-list>
</resources>

Processing a new Tag

Once you have enabled live tag scanning in the client activity (and added the intents to process new tags to the application Manifest file), newly found NFC tags will be registered via Intents to the client activity, which should implement a handler that looks something like the following code snippet:

     @Override
     protected void onNewIntent(Intent intent) {
          if(intent == null || intent.getAction() == null) {
               return;
          }
          if(intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED) ||
             intent.getAction().equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
               final Tag nfcTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
               if(MifareClassicTag.CheckMifareClassicSupport(nfcTag) != 0) {
                    DisplayToastMessage("The discovered NFC device is not a Mifare Classic tag.");
               }
               else {
                    MifareClassicTag mfcTag = MifareClassicTag.Decode(nfcTag, keyStringArray, displayProgressBar);
               }
          }
          // process other intents
     }

The MifareClassicTag.Decode function has the next specification:

public static MifareClassicTag Decode(Tag nfcTag, String[] keyData, boolean displayGUIProgressBar) throws MifareClassicLibraryException

The following utility functions are available in the MifareClassicTag class after scanning a new tag:

     public String[] GetMFCDumpImageData();
     public String GetTagType();
     public int GetSectorCount();
     public int GetBlockCount();
     public int GetBytesPerBlock();
     public int GetBlockCountInSector();
     public int GetSize();
     public List<MFCSector> GetFailedSectors();
     public String GetManufacturer();
     public String GetTagUID();
     public int GetTagUIDSize();
     public String GetATQA();
     public String GetSAK();
     public String GetATS();
     public long GetTotalReadTime();
     public MFCSector GetSectorByIndex(int index);
     public boolean GetSectorReadStatus(int index);

The subclass MifareClassicTag.MFCSector contains the following public fields:

     public static class MFCSector {
          public int sectorAddress;
          public int sectorSize;
          public int sectorBlockCount;
          public int sectorFirstBlock;
          public int sectorBytesPerBlock;
          public String[] sectorBlockData;
          // ...
     }

Other useful functions

public class MifareClassicToolLibrary {
     // checking for NFC / MFC support on the target phone:
     public static boolean CheckNFCEnabled(boolean promptUser);
     public static boolean CheckPhoneMFCSupport();
     
     // access conditions processing:
     public static byte[][] GetAccessBitsArray(byte[] accessBytes);
     public static String GetAccessConditionsDescription(byte[][] sectorAccessBits, int blockIndex, boolean isSectorTrailer);
     
     // loading standard and extended key sets (as in MCT app):
     public static boolean LoadStandardKeySets(boolean useExtendedKeys);
     public static int GetStandardKeyCount();
     public static String GetStandardKey(int kidx);
     public static String[] GetStandardAllKeys();
     
     // displaying a progress bar in the client activity:
     public static void DisplayProgressBar(String thingsName, int curPos, int totalPos);
}