From eb5dae1cda00d254641b29700d4e38ef4f55d04f Mon Sep 17 00:00:00 2001 From: AloneLiberty <111039319+AloneLiberty@users.noreply.github.com> Date: Tue, 7 Mar 2023 21:33:59 +0300 Subject: [PATCH] NFC: Support reading Mifare Classic key B from sector trailer, reading sector with B key where A key can't read block, Nfc Magic app not using NFC folder by default (in file select) (#2437) * NFC: Support reading Mifare Classic key B from sector trailer and reusing it for other sectors * NFC: Fix my pointer typo * NFC: Fix reading sector with B key where A key can't read block (fixes #2413) and fix Nfc Magic app not using NFC folder by default (in file select) * NFC: Fix strange bug Co-authored-by: Aleksandr Kutuzov --- .../scenes/nfc_magic_scene_file_select.c | 4 ++ firmware/targets/f7/api_symbols.csv | 2 +- lib/nfc/nfc_worker.c | 49 +++++++++++++++++++ lib/nfc/protocols/mifare_classic.c | 13 +++-- lib/nfc/protocols/mifare_classic.h | 1 + 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c index a19237ed..d78422ee 100644 --- a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c @@ -11,6 +11,10 @@ void nfc_magic_scene_file_select_on_enter(void* context) { // Process file_select return nfc_device_set_loading_callback(nfc_magic->nfc_dev, nfc_magic_show_loading_popup, nfc_magic); + if(!furi_string_size(nfc_magic->nfc_dev->load_path)) { + furi_string_set_str(nfc_magic->nfc_dev->load_path, NFC_APP_FOLDER); + } + if(nfc_file_select(nfc_magic->nfc_dev)) { if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic->nfc_dev)) { scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 57c1a2fa..f505b943 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1892,7 +1892,7 @@ Function,+,menu_free,void,Menu* Function,+,menu_get_view,View*,Menu* Function,+,menu_reset,void,Menu* Function,+,menu_set_selected_item,void,"Menu*, uint32_t" -Function,-,mf_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, MfClassicAuthContext*, uint64_t" +Function,-,mf_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, MfClassicAuthContext*, uint64_t" Function,-,mf_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" Function,-,mf_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" Function,-,mf_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 54bdbb24..062a3953 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -569,6 +569,32 @@ void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) { } } +static bool nfc_worker_mf_get_b_key_from_sector_trailer( + FuriHalNfcTxRxContext* tx_rx, + uint16_t sector, + uint64_t key, + uint64_t* found_key) { + // Some access conditions allow reading B key via A key + + uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + + Crypto1 crypto = {}; + MfClassicBlock block_tmp = {}; + MfClassicAuthContext auth_context = {.sector = sector, .key_a = MF_CLASSIC_NO_KEY, .key_b = 0}; + + furi_hal_nfc_sleep(); + + if(mf_classic_auth_attempt(tx_rx, &crypto, &auth_context, key)) { + if(mf_classic_read_block(tx_rx, &crypto, block, &block_tmp)) { + *found_key = nfc_util_bytes2num(&block_tmp.value[10], sizeof(uint8_t) * 6); + + return *found_key; + } + } + + return false; +} + static void nfc_worker_mf_classic_key_attack( NfcWorker* nfc_worker, uint64_t key, @@ -614,6 +640,16 @@ static void nfc_worker_mf_classic_key_attack( mf_classic_set_key_found(data, i, MfClassicKeyA, key); FURI_LOG_D(TAG, "Key found"); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); + + uint64_t found_key; + if(nfc_worker_mf_get_b_key_from_sector_trailer(tx_rx, i, key, &found_key)) { + FURI_LOG_D(TAG, "Found B key via reading sector %d", i); + mf_classic_set_key_found(data, i, MfClassicKeyB, found_key); + + if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { + nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); + } + } } } if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) { @@ -705,6 +741,19 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { mf_classic_set_key_found(data, i, MfClassicKeyA, key); FURI_LOG_D(TAG, "Key found"); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); + + uint64_t found_key; + if(nfc_worker_mf_get_b_key_from_sector_trailer( + &tx_rx, i, key, &found_key)) { + FURI_LOG_D(TAG, "Found B key via reading sector %d", i); + mf_classic_set_key_found(data, i, MfClassicKeyB, found_key); + + if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { + nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); + } + + nfc_worker_mf_classic_key_attack(nfc_worker, found_key, &tx_rx, i + 1); + } nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1); } furi_hal_nfc_sleep(); diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index e4d5e027..a8a90889 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -541,6 +541,7 @@ bool mf_classic_authenticate_skip_activate( bool mf_classic_auth_attempt( FuriHalNfcTxRxContext* tx_rx, + Crypto1* crypto, MfClassicAuthContext* auth_ctx, uint64_t key) { furi_assert(tx_rx); @@ -549,15 +550,14 @@ bool mf_classic_auth_attempt( bool need_halt = (auth_ctx->key_a == MF_CLASSIC_NO_KEY) && (auth_ctx->key_b == MF_CLASSIC_NO_KEY); - Crypto1 crypto; if(auth_ctx->key_a == MF_CLASSIC_NO_KEY) { // Try AUTH with key A if(mf_classic_auth( tx_rx, - mf_classic_get_first_block_num_of_sector(auth_ctx->sector), + mf_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector), key, MfClassicKeyA, - &crypto, + crypto, false, 0)) { auth_ctx->key_a = key; @@ -573,10 +573,10 @@ bool mf_classic_auth_attempt( // Try AUTH with key B if(mf_classic_auth( tx_rx, - mf_classic_get_first_block_num_of_sector(auth_ctx->sector), + mf_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector), key, MfClassicKeyB, - &crypto, + crypto, false, 0)) { auth_ctx->key_b = key; @@ -671,6 +671,9 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u do { if(blocks_read == total_blocks) break; if(!key_b_found) break; + if(key_a_found) { + furi_hal_nfc_sleep(); + } FURI_LOG_D(TAG, "Try to read blocks with key B"); key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b)); if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) break; diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index a88781f9..c03350f2 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -174,6 +174,7 @@ bool mf_classic_authenticate_skip_activate( bool mf_classic_auth_attempt( FuriHalNfcTxRxContext* tx_rx, + Crypto1* crypto, MfClassicAuthContext* auth_ctx, uint64_t key);