From 6dde5586af130a8ca85416c502bee1a69da5220e Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Thu, 6 Oct 2022 20:07:56 +0300 Subject: [PATCH] [FL-2803] Mifare Classic read improvements Part 1 (#1822) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Reuse found keys when reading a card * Fix keys not being read if no newline at the end of the file * Actually read all keys from the dictionary * Support for furi_string * Check only for re-used key after the current sector * Declare the key attack function as static * nfc: change logs, check worker state Co-authored-by: gornekich Co-authored-by: あく --- lib/nfc/helpers/mf_classic_dict.c | 13 ++++++-- lib/nfc/nfc_worker.c | 53 +++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/lib/nfc/helpers/mf_classic_dict.c b/lib/nfc/helpers/mf_classic_dict.c index 57841afc..356f6f7c 100644 --- a/lib/nfc/helpers/mf_classic_dict.c +++ b/lib/nfc/helpers/mf_classic_dict.c @@ -69,9 +69,18 @@ MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) { FuriString* next_line; next_line = furi_string_alloc(); while(true) { - if(!stream_read_line(dict->stream, next_line)) break; + if(!stream_read_line(dict->stream, next_line)) { + FURI_LOG_T(TAG, "No keys left in dict"); + break; + } + furi_string_trim(next_line); + FURI_LOG_T( + TAG, + "Read line: %s, len: %d", + furi_string_get_cstr(next_line), + furi_string_size(next_line)); if(furi_string_get_char(next_line, 0) == '#') continue; - if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN - 1) continue; dict->total_keys++; } furi_string_free(next_line); diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 996e68f0..c61ad444 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -453,6 +453,54 @@ void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) { } } +static void nfc_worker_mf_classic_key_attack( + NfcWorker* nfc_worker, + uint64_t key, + FuriHalNfcTxRxContext* tx_rx, + uint16_t start_sector) { + furi_assert(nfc_worker); + + MfClassicData* data = &nfc_worker->dev_data->mf_classic_data; + uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type); + + furi_assert(start_sector < total_sectors); + + // Check every sector's A and B keys with the given key + for(size_t i = start_sector; i < total_sectors; i++) { + uint8_t block_num = mf_classic_get_sector_trailer_block_num_by_sector(i); + if(mf_classic_is_sector_read(data, i)) continue; + if(!mf_classic_is_key_found(data, i, MfClassicKeyA)) { + FURI_LOG_D( + TAG, + "Trying A key for sector %d, key: %04lx%08lx", + i, + (uint32_t)(key >> 32), + (uint32_t)key); + if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) { + mf_classic_set_key_found(data, i, MfClassicKeyA, key); + FURI_LOG_D(TAG, "Key found"); + nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); + } + } + if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) { + FURI_LOG_D( + TAG, + "Trying B key for sector %d, key: %04lx%08lx", + i, + (uint32_t)(key >> 32), + (uint32_t)key); + if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) { + mf_classic_set_key_found(data, i, MfClassicKeyB, key); + FURI_LOG_D(TAG, "Key found"); + nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); + } + } + if(mf_classic_is_sector_read(data, i)) continue; + mf_classic_read_sector(tx_rx, data, i); + if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break; + } +} + void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { furi_assert(nfc_worker); furi_assert(nfc_worker->callback); @@ -484,6 +532,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { bool is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); uint16_t key_index = 0; while(mf_classic_dict_get_next_key(dict, &key)) { + FURI_LOG_T(TAG, "Key %d", key_index); if(++key_index % NFC_DICT_KEY_BATCH_SIZE == 0) { nfc_worker->callback(NfcWorkerEventNewDictKeyBatch, nfc_worker->context); } @@ -505,15 +554,19 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { is_key_a_found = mf_classic_is_key_found(data, i, MfClassicKeyA); if(mf_classic_authenticate(&tx_rx, block_num, key, MfClassicKeyA)) { mf_classic_set_key_found(data, i, MfClassicKeyA, key); + FURI_LOG_D(TAG, "Key found"); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); + nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1); } furi_hal_nfc_sleep(); } if(!is_key_b_found) { is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); if(mf_classic_authenticate(&tx_rx, block_num, key, MfClassicKeyB)) { + FURI_LOG_D(TAG, "Key found"); mf_classic_set_key_found(data, i, MfClassicKeyB, key); nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); + nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1); } } if(is_key_a_found && is_key_b_found) break;