diff options
author | gornekich <n.gorbadey@gmail.com> | 2022-03-24 01:14:34 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-24 01:14:34 +0300 |
commit | eafeefb8431cffaa02d99059200b5fbd8d9628da (patch) | |
tree | c2ebebfefe5325750eb8d5d6cba2d4c585d9487c /applications/nfc/nfc_worker.c | |
parent | 46a894bc5cd242876104ac1134e68fc5fe7c89c1 (diff) |
[FL-1396] Mifare Classic read (#1034)
* rfal: add new data exchange function
* core: add FURI_BIT to common defines
* furi_hal_nfc: add data exchange with custom patiry bits
* lib: extend nfc common API
* assets: add mf classic dictionary
* lib: introduce mifare classic library
* nfc: add dictionary reader helper
* nfc worker: add worker events, add mifare classic read
* nfc: rework scenes with worker events
* nfc: add read mifare classic GUI
* nfc device: add mifare classic save
* nfc: add dictionary open fail scene
* nfc: mention resources
* stream: fix stream read line
* subghz: rework file read with fixed stream_read_line
* furi_hal_nfc: decrease communication timeout
* nfc: rework keys load from dictionary with file_stream
* nfc: add read mifare classic suggestion
* nfc: fix mifare classic read view
* nfc: fix index size
* nfc: add switch to no dictionary found scene
* nfc: add mifare classic load
* nfc: improve read mifare classic design
* mifare_classic: add proxmark3 mention
* nfc: format sources
* nfc: fix typos, add documentation
Diffstat (limited to 'applications/nfc/nfc_worker.c')
-rw-r--r-- | applications/nfc/nfc_worker.c | 189 |
1 files changed, 178 insertions, 11 deletions
diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index ce865a7f..17b54260 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -1,8 +1,13 @@ #include "nfc_worker_i.h" #include <furi_hal.h> -#include "nfc_protocols/emv_decoder.h" -#include "nfc_protocols/mifare_desfire.h" -#include "nfc_protocols/mifare_ultralight.h" + +#include <lib/nfc_protocols/nfc_util.h> +#include <lib/nfc_protocols/emv_decoder.h> +#include <lib/nfc_protocols/mifare_ultralight.h> +#include <lib/nfc_protocols/mifare_classic.h> +#include <lib/nfc_protocols/mifare_desfire.h> + +#include "helpers/nfc_mf_classic_dict.h" #define TAG "NfcWorker" @@ -20,6 +25,7 @@ NfcWorker* nfc_worker_alloc() { nfc_worker->callback = NULL; nfc_worker->context = NULL; + nfc_worker->storage = furi_record_open("storage"); // Initialize rfal while(furi_hal_nfc_is_busy()) { @@ -33,6 +39,7 @@ NfcWorker* nfc_worker_alloc() { void nfc_worker_free(NfcWorker* nfc_worker) { furi_assert(nfc_worker); furi_thread_free(nfc_worker->thread); + furi_record_close("storage"); free(nfc_worker); } @@ -95,6 +102,8 @@ int32_t nfc_worker_task(void* context) { nfc_worker_read_mifare_ul(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { nfc_worker_emulate_mifare_ul(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { + nfc_worker_mifare_classic_dict_attack(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { nfc_worker_read_mifare_desfire(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateField) { @@ -130,6 +139,11 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { dev->dev.nfca.sensRes.platformInfo, dev->dev.nfca.selRes.sak)) { result->protocol = NfcDeviceProtocolMifareUl; + } else if(mf_classic_check_card_type( + dev->dev.nfca.sensRes.anticollisionInfo, + dev->dev.nfca.sensRes.platformInfo, + dev->dev.nfca.selRes.sak)) { + result->protocol = NfcDeviceProtocolMifareClassic; } else if(mf_df_check_card_type( dev->dev.nfca.sensRes.anticollisionInfo, dev->dev.nfca.sensRes.platformInfo, @@ -149,7 +163,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { } // Notify caller and exit if(nfc_worker->callback) { - nfc_worker->callback(nfc_worker->context); + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } break; } @@ -171,7 +185,7 @@ bool nfc_worker_emulate_uid_callback( if(reader_data->size > 0) { memcpy(reader_data->data, buff_rx, reader_data->size); if(nfc_worker->callback) { - nfc_worker->callback(nfc_worker->context); + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } } return true; @@ -231,7 +245,7 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { result->emv_data.aid_len = emv_app.aid_len; memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); if(nfc_worker->callback) { - nfc_worker->callback(nfc_worker->context); + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } break; } else { @@ -329,7 +343,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len); // Notify caller and exit if(nfc_worker->callback) { - nfc_worker->callback(nfc_worker->context); + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } break; } else { @@ -378,7 +392,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { } // Notify caller and exit if(nfc_worker->callback) { - nfc_worker->callback(nfc_worker->context); + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } break; } else { @@ -633,7 +647,7 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { // Notify caller and exit if(nfc_worker->callback) { - nfc_worker->callback(nfc_worker->context); + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } break; } else { @@ -663,13 +677,166 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { if(mf_ul_emulate.data_changed) { nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data; if(nfc_worker->callback) { - nfc_worker->callback(nfc_worker->context); + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } mf_ul_emulate.data_changed = false; } } } +void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { + furi_assert(nfc_worker->callback); + rfalNfcDevice* dev_list; + rfalNfcDevice* dev; + NfcDeviceCommonData* nfc_common; + uint8_t dev_cnt = 0; + FuriHalNfcTxRxContext tx_rx_ctx = {}; + MfClassicAuthContext auth_ctx = {}; + MfClassicReader reader = {}; + uint64_t curr_key = 0; + uint16_t curr_sector = 0; + uint8_t total_sectors = 0; + NfcWorkerEvent event; + + // Open dictionary + nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage); + if(!nfc_mf_classic_dict_open_file(nfc_worker->dict_stream)) { + event = NfcWorkerEventNoDictFound; + nfc_worker->callback(event, nfc_worker->context); + nfc_mf_classic_dict_close_file(nfc_worker->dict_stream); + stream_free(nfc_worker->dict_stream); + return; + } + + // Detect Mifare Classic card + while(nfc_worker->state == NfcWorkerStateReadMifareClassic) { + if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { + dev = &dev_list[0]; + if(mf_classic_get_type( + dev->nfcid, + dev->nfcidLen, + dev->dev.nfca.sensRes.anticollisionInfo, + dev->dev.nfca.sensRes.platformInfo, + dev->dev.nfca.selRes.sak, + &reader)) { + total_sectors = mf_classic_get_total_sectors_num(&reader); + if(reader.type == MfClassicType1k) { + event = NfcWorkerEventDetectedClassic1k; + } else { + event = NfcWorkerEventDetectedClassic4k; + } + nfc_worker->callback(event, nfc_worker->context); + break; + } + } else { + event = NfcWorkerEventNoCardDetected; + nfc_worker->callback(event, nfc_worker->context); + } + } + + if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { + bool card_removed_notified = false; + bool card_found_notified = false; + // Seek for mifare classic keys + for(curr_sector = 0; curr_sector < total_sectors; curr_sector++) { + FURI_LOG_I(TAG, "Sector: %d ...", curr_sector); + event = NfcWorkerEventNewSector; + nfc_worker->callback(event, nfc_worker->context); + mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector); + bool sector_key_found = false; + while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) { + furi_hal_nfc_deactivate(); + if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) { + if(!card_found_notified) { + if(reader.type == MfClassicType1k) { + event = NfcWorkerEventDetectedClassic1k; + } else { + event = NfcWorkerEventDetectedClassic4k; + } + nfc_worker->callback(event, nfc_worker->context); + card_found_notified = true; + card_removed_notified = false; + } + FURI_LOG_D( + TAG, + "Try to auth to sector %d with key %04lx%08lx", + curr_sector, + (uint32_t)(curr_key >> 32), + (uint32_t)curr_key); + if(mf_classic_auth_attempt(&tx_rx_ctx, &auth_ctx, curr_key)) { + sector_key_found = true; + if((auth_ctx.key_a != MF_CLASSIC_NO_KEY) && + (auth_ctx.key_b != MF_CLASSIC_NO_KEY)) + break; + } + } else { + // Notify that no tag is availalble + FURI_LOG_D(TAG, "Can't find tags"); + if(!card_removed_notified) { + event = NfcWorkerEventNoCardDetected; + nfc_worker->callback(event, nfc_worker->context); + card_removed_notified = true; + card_found_notified = false; + } + } + if(nfc_worker->state != NfcWorkerStateReadMifareClassic) break; + } + if(nfc_worker->state != NfcWorkerStateReadMifareClassic) break; + if(sector_key_found) { + // Notify that keys were found + if(auth_ctx.key_a != MF_CLASSIC_NO_KEY) { + FURI_LOG_I( + TAG, + "Sector %d key A: %04lx%08lx", + curr_sector, + (uint32_t)(auth_ctx.key_a >> 32), + (uint32_t)auth_ctx.key_a); + event = NfcWorkerEventFoundKeyA; + nfc_worker->callback(event, nfc_worker->context); + } + if(auth_ctx.key_b != MF_CLASSIC_NO_KEY) { + FURI_LOG_I( + TAG, + "Sector %d key B: %04lx%08lx", + curr_sector, + (uint32_t)(auth_ctx.key_b >> 32), + (uint32_t)auth_ctx.key_b); + event = NfcWorkerEventFoundKeyB; + nfc_worker->callback(event, nfc_worker->context); + } + // Add sectors to read sequence + mf_classic_reader_add_sector(&reader, curr_sector, auth_ctx.key_a, auth_ctx.key_b); + } + nfc_mf_classic_dict_reset(nfc_worker->dict_stream); + } + } + + if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { + FURI_LOG_I(TAG, "Found keys to %d sectors. Start reading sectors", reader.sectors_to_read); + uint8_t sectors_read = + mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data); + if(sectors_read) { + dev = &dev_list[0]; + nfc_common = &nfc_worker->dev_data->nfc_data; + nfc_common->uid_len = dev->dev.nfca.nfcId1Len; + nfc_common->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo; + nfc_common->atqa[1] = dev->dev.nfca.sensRes.platformInfo; + nfc_common->sak = dev->dev.nfca.selRes.sak; + nfc_common->protocol = NfcDeviceProtocolMifareClassic; + memcpy(nfc_common->uid, dev->dev.nfca.nfcId1, nfc_common->uid_len); + event = NfcWorkerEventSuccess; + FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read); + } else { + event = NfcWorkerEventFail; + FURI_LOG_W(TAG, "Failed to read any sector"); + } + nfc_worker->callback(event, nfc_worker->context); + } + + nfc_mf_classic_dict_close_file(nfc_worker->dict_stream); + stream_free(nfc_worker->dict_stream); +} + ReturnCode nfc_exchange_full( uint8_t* tx_buff, uint16_t tx_len, @@ -900,7 +1067,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { // Notify caller and exit if(nfc_worker->callback) { - nfc_worker->callback(nfc_worker->context); + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } break; } |