desfire package¶
Submodules¶
desfire.android module¶
-
class
desfire.android.
AndroidDevice
(iso_dep)[source]¶ Bases:
desfire.device.Device
DESFire protocol wrapper for pyscard interface.
Iso_dep: android.nfc.tech.IsoDep
Java class wrapped as jnius object.
desfire.device module¶
desfire.dummy module¶
-
class
desfire.dummy.
DummyDevice
[source]¶ Bases:
desfire.device.Device
Dummy device mock implementation.
desfire.pcsc module¶
-
class
desfire.pcsc.
PCSCDevice
(card_connection)[source]¶ Bases:
desfire.device.Device
DESFire protocol wrapper for pyscard interface.
Card_connection: smartcard.pcsc.PCSCCardConnection.PCSCCardConnection
instance. Callcard_connection.connect()
before calling any DESFire APIs.
desfire.protocol module¶
MIFARE DESFire communication protocol for Python.
For DESFire overview:
For list of DESFire commands see:
- https://github.com/jekkos/android-hce-desfire/blob/master/hceappletdesfire/src/main/java/net/jpeelaer/hce/desfire/DesFireInstruction.java
- https://www.mifare.net/files/advanced_javadoc/com/nxp/nfclib/desfire/DESFire.html
- https://github.com/jekkos/android-hce-desfire/blob/master/hceappletdesfire/src/main/java/net/jpeelaer/hce/desfire/DesfireStatusWord.java
- https://github.com/nfc-tools/libfreefare/blob/master/libfreefare/mifare_desfire.c
- https://github.com/codebutler/farebot/blob/master/src/main/java/com/codebutler/farebot/card/desfire/DesfireProtocol.java
-
class
desfire.protocol.
DESFire
(device, logger=None)[source]¶ Bases:
object
MIFare DEefire EV1 communication protocol for NFC cards.
Parameters: - device –
desfire.device.Device
implementation - logger – Python
logging.Logger
used for logging output. Overrides the default logger. Extensively usesINFO
logging level.
-
authenticate
(app_id, key_id, private_key=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])[source]¶ Hacked together Android only DESFire authentication.
Desfire supports multiple authentication modes, see:
Here we use legacy authentication (0xa0)
Parameters: - app_id – 24-bit app id
- key_id – One of 0-16 keys on the card as byte
- private_key – 8 or 16 bytes of private key
-
commit
()[source]¶ Commit all write changes to the card.
Example
def top_up(self, tag, added_value): device = deviceDep.get(tag) device.connect() desfire = DESFire(device, Logger) try: desfire.select_application(XXX_APP_ID) old_value = desfire.get_value(0x01) desfire.credit_value(0x01, added_value) desfire.commit() return old_value finally: device.close()
-
communicate
(apdu_cmd, description, allow_continue_fallthrough=False)[source]¶ Communicate with a NFC tag.
Send in outgoing request and waith for a card reply.
TODO: Handle additional framing via 0xaf
Parameters: - apdu_cmd – Outgoing APDU command as array of bytes
- description – Command description for logging purposes
- allow_continue_fallthrough – If True 0xAF response (incoming more data, need mode data) is instantly returned to the called instead of trying to handle it internally
Raise: desfire.protocol.DESFireCommunicationError
on any errorReturns: tuple(APDU response as list of bytes, bool if additional frames are inbound)
-
create_value_file
(file_id, communication_settings, access_permissions, min_value, max_value, current_value, limited_credit_enabled)[source]¶ Create a new value file.
Parameters: - file_id – (byte)
- communication_settings – (byte) See FILE_COMMUNICATION
- access_permissions – (word) 0xeeee Everybody has read write access
- current_value – (dword)
- max_value – (dword)
- min_value – (dword)
- limited_credit_enabled – (byte) Allows limited increase in value file without having full credit permission.
Example
def write_card(self, tag, value): device = deviceDep.get(tag) device.connect() desfire = DESFire(device, Logger) try: desfire.select_application(XXX_APP_ID) file_ids = desfire.get_file_ids() if XXX_FILE_STORED_VALUE in file_ids: old_value = desfire.get_value(XXX_FILE_STORED_VALUE) desfire.delete_file(XXX_FILE_STORED_VALUE) else: old_value = None desfire.create_value_file(file_id=XXX_FILE_STORED_VALUE, communication_settings=0x00, access_permissions=0xeeee, min_value=0, max_value=1000000, current_value=value, limited_credit_enabled=0) return old_value finally: device.close()
-
credit_value
(file_id, added_value)[source]¶ Increase stored value.
Parameters: - file_id – (byte)
- added_value – (int, 32 bit) Value to be added to the current value
Raise: desfire.protocol.DESFireCommunicationError
on any error
-
debit_value
(file_id, value_decrease)[source]¶ Decrease stored value.
Parameters: - file_id – (byte)
- value_decrease – (int, 32 bit) How much we reduce from existing value
Example
class BurnerScreen(Screen): '''Continuously keep decreasing credits on the card.''' def on_enter(self): Logger.debug("Entering burner screen") nfc_controller.callback = self.detect_new_tag self.timer = None self.device = None def detect_new_tag(self, tag): Logger.debug("Detected tag %s", tag) self.tag = tag self.device = deviceDep.get(tag) self.device.connect() self.start_burner_cycle() def start_burner_cycle(self): Logger.debug("Starting next burner cycle") self.timer = Timer(0.3, self.burn) self.timer.start() def burn(self): Logger.debug("Running burner cycle") try: if not self.device.isConnected(): # We have lost the tag return desfire = DESFire(self.device, Logger) desfire.select_application(XXX_APP_ID) desfire.debit_value(XXX_FILE_STORED_VALUE, 1) new_value = desfire.get_value(XXX_FILE_STORED_VALUE) desfire.commit() # Show how much value we have after burn self.value.text = "%d" % new_value # Do next tick self.start_burner_cycle() except Exception as e: # Most likely exception from device tag communications, tag moved away during communications tb = traceback.format_exc() Logger.exception(str(e)) Logger.exception(tb) finally: # Tell pyjnius we are done with this thread jnius.detach() def cancel(self): self.close() def close(self): if self.device: self.device.close() # jnius threads are not cancellable # if self.timer: # self.timer.cancel() nfc_controller.callback = None self.manager.switch_to(NFCScreen())
-
get_applications
()[source]¶ Get all applications listed in Desfire root.
TODO: Check byte order here
Returns: List of 24-bit intesx Raise: desfire.protocol.DESFireCommunicationError
on any error
-
get_file_settings
(file_id)[source]¶ Get DESFire file settings.
Parameters: file_id – File id as a byte Returns: File description dict.
-
get_value
(file_id)[source]¶ Get stored value.
Parameters: file_id – Stored value file id Returns: Integer. Raise: desfire.protocol.DESFireCommunicationError
on any error
-
parse_application_list
(resp)[source]¶ Handle response for command 0x6a list applications.
DESFire application ids are 24-bit integers.
Parameters: resp – DESFire response as byte array Returns: List of parsed application ids
-
read_data_file
(file_id)[source]¶ Read standard data file.
If the data file is unwritten (no single write since card format) it should return 0x00 as data after format.
Example:
def write_test(desfire): '''Write a long data file to see card write functions work. Assume the card is formatted with 7000 bytes test file. If we do not fill in file bytes during write, then the next read will reflect back whatever garbage we left there unwritten. ''' logger.debug("Writing and reading back a test file") desfire.select_application(XXX_APP_ID) file_settings = desfire.get_file_settings(XXX_BACKCHANNEL_FILE) logger.debug("File settings info %s", file_settings) data = [0xff] data += [0xaa] * 4000 data += [0xbb] desfire.write_data_file(XXX_BACKCHANNEL_FILE, data) # Standard files do not have any kind of commit of write corruption or commit support, # so no need to commit here # Now read it back read_back_data = desfire.read_data_file(XXX_BACKCHANNEL_FILE) assert len(read_back_data) == 7000 assert data == read_back_data[0:4002]
Parameters: file_id – File id to read, 8-bit int Returns: List of bytes
-
read_linear_record_file
(file_id, offset_in_records, length_in_records)[source]¶ Read all records of a linear record file.
Parameters: - file_id – File id, 8-bit int
- offset_in_records – First record to read, 16-bit int
- length_in_records – Number of records to read, 16-bit int
Returns: File data as bytes
-
select_application
(app_id)[source]¶ Choose application on a card on which all the following file commands will apply.
TODO: Check byte order here
Parameters: app_id – 24-bit int Raise: desfire.protocol.DESFireCommunicationError
on any error
-
classmethod
wrap_command
(command, parameters=None)[source]¶ Wrap a command to native DES framing.
Parameters: - command – Command byte
- parameters – Command parameters as list of bytes
-
write_data_file
(file_id, data)[source]¶ Write the data to a standard data file.
Parameters: - file_id – File number to write, 8-bit int
- data – Data as bytes or array of bytes
-
write_linear_record_file_record
(file_id, offset_in_records, length_in_records, data)[source]¶ Write n records in a linear record file.
Parameters: - file_id – File id, 8-bit int
- offset_in_records – First record to read, 16-bit int
- length_in_records – Number of records to read, 16-bit int
- data – bytes or list of bytes
Returns: File data as bytes
- device –
-
exception
desfire.protocol.
DESFireCommunicationError
(msg, status_code)[source]¶ Bases:
exceptions.Exception
Outgoing DESFire command received a non-OK reply.
The exception message is human readable translation of the error code if available. The
status_code
carries the original status word error byte.
-
desfire.protocol.
ERRORS
= {12: 'No changes', 174: 'Authentication error', 189: 'File not found', 240: 'File not found', 28: 'Limited credit', 157: 'Permission denied', 126: 'Length error when sending the command'}¶ Error code translation mappings https://github.com/jekkos/android-hce-desfire/blob/master/hceappletdesfire/src/main/java/net/jpeelaer/hce/desfire/DesfireStatusWord.java
-
desfire.protocol.
FILE_COMMUNICATION
= {0: 'Plain communication', 1: 'Plain communication secured by DES/3DES MACing', 3: 'Fully DES/3DES enciphered communication'}¶ Communication requirements bits set a on DESFire file
-
desfire.protocol.
FILE_TYPES
= {0: 'Standard Data Files', 1: 'Backup Data Files', 2: 'Value Files with Backup', 3: 'Linear Record Files with Backup', 4: 'Cyclic Record Files with Backup'}¶ File kind bits set on a DESFire file
desfire.util module¶
Misc. utility functions.