Przeglądaj źródła

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 <alleteam@gmail.com>
AloneLiberty 2 lat temu
rodzic
commit
eb5dae1cda

+ 4 - 0
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);

+ 1 - 1
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"

+ 49 - 0
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();

+ 8 - 5
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;

+ 1 - 0
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);