#!/usr/bin/env python3 # Copyright 2023 Sergey Stolyarov # # Distributed under New BSD License. # # https://opensource.org/license/bsd-3-clause/ import configparser from smartcard.System import readers from smartcard.CardRequest import CardRequest from smartcard.CardConnection import CardConnection from smartcard.util import toHexString, toBytes from util import unpack_access_conditions_bits, pack_access_conditions_bits def main() -> int: config = configparser.ConfigParser() config.read('config.ini') value_sector = config.getint('DEFAULT', 'value_sector') value_block = config.getint('DEFAULT', 'value_block') original_key_a = config.get('DEFAULT', 'original_key_a') key_a = config.get('DEFAULT', 'key_a') key_b = config.get('DEFAULT', 'key_b') reader = readers()[0] print('Connected reader: {0}'.format(reader)) cardrequest = CardRequest(timeout=None, readers=[reader]) print('Waiting for empty Mifare Classic 1K...') cardservice = cardrequest.waitforcard() cardservice.connection.connect() print('Card connected, checking card, please wait ... ', end='') # store original key data to the first cell (CellN = P2 = 0) # CLA INS P1 P2 Lc apdu = 'FF 82 00 00 06 ' + original_key_a response, sw1, sw2 = cardservice.connection.transmit(toBytes(apdu)) if (sw1,sw2) != (0x90,0x00): print('Load Keys command failed, probably not Mifare compatible card, terminating.') return 1 # store key B data to the seconds cell (CellN = P2 = 1) # CLA INS P1 P2 Lc apdu = 'FF 82 00 01 06 ' + key_b response, sw1, sw2 = cardservice.connection.transmit(toBytes(apdu)) if (sw1,sw2) != (0x90,0x00): print('Load Keys command failed, probably not Mifare compatible card, terminating.') return 1 # perform authentication for 4th (trailer) block of the sector using stored data as Key A blockMSB = 0 blockLSB = value_sector * 4 + 3 # 4th block # CLA INS P1 P2 Lc VER BlockMSB BlockLSB KeyA CellN apdu = 'FF 86 00 00 05 01 {:02X} {:02X} 60 00'.format(blockMSB, blockLSB) response, sw1, sw2 = cardservice.connection.transmit(toBytes(apdu)) if (sw1,sw2) != (0x90,0x00): print('authentication failed for trailer block of sector {:02X}'.format(value_sector)) return 1 # try to read trailer block content # CLA INS BlockMSB BlockLSB Le apdu = 'FF B0 {:02X} {:02X} 10'.format(blockMSB, blockLSB) response, sw1, sw2 = cardservice.connection.transmit(toBytes(apdu)) if (sw1,sw2) != (0x90,0x00): print('failed to read sector trailer data') return 1 # check access condition, we should be able to change both access keys and write access bits using current Key A # the only bits combination for this is `0 0 1` access_conditions_bits = unpack_access_conditions_bits(response[6:9]) if access_conditions_bits[3] != [0, 0, 1]: print('unsuitable access bits') return 1 print('done') print('Initializing sector trailer ... ', end='') # new access bit for trailer should be `0 1 1` (write Keys A and B using key B, read access bit with both keys, write access bits using Key B) access_conditions_bits[3] = [0, 1, 1] # new access bit for value block should be `1 1 0` (allow read and decrement with key A, all other operations with key B) access_conditions_bits[value_block] = [1, 1, 0] trailer_bytes = toBytes(key_a) + pack_access_conditions_bits(access_conditions_bits) + [0] + toBytes(key_b) # write bytes to trailer block # CLA INS BlockMSB BlockLSB Lc DATA apdu = 'FF D6 00 {:02X} 10 {}'.format(value_sector * 4 + 3, toHexString(trailer_bytes)) response, sw1, sw2 = cardservice.connection.transmit(toBytes(apdu)) if (sw1,sw2) != (0x90,0x00): print('sector trailer block write failed') return 1 print('done') print('Re-authenticate using Key B ... ', end='') # perform authentication for 4th (trailer) block of the sector using stored data as Key B blockMSB = 0 blockLSB = value_sector * 4 + 3 # 4th block # CLA INS P1 P2 Lc VER BlockMSB BlockLSB KeyB CellN apdu = 'FF 86 00 00 05 01 {:02X} {:02X} 61 01'.format(blockMSB, blockLSB) response, sw1, sw2 = cardservice.connection.transmit(toBytes(apdu)) if (sw1,sw2) != (0x90,0x00): print('authentication failed for trailer block of sector {:02X}'.format(value_sector)) return 1 print('done') print('Initializing value block ... ', end='') balance = 0 nb = toHexString(list(balance.to_bytes(4))) # write balance (0) to value block # CLA INS P1 P2 Lc VB_OP ValueMSB...LSB apdu = 'FF D7 00 {:02X} 05 00 '.format(value_sector * 4 + value_block) + nb response, sw1, sw2 = cardservice.connection.transmit(toBytes(apdu)) if (sw1,sw2) != (0x90,0x00): print('value block write failed') return 1 print('done') if __name__ == '__main__': main()