Android's NfcA to python's pyscard (smartcard)

Question:

I am backwards-engineering an android application (written in java) into a python application, where nfc (apdu) commands are sent. (ISO 14443-3A, if that helps)

The android applications makes use of the android.nfc.tech.NfcA library and sends commands such as:

import android.nfc.tech.NfcA;
NfcA nfca_tag;
byte[] message;
message = nfca_tag.transceive(new byte[]{48, 4});
// also with negative numbers:
message = nfca_tag.transceive(new byte[]{-51, 13};

On the python-side, using the pyscard module an example would look like this:

from smartcard.CardRequest import CardRequest

cardrequest = CardRequest( timeout=1, 
 cardType=cardtype )
cardservice = cardrequest.waitforcard()
cardservice.connection.connect()

data, sw1, sw2 = cardservice.connection.transmit([0xFF, 0xB0, 0x00, 0x00, 0x0F])
# respectively
data, sw1, sw2 = cardservice.connection.transmit([255, 176, 0, 0, 15])

What is the translation of the android NfcA’s message (such as {48, 4}) to python pyscard’s message (such as `[0xFF, 0xB0, 0x00, 0x00, 0x0F]’)?

Now i know, that java bytes go from -128 to 127 and therefore whatever byte we have in java, we can translate it using this function

def java_byte_to_python(java_byte: int):
    return java_byte%256

However, it seems to me, that the NfcA module already has some bytes that are sent by default, as an apdu command requires at least 4 bytes?


Further information on the specific tag for this application:

  • ISO/IEC 14443:3 (Type A) compatible

Android technology information:

  1. TAG: Tech [android.nfc.tech.NfcA]
  2. Maximum transceive length: 253 bytes
  3. Default maximum transceive time-out: 618 ms

Detailed protocol information

  • ID: 46:53:54:4E:31:31:6D
  • ATQA: 0x4400
  • SAK: 0x00
  • ATS: 0xFFFF
Asked By: Engensmax

||

Answers:

The answer here is dependent on the smart card reader and tag that is used.

In my case, using an ACR1252U (Product page
& API documentation) and a Mifare Ultralight C:

  1. Start a session:
cardservice.connection.transmit([0xFF, 0xC2, 0x00, 0x00, 0x02, 0x81, 0x00])
  1. Send command via transparent exchange "transceive" (0x95):
message_in_java_bytes = [48, 4]
message = [x%256 for x in message_in_java_bytes]
cardservice.connection.transmit([0xFF, 0xC2, 0x00, 0x01, len(message)+2, 0x95, len(message), *message])

(Card response format: C0 03 00 90 00 92 01 00 96 02 00 00 97 0C [Card Response] 90 00)

  1. Close session
cardservice.connection.transmit([0xFF, 0xC2, 0x00, 0x00, 0x02, 0x82, 0x00])

Some further documentation:

Android Tag Operation commands

Relation between APDU and ISO 14443-A

NFC Forum Digital Protocol (this goes deep down the rabbit hole)

Answered By: Engensmax
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.