From 9c59bcd7763cbe9b0132b0f2698543e2dfb11623 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 26 Jul 2022 18:30:49 +0300 Subject: [PATCH] [FL-2605] NFC new design (#1364) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: add new read scene * lib: refactore nfc library * mifare desfire: add read card fuction * lib nfc: add auto read worker * nfc: add supported cards * nfc: add mifare classic read success scene * nfc: add troyka support * submodule: update protobuf * nfc: mifare classic keys cache * nfc: rework mifare classic key cache * Correct spelling * nfc: add user dictionary * nfc: introduce block read map in fff * nfc: rework dict attack * nfc: improve dict attack * nfc: rework mifare classic format * nfc: rework MFC read with Reader * nfc: add gui for MFC read success scene * nfc: fix dict attack view gui * nfc: add retry and exit confirm scenes * nfc: add retry and exit scenes navigation * nfc: check user dictionary * nfc: remove unused scenes * nfc: rename functions in nfc worker * nfc: rename mf_classic_dict_attack -> dict_attack * nfc: change scenes names * nfc: remove scene tick events * nfc: rework dict calls with buffer streams * nfc: fix notifications * nfc: fix mf desfire navigation * nfc: remove notification from mf classic read success * nfc: fix read sectors calculation * nfc: add fallback for unknown card * nfc: show file name while emulating * nfc: fix build * nfc: fix memory leak * nfc: fix desfire read * nfc: add no dict found navigation * nfc: add read views * nfc: update card fix * nfc: fix access bytes save * nfc: add exit and retry confirm to mf ultralight read success * nfc: introduce detect reader * nfc: change record open arg to macros * nfc: fix start from archive Co-authored-by: Astra Co-authored-by: あく --- .github/CODEOWNERS | 2 +- applications/nfc/helpers/nfc_custom_event.h | 1 + applications/nfc/helpers/nfc_generators.c | 26 +- .../nfc/helpers/nfc_mf_classic_dict.c | 53 -- .../nfc/helpers/nfc_mf_classic_dict.h | 15 - applications/nfc/nfc.c | 24 +- applications/nfc/nfc_cli.c | 5 +- applications/nfc/nfc_i.h | 11 +- applications/nfc/nfc_worker.c | 708 ------------------ applications/nfc/nfc_worker_i.h | 57 -- applications/nfc/scenes/nfc_scene_card_menu.c | 90 --- applications/nfc/scenes/nfc_scene_config.h | 53 +- .../nfc/scenes/nfc_scene_detect_reader.c | 143 ++++ .../nfc/scenes/nfc_scene_device_info.c | 2 +- .../nfc/scenes/nfc_scene_dict_not_found.c | 7 +- .../nfc/scenes/nfc_scene_emulate_uid.c | 9 +- ...success.c => nfc_scene_emv_read_success.c} | 36 +- .../nfc/scenes/nfc_scene_exit_confirm.c | 47 ++ .../nfc/scenes/nfc_scene_extra_actions.c | 48 ++ .../scenes/nfc_scene_mf_classic_dict_attack.c | 137 ++++ ...assic.c => nfc_scene_mf_classic_emulate.c} | 29 +- .../nfc/scenes/nfc_scene_mf_classic_keys.c | 59 ++ .../scenes/nfc_scene_mf_classic_keys_add.c | 57 ++ ..._ul_menu.c => nfc_scene_mf_classic_menu.c} | 22 +- .../nfc_scene_mf_classic_read_success.c | 104 +++ ...sfire_app.c => nfc_scene_mf_desfire_app.c} | 36 +- ...ire_data.c => nfc_scene_mf_desfire_data.c} | 32 +- ...ire_menu.c => nfc_scene_mf_desfire_menu.c} | 15 +- ....c => nfc_scene_mf_desfire_read_success.c} | 45 +- ...ul.c => nfc_scene_mf_ultralight_emulate.c} | 29 +- ..._menu.c => nfc_scene_mf_ultralight_menu.c} | 22 +- ...=> nfc_scene_mf_ultralight_read_success.c} | 28 +- applications/nfc/scenes/nfc_scene_read.c | 108 +++ applications/nfc/scenes/nfc_scene_read_card.c | 51 -- .../nfc/scenes/nfc_scene_read_card_success.c | 20 +- .../nfc/scenes/nfc_scene_read_emv_app.c | 58 -- .../scenes/nfc_scene_read_emv_app_success.c | 83 -- .../nfc/scenes/nfc_scene_read_emv_data.c | 59 -- .../scenes/nfc_scene_read_mifare_classic.c | 96 --- .../scenes/nfc_scene_read_mifare_desfire.c | 56 -- .../nfc/scenes/nfc_scene_read_mifare_ul.c | 54 -- .../nfc/scenes/nfc_scene_retry_confirm.c | 47 ++ .../scenes/nfc_scene_run_emv_app_confirm.c | 49 -- .../nfc/scenes/nfc_scene_save_success.c | 8 +- .../nfc/scenes/nfc_scene_saved_menu.c | 4 +- .../nfc/scenes/nfc_scene_scripts_menu.c | 82 -- applications/nfc/scenes/nfc_scene_start.c | 23 +- applications/nfc/views/dict_attack.c | 220 +++--- applications/nfc/views/dict_attack.h | 25 +- applications/unit_tests/nfc/nfc_test.c | 2 +- assets/icons/NFC/NFC_manual.png | Bin 0 -> 3785 bytes assets/icons/NFC/Reader_detect.png | Bin 0 -> 3771 bytes firmware.scons | 1 + .../targets/furi_hal_include/furi_hal_nfc.h | 2 +- furi/core/common_defines.h | 4 + lib/SConscript | 1 + lib/misc.scons | 2 - lib/nfc/SConscript | 16 + lib/nfc/helpers/mf_classic_dict.c | 148 ++++ lib/nfc/helpers/mf_classic_dict.h | 28 + .../nfc/helpers/nfc_debug_pcap.c | 0 .../nfc/helpers/nfc_debug_pcap.h | 0 {applications => lib}/nfc/nfc_device.c | 273 ++++++- {applications => lib}/nfc/nfc_device.h | 11 +- {applications => lib}/nfc/nfc_types.c | 0 {applications => lib}/nfc/nfc_types.h | 0 lib/nfc/nfc_worker.c | 510 +++++++++++++ {applications => lib}/nfc/nfc_worker.h | 36 +- lib/nfc/nfc_worker_i.h | 48 ++ lib/nfc/parsers/nfc_supported_card.c | 12 + lib/nfc/parsers/nfc_supported_card.h | 27 + lib/nfc/parsers/troyka_parser.c | 70 ++ lib/nfc/parsers/troyka_parser.h | 9 + .../protocols}/crypto1.c | 0 .../protocols}/crypto1.h | 0 lib/{nfc_protocols => nfc/protocols}/emv.c | 0 lib/{nfc_protocols => nfc/protocols}/emv.h | 0 .../protocols}/mifare_classic.c | 325 ++++++-- .../protocols}/mifare_classic.h | 71 +- .../protocols}/mifare_common.c | 0 .../protocols}/mifare_common.h | 0 .../protocols}/mifare_desfire.c | 172 +++++ .../protocols}/mifare_desfire.h | 4 + .../protocols}/mifare_ultralight.c | 0 .../protocols}/mifare_ultralight.h | 0 .../protocols}/nfc_util.c | 0 .../protocols}/nfc_util.h | 0 lib/{nfc_protocols => nfc/protocols}/nfca.c | 0 lib/{nfc_protocols => nfc/protocols}/nfca.h | 0 89 files changed, 2755 insertions(+), 2012 deletions(-) delete mode 100644 applications/nfc/helpers/nfc_mf_classic_dict.c delete mode 100644 applications/nfc/helpers/nfc_mf_classic_dict.h delete mode 100644 applications/nfc/nfc_worker.c delete mode 100644 applications/nfc/nfc_worker_i.h delete mode 100755 applications/nfc/scenes/nfc_scene_card_menu.c create mode 100644 applications/nfc/scenes/nfc_scene_detect_reader.c rename applications/nfc/scenes/{nfc_scene_read_emv_data_success.c => nfc_scene_emv_read_success.c} (78%) mode change 100755 => 100644 create mode 100644 applications/nfc/scenes/nfc_scene_exit_confirm.c create mode 100644 applications/nfc/scenes/nfc_scene_extra_actions.c create mode 100644 applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c rename applications/nfc/scenes/{nfc_scene_emulate_mifare_classic.c => nfc_scene_mf_classic_emulate.c} (57%) create mode 100644 applications/nfc/scenes/nfc_scene_mf_classic_keys.c create mode 100644 applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c rename applications/nfc/scenes/{nfc_scene_mifare_ul_menu.c => nfc_scene_mf_classic_menu.c} (64%) mode change 100755 => 100644 create mode 100644 applications/nfc/scenes/nfc_scene_mf_classic_read_success.c rename applications/nfc/scenes/{nfc_scene_mifare_desfire_app.c => nfc_scene_mf_desfire_app.c} (73%) rename applications/nfc/scenes/{nfc_scene_mifare_desfire_data.c => nfc_scene_mf_desfire_data.c} (74%) rename applications/nfc/scenes/{nfc_scene_mifare_desfire_menu.c => nfc_scene_mf_desfire_menu.c} (61%) rename applications/nfc/scenes/{nfc_scene_read_mifare_desfire_success.c => nfc_scene_mf_desfire_read_success.c} (64%) rename applications/nfc/scenes/{nfc_scene_emulate_mifare_ul.c => nfc_scene_mf_ultralight_emulate.c} (56%) rename applications/nfc/scenes/{nfc_scene_mifare_classic_menu.c => nfc_scene_mf_ultralight_menu.c} (66%) rename applications/nfc/scenes/{nfc_scene_read_mifare_ul_success.c => nfc_scene_mf_ultralight_read_success.c} (77%) create mode 100644 applications/nfc/scenes/nfc_scene_read.c delete mode 100755 applications/nfc/scenes/nfc_scene_read_card.c delete mode 100755 applications/nfc/scenes/nfc_scene_read_emv_app.c delete mode 100755 applications/nfc/scenes/nfc_scene_read_emv_app_success.c delete mode 100755 applications/nfc/scenes/nfc_scene_read_emv_data.c delete mode 100644 applications/nfc/scenes/nfc_scene_read_mifare_classic.c delete mode 100644 applications/nfc/scenes/nfc_scene_read_mifare_desfire.c delete mode 100755 applications/nfc/scenes/nfc_scene_read_mifare_ul.c create mode 100644 applications/nfc/scenes/nfc_scene_retry_confirm.c delete mode 100755 applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c delete mode 100755 applications/nfc/scenes/nfc_scene_scripts_menu.c create mode 100644 assets/icons/NFC/NFC_manual.png create mode 100644 assets/icons/NFC/Reader_detect.png create mode 100644 lib/nfc/SConscript create mode 100644 lib/nfc/helpers/mf_classic_dict.c create mode 100644 lib/nfc/helpers/mf_classic_dict.h rename {applications => lib}/nfc/helpers/nfc_debug_pcap.c (100%) rename {applications => lib}/nfc/helpers/nfc_debug_pcap.h (100%) rename {applications => lib}/nfc/nfc_device.c (79%) rename {applications => lib}/nfc/nfc_device.h (89%) rename {applications => lib}/nfc/nfc_types.c (100%) rename {applications => lib}/nfc/nfc_types.h (100%) create mode 100644 lib/nfc/nfc_worker.c rename {applications => lib}/nfc/nfc_worker.h (59%) create mode 100644 lib/nfc/nfc_worker_i.h create mode 100644 lib/nfc/parsers/nfc_supported_card.c create mode 100644 lib/nfc/parsers/nfc_supported_card.h create mode 100644 lib/nfc/parsers/troyka_parser.c create mode 100644 lib/nfc/parsers/troyka_parser.h rename lib/{nfc_protocols => nfc/protocols}/crypto1.c (100%) rename lib/{nfc_protocols => nfc/protocols}/crypto1.h (100%) rename lib/{nfc_protocols => nfc/protocols}/emv.c (100%) rename lib/{nfc_protocols => nfc/protocols}/emv.h (100%) rename lib/{nfc_protocols => nfc/protocols}/mifare_classic.c (71%) rename lib/{nfc_protocols => nfc/protocols}/mifare_classic.h (54%) rename lib/{nfc_protocols => nfc/protocols}/mifare_common.c (100%) rename lib/{nfc_protocols => nfc/protocols}/mifare_common.h (100%) rename lib/{nfc_protocols => nfc/protocols}/mifare_desfire.c (62%) rename lib/{nfc_protocols => nfc/protocols}/mifare_desfire.h (98%) rename lib/{nfc_protocols => nfc/protocols}/mifare_ultralight.c (100%) rename lib/{nfc_protocols => nfc/protocols}/mifare_ultralight.h (100%) rename lib/{nfc_protocols => nfc/protocols}/nfc_util.c (100%) rename lib/{nfc_protocols => nfc/protocols}/nfc_util.h (100%) rename lib/{nfc_protocols => nfc/protocols}/nfca.c (100%) rename lib/{nfc_protocols => nfc/protocols}/nfca.h (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index da0cfd2c..71acb5f1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -76,7 +76,7 @@ /lib/microtar/ @skotopes @DrZlo13 @hedger /lib/mlib/ @skotopes @DrZlo13 @hedger /lib/nanopb/ @skotopes @DrZlo13 @hedger -/lib/nfc_protocols/ @skotopes @DrZlo13 @hedger @gornekich +/lib/nfc/ @skotopes @DrZlo13 @hedger @gornekich /lib/one_wire/ @skotopes @DrZlo13 @hedger /lib/qrcode/ @skotopes @DrZlo13 @hedger /lib/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm diff --git a/applications/nfc/helpers/nfc_custom_event.h b/applications/nfc/helpers/nfc_custom_event.h index b877732a..fbd54b27 100644 --- a/applications/nfc/helpers/nfc_custom_event.h +++ b/applications/nfc/helpers/nfc_custom_event.h @@ -9,5 +9,6 @@ enum NfcCustomEvent { NfcCustomEventByteInputDone, NfcCustomEventTextInputDone, NfcCustomEventDictAttackDone, + NfcCustomEventDictAttackSkip, NfcCustomEventRpcLoad, }; diff --git a/applications/nfc/helpers/nfc_generators.c b/applications/nfc/helpers/nfc_generators.c index 4121daf4..066ac9d1 100644 --- a/applications/nfc/helpers/nfc_generators.c +++ b/applications/nfc/helpers/nfc_generators.c @@ -267,67 +267,67 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) { static const NfcGenerator mf_ul_generator = { .name = "Mifare Ultralight", .generator_func = nfc_generate_mf_ul_orig, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator mf_ul_11_generator = { .name = "Mifare Ultralight EV1 11", .generator_func = nfc_generate_mf_ul_11, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator mf_ul_h11_generator = { .name = "Mifare Ultralight EV1 H11", .generator_func = nfc_generate_mf_ul_h11, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator mf_ul_21_generator = { .name = "Mifare Ultralight EV1 21", .generator_func = nfc_generate_mf_ul_21, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator mf_ul_h21_generator = { .name = "Mifare Ultralight EV1 H21", .generator_func = nfc_generate_mf_ul_h21, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator ntag203_generator = { .name = "NTAG203", .generator_func = nfc_generate_mf_ul_ntag203, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator ntag213_generator = { .name = "NTAG213", .generator_func = nfc_generate_ntag213, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator ntag215_generator = { .name = "NTAG215", .generator_func = nfc_generate_ntag215, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator ntag216_generator = { .name = "NTAG216", .generator_func = nfc_generate_ntag216, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator ntag_i2c_1k_generator = { .name = "NTAG I2C 1k", .generator_func = nfc_generate_ntag_i2c_1k, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator ntag_i2c_2k_generator = { .name = "NTAG I2C 2k", .generator_func = nfc_generate_ntag_i2c_2k, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator ntag_i2c_plus_1k_generator = { .name = "NTAG I2C Plus 1k", .generator_func = nfc_generate_ntag_i2c_plus_1k, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; static const NfcGenerator ntag_i2c_plus_2k_generator = { .name = "NTAG I2C Plus 2k", .generator_func = nfc_generate_ntag_i2c_plus_2k, - .next_scene = NfcSceneMifareUlMenu}; + .next_scene = NfcSceneMfUltralightMenu}; const NfcGenerator* const nfc_generators[] = { &mf_ul_generator, diff --git a/applications/nfc/helpers/nfc_mf_classic_dict.c b/applications/nfc/helpers/nfc_mf_classic_dict.c deleted file mode 100644 index be77dede..00000000 --- a/applications/nfc/helpers/nfc_mf_classic_dict.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "nfc_mf_classic_dict.h" - -#include -#include - -#define NFC_MF_CLASSIC_DICT_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") - -#define NFC_MF_CLASSIC_KEY_LEN (13) - -bool nfc_mf_classic_dict_check_presence(Storage* storage) { - furi_assert(storage); - return storage_common_stat(storage, NFC_MF_CLASSIC_DICT_PATH, NULL) == FSE_OK; -} - -bool nfc_mf_classic_dict_open_file(Stream* stream) { - furi_assert(stream); - return file_stream_open(stream, NFC_MF_CLASSIC_DICT_PATH, FSAM_READ, FSOM_OPEN_EXISTING); -} - -void nfc_mf_classic_dict_close_file(Stream* stream) { - furi_assert(stream); - file_stream_close(stream); -} - -bool nfc_mf_classic_dict_get_next_key(Stream* stream, uint64_t* key) { - furi_assert(stream); - furi_assert(key); - uint8_t key_byte_tmp = 0; - string_t next_line; - string_init(next_line); - *key = 0; - - bool next_key_read = false; - while(!next_key_read) { - if(!stream_read_line(stream, next_line)) break; - if(string_get_char(next_line, 0) == '#') continue; - if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; - for(uint8_t i = 0; i < 12; i += 2) { - args_char_to_hex( - string_get_char(next_line, i), string_get_char(next_line, i + 1), &key_byte_tmp); - *key |= (uint64_t)key_byte_tmp << 8 * (5 - i / 2); - } - next_key_read = true; - } - - string_clear(next_line); - return next_key_read; -} - -void nfc_mf_classic_dict_reset(Stream* stream) { - furi_assert(stream); - stream_rewind(stream); -} diff --git a/applications/nfc/helpers/nfc_mf_classic_dict.h b/applications/nfc/helpers/nfc_mf_classic_dict.h deleted file mode 100644 index 8d3a7372..00000000 --- a/applications/nfc/helpers/nfc_mf_classic_dict.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include -#include -#include - -bool nfc_mf_classic_dict_check_presence(Storage* storage); - -bool nfc_mf_classic_dict_open_file(Stream* stream); - -void nfc_mf_classic_dict_close_file(Stream* stream); - -bool nfc_mf_classic_dict_get_next_key(Stream* stream, uint64_t* key); - -void nfc_mf_classic_dict_reset(Stream* stream); diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index f6af3573..b19f92f2 100644 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -13,12 +13,6 @@ bool nfc_back_event_callback(void* context) { return scene_manager_handle_back_event(nfc->scene_manager); } -void nfc_tick_event_callback(void* context) { - furi_assert(context); - Nfc* nfc = context; - scene_manager_handle_tick_event(nfc->scene_manager); -} - void nfc_rpc_exit_callback(Nfc* nfc) { if(nfc->rpc_state == NfcRpcStateEmulating) { // Stop worker @@ -36,11 +30,12 @@ void nfc_rpc_exit_callback(Nfc* nfc) { } } -static void nfc_rpc_emulate_callback(NfcWorkerEvent event, void* context) { +static bool nfc_rpc_emulate_callback(NfcWorkerEvent event, void* context) { UNUSED(event); Nfc* nfc = context; nfc->rpc_state = NfcRpcStateEmulated; + return true; } static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) { @@ -67,20 +62,20 @@ static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, v if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { nfc_worker_start( nfc->worker, - NfcWorkerStateEmulateMifareUltralight, + NfcWorkerStateMfUltralightEmulate, &nfc->dev->dev_data, nfc_rpc_emulate_callback, nfc); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { nfc_worker_start( nfc->worker, - NfcWorkerStateEmulateMifareClassic, + NfcWorkerStateMfClassicEmulate, &nfc->dev->dev_data, nfc_rpc_emulate_callback, nfc); } else { nfc_worker_start( - nfc->worker, NfcWorkerStateEmulate, &nfc->dev->dev_data, NULL, nfc); + nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc); } nfc->rpc_state = NfcRpcStateEmulating; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad); @@ -102,7 +97,6 @@ Nfc* nfc_alloc() { view_dispatcher_set_event_callback_context(nfc->view_dispatcher, nfc); view_dispatcher_set_custom_event_callback(nfc->view_dispatcher, nfc_custom_event_callback); view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback); - view_dispatcher_set_tick_event_callback(nfc->view_dispatcher, nfc_tick_event_callback, 100); // Nfc device nfc->dev = nfc_device_alloc(); @@ -155,7 +149,7 @@ Nfc* nfc_alloc() { view_dispatcher_add_view( nfc->view_dispatcher, NfcViewBankCard, bank_card_get_view(nfc->bank_card)); - // Dict Attack + // Mifare Classic Dict Attack nfc->dict_attack = dict_attack_alloc(); view_dispatcher_add_view( nfc->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(nfc->dict_attack)); @@ -209,7 +203,7 @@ void nfc_free(Nfc* nfc) { view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard); bank_card_free(nfc->bank_card); - // Dict Attack + // Mifare Classic Dict Attack view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); dict_attack_free(nfc->dict_attack); @@ -301,9 +295,9 @@ int32_t nfc_app(void* p) { nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); if(nfc_device_load(nfc->dev, p, true)) { if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } diff --git a/applications/nfc/nfc_cli.c b/applications/nfc/nfc_cli.c index 133bd558..4ac95f04 100755 --- a/applications/nfc/nfc_cli.c +++ b/applications/nfc/nfc_cli.c @@ -1,9 +1,10 @@ #include #include #include -#include +#include -#include "nfc_types.h" +#include +#include static void nfc_cli_print_usage() { printf("Usage:\r\n"); diff --git a/applications/nfc/nfc_i.h b/applications/nfc/nfc_i.h index 4b806d40..84c0e7f0 100755 --- a/applications/nfc/nfc_i.h +++ b/applications/nfc/nfc_i.h @@ -1,9 +1,6 @@ #pragma once #include "nfc.h" -#include "nfc_types.h" -#include "nfc_worker.h" -#include "nfc_device.h" #include #include @@ -24,6 +21,11 @@ #include #include +#include +#include +#include +#include + #include "views/bank_card.h" #include "views/dict_attack.h" @@ -32,8 +34,6 @@ #include "rpc/rpc_app.h" -#define NFC_SEND_NOTIFICATION_FALSE (0UL) -#define NFC_SEND_NOTIFICATION_TRUE (1UL) #define NFC_TEXT_STORE_SIZE 128 typedef enum { @@ -56,6 +56,7 @@ struct Nfc { char text_store[NFC_TEXT_STORE_SIZE + 1]; string_t text_box_store; + uint8_t byte_input_store[6]; void* rpc_ctx; NfcRpcState rpc_state; diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c deleted file mode 100644 index df1b5faf..00000000 --- a/applications/nfc/nfc_worker.c +++ /dev/null @@ -1,708 +0,0 @@ -#include "nfc_worker_i.h" -#include - -#include - -#define TAG "NfcWorker" - -/***************************** NFC Worker API *******************************/ - -NfcWorker* nfc_worker_alloc() { - NfcWorker* nfc_worker = malloc(sizeof(NfcWorker)); - - // Worker thread attributes - nfc_worker->thread = furi_thread_alloc(); - furi_thread_set_name(nfc_worker->thread, "NfcWorker"); - furi_thread_set_stack_size(nfc_worker->thread, 8192); - furi_thread_set_callback(nfc_worker->thread, nfc_worker_task); - furi_thread_set_context(nfc_worker->thread, nfc_worker); - - nfc_worker->callback = NULL; - nfc_worker->context = NULL; - nfc_worker->storage = furi_record_open(RECORD_STORAGE); - - // Initialize rfal - while(furi_hal_nfc_is_busy()) { - furi_delay_ms(10); - } - nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); - - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - nfc_worker->debug_pcap_worker = nfc_debug_pcap_alloc(nfc_worker->storage); - } - - return nfc_worker; -} - -void nfc_worker_free(NfcWorker* nfc_worker) { - furi_assert(nfc_worker); - - furi_thread_free(nfc_worker->thread); - - furi_record_close(RECORD_STORAGE); - - if(nfc_worker->debug_pcap_worker) nfc_debug_pcap_free(nfc_worker->debug_pcap_worker); - - free(nfc_worker); -} - -NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker) { - return nfc_worker->state; -} - -void nfc_worker_start( - NfcWorker* nfc_worker, - NfcWorkerState state, - NfcDeviceData* dev_data, - NfcWorkerCallback callback, - void* context) { - furi_assert(nfc_worker); - furi_assert(dev_data); - while(furi_hal_nfc_is_busy()) { - furi_delay_ms(10); - } - - nfc_worker->callback = callback; - nfc_worker->context = context; - nfc_worker->dev_data = dev_data; - nfc_worker_change_state(nfc_worker, state); - furi_thread_start(nfc_worker->thread); -} - -void nfc_worker_stop(NfcWorker* nfc_worker) { - furi_assert(nfc_worker); - if(nfc_worker->state == NfcWorkerStateBroken || nfc_worker->state == NfcWorkerStateReady) { - return; - } - furi_hal_nfc_stop(); - nfc_worker_change_state(nfc_worker, NfcWorkerStateStop); - furi_thread_join(nfc_worker->thread); -} - -void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state) { - nfc_worker->state = state; -} - -/***************************** NFC Worker Thread *******************************/ - -int32_t nfc_worker_task(void* context) { - NfcWorker* nfc_worker = context; - - furi_hal_nfc_exit_sleep(); - - if(nfc_worker->state == NfcWorkerStateDetect) { - nfc_worker_detect(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateEmulate) { - nfc_worker_emulate(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateReadEMVApp) { - nfc_worker_read_emv_app(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateReadEMVData) { - nfc_worker_read_emv(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateEmulateApdu) { - nfc_worker_emulate_apdu(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateReadMifareUltralight) { - nfc_worker_read_mifare_ultralight(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) { - 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 == NfcWorkerStateEmulateMifareClassic) { - nfc_worker_emulate_mifare_classic(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { - nfc_worker_read_mifare_desfire(nfc_worker); - } - furi_hal_nfc_sleep(); - nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); - - return 0; -} - -void nfc_worker_detect(NfcWorker* nfc_worker) { - nfc_device_data_clear(nfc_worker->dev_data); - NfcDeviceData* dev_data = nfc_worker->dev_data; - FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - - while(nfc_worker->state == NfcWorkerStateDetect) { - if(furi_hal_nfc_detect(nfc_data, 1000)) { - // Process first found device - if(nfc_data->type == FuriHalNfcTypeA) { - if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { - dev_data->protocol = NfcDeviceProtocolMifareUl; - } else if(mf_classic_check_card_type( - nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { - dev_data->protocol = NfcDeviceProtocolMifareClassic; - } else if(mf_df_check_card_type( - nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { - dev_data->protocol = NfcDeviceProtocolMifareDesfire; - } else if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) { - dev_data->protocol = NfcDeviceProtocolEMV; - } else { - dev_data->protocol = NfcDeviceProtocolUnknown; - } - } - - // Notify caller and exit - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - break; - } - furi_hal_nfc_sleep(); - furi_delay_ms(100); - } -} - -void nfc_worker_emulate(NfcWorker* nfc_worker) { - FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); - FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data; - NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data; - - while(nfc_worker->state == NfcWorkerStateEmulate) { - if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, true, 100)) { - if(furi_hal_nfc_tx_rx(&tx_rx, 100)) { - reader_data->size = tx_rx.rx_bits / 8; - if(reader_data->size > 0) { - memcpy(reader_data->data, tx_rx.rx_data, reader_data->size); - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - } - } else { - FURI_LOG_E(TAG, "Failed to get reader commands"); - } - } - } -} - -void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { - FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false); - EmvApplication emv_app = {}; - NfcDeviceData* result = nfc_worker->dev_data; - FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - nfc_device_data_clear(result); - - while(nfc_worker->state == NfcWorkerStateReadEMVApp) { - if(furi_hal_nfc_detect(nfc_data, 1000)) { - // Card was found. Check that it supports EMV - if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) { - result->protocol = NfcDeviceProtocolEMV; - if(emv_search_application(&tx_rx, &emv_app)) { - // Notify caller and exit - 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(NfcWorkerEventSuccess, nfc_worker->context); - } - } - } else { - FURI_LOG_W(TAG, "Card doesn't support EMV"); - } - } else { - FURI_LOG_D(TAG, "Can't find any cards"); - } - furi_hal_nfc_sleep(); - furi_delay_ms(20); - } -} - -void nfc_worker_read_emv(NfcWorker* nfc_worker) { - FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false); - EmvApplication emv_app = {}; - NfcDeviceData* result = nfc_worker->dev_data; - FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - nfc_device_data_clear(result); - - while(nfc_worker->state == NfcWorkerStateReadEMVData) { - if(furi_hal_nfc_detect(nfc_data, 1000)) { - // Card was found. Check that it supports EMV - if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) { - result->protocol = NfcDeviceProtocolEMV; - if(emv_read_bank_card(&tx_rx, &emv_app)) { - result->emv_data.number_len = emv_app.card_number_len; - memcpy( - result->emv_data.number, emv_app.card_number, result->emv_data.number_len); - result->emv_data.aid_len = emv_app.aid_len; - memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); - if(emv_app.name_found) { - memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name)); - } - if(emv_app.exp_month) { - result->emv_data.exp_mon = emv_app.exp_month; - result->emv_data.exp_year = emv_app.exp_year; - } - if(emv_app.country_code) { - result->emv_data.country_code = emv_app.country_code; - } - if(emv_app.currency_code) { - result->emv_data.currency_code = emv_app.currency_code; - } - // Notify caller and exit - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - break; - } - } else { - FURI_LOG_W(TAG, "Card doesn't support EMV"); - } - } else { - FURI_LOG_D(TAG, "Can't find any cards"); - } - furi_hal_nfc_sleep(); - furi_delay_ms(20); - } -} - -void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { - FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); - FuriHalNfcDevData params = { - .uid = {0xCF, 0x72, 0xd4, 0x40}, - .uid_len = 4, - .atqa = {0x00, 0x04}, - .sak = 0x20, - .type = FuriHalNfcTypeA, - }; - - while(nfc_worker->state == NfcWorkerStateEmulateApdu) { - if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { - FURI_LOG_D(TAG, "POS terminal detected"); - if(emv_card_emulation(&tx_rx)) { - FURI_LOG_D(TAG, "EMV card emulated"); - } - } else { - FURI_LOG_D(TAG, "Can't find reader"); - } - furi_hal_nfc_sleep(); - furi_delay_ms(20); - } -} - -void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) { - FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false); - MfUltralightReader reader = {}; - MfUltralightData data = {}; - NfcDeviceData* result = nfc_worker->dev_data; - FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - - while(nfc_worker->state == NfcWorkerStateReadMifareUltralight) { - if(furi_hal_nfc_detect(nfc_data, 300)) { - if(nfc_data->type == FuriHalNfcTypeA && - mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { - FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Start reading"); - if(mf_ul_read_card(&tx_rx, &reader, &data)) { - result->protocol = NfcDeviceProtocolMifareUl; - result->mf_ul_data = data; - // Notify caller and exit - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - break; - } else { - FURI_LOG_D(TAG, "Failed reading Mifare Ultralight"); - } - } else { - FURI_LOG_W(TAG, "Tag is not Mifare Ultralight"); - } - } else { - FURI_LOG_D(TAG, "Can't find any tags"); - } - furi_hal_nfc_sleep(); - furi_delay_ms(100); - } -} - -void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { - FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - MfUltralightEmulator emulator = {}; - mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data); - while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) { - mf_ul_reset_emulation(&emulator, true); - furi_hal_nfc_emulate_nfca( - nfc_data->uid, - nfc_data->uid_len, - nfc_data->atqa, - nfc_data->sak, - mf_ul_prepare_emulation_response, - &emulator, - 5000); - // Check if data was modified - if(emulator.data_changed) { - nfc_worker->dev_data->mf_ul_data = emulator.data; - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - emulator.data_changed = false; - } - } -} - -void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { - furi_assert(nfc_worker->callback); - FuriHalNfcTxRxContext tx_rx_ctx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx_ctx, false); - MfClassicAuthContext auth_ctx = {}; - MfClassicReader reader = {}; - uint64_t curr_key = 0; - uint16_t curr_sector = 0; - uint8_t total_sectors = 0; - NfcWorkerEvent event; - FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - - // 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(nfc_data, 300)) { - if(mf_classic_get_type( - nfc_data->uid, - nfc_data->uid_len, - nfc_data->atqa[0], - nfc_data->atqa[1], - nfc_data->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_sleep(); - 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; - furi_delay_tick(1); - } - 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) { - event = NfcWorkerEventSuccess; - nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic; - 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); -} - -void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) { - FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); - FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - MfClassicEmulator emulator = { - .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), - .data = nfc_worker->dev_data->mf_classic_data, - .data_changed = false, - }; - NfcaSignal* nfca_signal = nfca_signal_alloc(); - tx_rx.nfca_signal = nfca_signal; - - rfal_platform_spi_acquire(); - - furi_hal_nfc_listen_start(nfc_data); - while(nfc_worker->state == NfcWorkerStateEmulateMifareClassic) { - if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { - mf_classic_emulator(&emulator, &tx_rx); - } - } - if(emulator.data_changed) { - nfc_worker->dev_data->mf_classic_data = emulator.data; - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - emulator.data_changed = false; - } - - nfca_signal_free(nfca_signal); - - rfal_platform_spi_release(); -} - -void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { - FuriHalNfcTxRxContext tx_rx = {}; - nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false); - NfcDeviceData* result = nfc_worker->dev_data; - nfc_device_data_clear(result); - MifareDesfireData* data = &result->mf_df_data; - FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - - while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { - furi_hal_nfc_sleep(); - if(!furi_hal_nfc_detect(nfc_data, 300)) { - furi_delay_ms(100); - continue; - } - memset(data, 0, sizeof(MifareDesfireData)); - if(nfc_data->type != FuriHalNfcTypeA || - !mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { - FURI_LOG_D(TAG, "Tag is not DESFire"); - furi_delay_ms(100); - continue; - } - - FURI_LOG_D(TAG, "Found DESFire tag"); - - result->protocol = NfcDeviceProtocolMifareDesfire; - - // Get DESFire version - tx_rx.tx_bits = 8 * mf_df_prepare_get_version(tx_rx.tx_data); - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_W(TAG, "Bad exchange getting version"); - continue; - } - if(!mf_df_parse_get_version_response(tx_rx.rx_data, tx_rx.rx_bits / 8, &data->version)) { - FURI_LOG_W(TAG, "Bad DESFire GET_VERSION response"); - continue; - } - - tx_rx.tx_bits = 8 * mf_df_prepare_get_free_memory(tx_rx.tx_data); - if(furi_hal_nfc_tx_rx_full(&tx_rx)) { - data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); - memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory)); - if(!mf_df_parse_get_free_memory_response( - tx_rx.rx_data, tx_rx.rx_bits / 8, data->free_memory)) { - FURI_LOG_D(TAG, "Bad DESFire GET_FREE_MEMORY response (normal for pre-EV1 cards)"); - free(data->free_memory); - data->free_memory = NULL; - } - } - - tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data); - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_D(TAG, "Bad exchange getting key settings"); - } else { - data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); - memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); - if(!mf_df_parse_get_key_settings_response( - tx_rx.rx_data, tx_rx.rx_bits / 8, data->master_key_settings)) { - FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); - free(data->master_key_settings); - data->master_key_settings = NULL; - } else { - MifareDesfireKeyVersion** key_version_head = - &data->master_key_settings->key_version_head; - for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { - tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_W(TAG, "Bad exchange getting key version"); - continue; - } - MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); - memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); - key_version->id = key_id; - if(!mf_df_parse_get_key_version_response( - tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) { - FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); - free(key_version); - continue; - } - *key_version_head = key_version; - key_version_head = &key_version->next; - } - } - } - - tx_rx.tx_bits = 8 * mf_df_prepare_get_application_ids(tx_rx.tx_data); - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_W(TAG, "Bad exchange getting application IDs"); - } else { - if(!mf_df_parse_get_application_ids_response( - tx_rx.rx_data, tx_rx.rx_bits / 8, &data->app_head)) { - FURI_LOG_W(TAG, "Bad DESFire GET_APPLICATION_IDS response"); - } - } - - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - tx_rx.tx_bits = 8 * mf_df_prepare_select_application(tx_rx.tx_data, app->id); - if(!furi_hal_nfc_tx_rx_full(&tx_rx) || - !mf_df_parse_select_application_response(tx_rx.rx_data, tx_rx.rx_bits / 8)) { - FURI_LOG_W(TAG, "Bad exchange selecting application"); - continue; - } - tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data); - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_W(TAG, "Bad exchange getting key settings"); - } else { - app->key_settings = malloc(sizeof(MifareDesfireKeySettings)); - memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings)); - if(!mf_df_parse_get_key_settings_response( - tx_rx.rx_data, tx_rx.rx_bits / 8, app->key_settings)) { - FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); - free(app->key_settings); - app->key_settings = NULL; - continue; - } - - MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head; - for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) { - tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_W(TAG, "Bad exchange getting key version"); - continue; - } - MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); - memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); - key_version->id = key_id; - if(!mf_df_parse_get_key_version_response( - tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) { - FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); - free(key_version); - continue; - } - *key_version_head = key_version; - key_version_head = &key_version->next; - } - } - - tx_rx.tx_bits = 8 * mf_df_prepare_get_file_ids(tx_rx.tx_data); - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_W(TAG, "Bad exchange getting file IDs"); - } else { - if(!mf_df_parse_get_file_ids_response( - tx_rx.rx_data, tx_rx.rx_bits / 8, &app->file_head)) { - FURI_LOG_W(TAG, "Bad DESFire GET_FILE_IDS response"); - } - } - - for(MifareDesfireFile* file = app->file_head; file; file = file->next) { - tx_rx.tx_bits = 8 * mf_df_prepare_get_file_settings(tx_rx.tx_data, file->id); - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_W(TAG, "Bad exchange getting file settings"); - continue; - } - if(!mf_df_parse_get_file_settings_response( - tx_rx.rx_data, tx_rx.rx_bits / 8, file)) { - FURI_LOG_W(TAG, "Bad DESFire GET_FILE_SETTINGS response"); - continue; - } - switch(file->type) { - case MifareDesfireFileTypeStandard: - case MifareDesfireFileTypeBackup: - tx_rx.tx_bits = 8 * mf_df_prepare_read_data(tx_rx.tx_data, file->id, 0, 0); - break; - case MifareDesfireFileTypeValue: - tx_rx.tx_bits = 8 * mf_df_prepare_get_value(tx_rx.tx_data, file->id); - break; - case MifareDesfireFileTypeLinearRecord: - case MifareDesfireFileTypeCyclicRecord: - tx_rx.tx_bits = 8 * mf_df_prepare_read_records(tx_rx.tx_data, file->id, 0, 0); - break; - } - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_W(TAG, "Bad exchange reading file %d", file->id); - continue; - } - if(!mf_df_parse_read_data_response(tx_rx.rx_data, tx_rx.rx_bits / 8, file)) { - FURI_LOG_W(TAG, "Bad response reading file %d", file->id); - continue; - } - } - } - - // Notify caller and exit - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - break; - } -} diff --git a/applications/nfc/nfc_worker_i.h b/applications/nfc/nfc_worker_i.h deleted file mode 100644 index 18c495a4..00000000 --- a/applications/nfc/nfc_worker_i.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "nfc_worker.h" -#include "nfc_i.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "helpers/nfc_mf_classic_dict.h" -#include "helpers/nfc_debug_pcap.h" - -struct NfcWorker { - FuriThread* thread; - Storage* storage; - Stream* dict_stream; - - NfcDeviceData* dev_data; - - NfcWorkerCallback callback; - void* context; - - NfcWorkerState state; - - NfcDebugPcapWorker* debug_pcap_worker; -}; - -void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state); - -int32_t nfc_worker_task(void* context); - -void nfc_worker_read_emv_app(NfcWorker* nfc_worker); - -void nfc_worker_read_emv(NfcWorker* nfc_worker); - -void nfc_worker_emulate_apdu(NfcWorker* nfc_worker); - -void nfc_worker_detect(NfcWorker* nfc_worker); - -void nfc_worker_emulate(NfcWorker* nfc_worker); - -void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker); - -void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker); - -void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker); - -void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker); - -void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker); diff --git a/applications/nfc/scenes/nfc_scene_card_menu.c b/applications/nfc/scenes/nfc_scene_card_menu.c deleted file mode 100755 index b7862409..00000000 --- a/applications/nfc/scenes/nfc_scene_card_menu.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "../nfc_i.h" - -enum SubmenuIndex { - SubmenuIndexRunApp, - SubmenuIndexChooseScript, - SubmenuIndexEmulate, - SubmenuIndexSave, -}; - -void nfc_scene_card_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_card_menu_on_enter(void* context) { - Nfc* nfc = context; - Submenu* submenu = nfc->submenu; - - if(nfc->dev->dev_data.protocol > NfcDeviceProtocolUnknown) { - submenu_add_item( - submenu, - "Run Compatible App", - SubmenuIndexRunApp, - nfc_scene_card_menu_submenu_callback, - nfc); - } - submenu_add_item( - submenu, - "Additional reading scripts", - SubmenuIndexChooseScript, - nfc_scene_card_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, "Emulate UID", SubmenuIndexEmulate, nfc_scene_card_menu_submenu_callback, nfc); - submenu_add_item( - submenu, "Save UID", SubmenuIndexSave, nfc_scene_card_menu_submenu_callback, nfc); - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneCardMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexRunApp) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp); - if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl); - } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareDesfire) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire); - } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolEMV) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp); - } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic); - } - consumed = true; - } else if(event.event == SubmenuIndexChooseScript) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexChooseScript); - scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu); - consumed = true; - } else if(event.event == SubmenuIndexEmulate) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexEmulate); - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - consumed = true; - } else if(event.event == SubmenuIndexSave) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexSave); - nfc->dev->format = NfcDeviceSaveFormatUid; - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - consumed = - scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); - } - - return consumed; -} - -void nfc_scene_card_menu_on_exit(void* context) { - Nfc* nfc = context; - - submenu_reset(nfc->submenu); -} diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index ffd757de..6e2369fd 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -1,41 +1,40 @@ ADD_SCENE(nfc, start, Start) -ADD_SCENE(nfc, read_card, ReadCard) -ADD_SCENE(nfc, read_card_success, ReadCardSuccess) -ADD_SCENE(nfc, card_menu, CardMenu) -ADD_SCENE(nfc, emulate_uid, EmulateUid) -ADD_SCENE(nfc, save_name, SaveName) -ADD_SCENE(nfc, save_success, SaveSuccess) -ADD_SCENE(nfc, file_select, FileSelect) +ADD_SCENE(nfc, read, Read) ADD_SCENE(nfc, saved_menu, SavedMenu) +ADD_SCENE(nfc, extra_actions, ExtraActions) ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) ADD_SCENE(nfc, set_atqa, SetAtqua) ADD_SCENE(nfc, set_uid, SetUid) -ADD_SCENE(nfc, scripts_menu, ScriptsMenu) -ADD_SCENE(nfc, read_mifare_ul, ReadMifareUl) -ADD_SCENE(nfc, read_mifare_ul_success, ReadMifareUlSuccess) -ADD_SCENE(nfc, mifare_ul_menu, MifareUlMenu) -ADD_SCENE(nfc, emulate_mifare_ul, EmulateMifareUl) -ADD_SCENE(nfc, read_emv_app, ReadEmvApp) -ADD_SCENE(nfc, read_emv_app_success, ReadEmvAppSuccess) -ADD_SCENE(nfc, read_mifare_desfire, ReadMifareDesfire) -ADD_SCENE(nfc, read_mifare_desfire_success, ReadMifareDesfireSuccess) -ADD_SCENE(nfc, mifare_desfire_menu, MifareDesfireMenu) -ADD_SCENE(nfc, mifare_desfire_data, MifareDesfireData) -ADD_SCENE(nfc, mifare_desfire_app, MifareDesfireApp) +ADD_SCENE(nfc, generate_info, GenerateInfo) +ADD_SCENE(nfc, read_card_success, ReadCardSuccess) +ADD_SCENE(nfc, save_name, SaveName) +ADD_SCENE(nfc, save_success, SaveSuccess) +ADD_SCENE(nfc, file_select, FileSelect) +ADD_SCENE(nfc, emulate_uid, EmulateUid) +ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) +ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) +ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) +ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess) +ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) +ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) +ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) +ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) +ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) +ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) +ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) +ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd) +ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) +ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) +ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) ADD_SCENE(nfc, device_info, DeviceInfo) ADD_SCENE(nfc, delete, Delete) ADD_SCENE(nfc, delete_success, DeleteSuccess) -ADD_SCENE(nfc, run_emv_app_confirm, RunEmvAppConfirm) -ADD_SCENE(nfc, read_emv_data, ReadEmvData) -ADD_SCENE(nfc, read_emv_data_success, ReadEmvDataSuccess) -ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) ADD_SCENE(nfc, restore_original, RestoreOriginal) ADD_SCENE(nfc, debug, Debug) ADD_SCENE(nfc, field, Field) -ADD_SCENE(nfc, read_mifare_classic, ReadMifareClassic) -ADD_SCENE(nfc, emulate_mifare_classic, EmulateMifareClassic) -ADD_SCENE(nfc, mifare_classic_menu, MifareClassicMenu) ADD_SCENE(nfc, dict_not_found, DictNotFound) ADD_SCENE(nfc, rpc, Rpc) -ADD_SCENE(nfc, generate_info, GenerateInfo) +ADD_SCENE(nfc, exit_confirm, ExitConfirm) +ADD_SCENE(nfc, retry_confirm, RetryConfirm) +ADD_SCENE(nfc, detect_reader, DetectReader) diff --git a/applications/nfc/scenes/nfc_scene_detect_reader.c b/applications/nfc/scenes/nfc_scene_detect_reader.c new file mode 100644 index 00000000..4639735d --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_detect_reader.c @@ -0,0 +1,143 @@ +#include "../nfc_i.h" +#include + +#define NFC_SCENE_DETECT_READER_LOG_SIZE_MAX (200) + +enum { + NfcSceneDetectReaderStateWidget, + NfcSceneDetectReaderStateTextBox, +}; + +bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); + return true; +} + +void nfc_scene_detect_reader_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_detect_reader_textbox_callback(void* context) { + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +// Add widget with device name or inform that data received +static void nfc_scene_detect_reader_widget_config(Nfc* nfc, bool data_received) { + Widget* widget = nfc->widget; + widget_reset(widget); + + widget_add_icon_element(widget, 0, 14, &I_Reader_detect); + widget_add_string_element( + widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold near reader"); + widget_add_string_element(widget, 55, 22, AlignLeft, AlignTop, FontPrimary, "Emulating..."); + + if(data_received) { + widget_add_button_element( + widget, GuiButtonTypeCenter, "Log", nfc_scene_detect_reader_widget_callback, nfc); + } +} + +void nfc_scene_detect_reader_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcEmulate); + FuriHalNfcDevData nfc_params = { + .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, + .uid_len = 7, + .atqa = {0x44, 0x00}, + .sak = 0x08, + .type = FuriHalNfcTypeA, + }; + nfc->dev->dev_data.nfc_data = nfc_params; + + // Setup Widget + nfc_scene_detect_reader_widget_config(nfc, false); + // Setup TextBox + TextBox* text_box = nfc->text_box; + text_box_set_font(text_box, TextBoxFontHex); + text_box_set_focus(text_box, TextBoxFocusEnd); + string_reset(nfc->text_box_store); + + // Set Widget state and view + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + // Start worker + memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); + nfc_worker_start( + nfc->worker, + NfcWorkerStateUidEmulate, + &nfc->dev->dev_data, + nfc_detect_reader_worker_callback, + nfc); + + nfc_blink_start(nfc); +} + +bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDetectReader); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventWorkerExit) { + // Add data button to widget if data is received for the first time + if(!string_size(nfc->text_box_store)) { + nfc_scene_detect_reader_widget_config(nfc, true); + } + // Update TextBox data + if(string_size(nfc->text_box_store) < NFC_SCENE_DETECT_READER_LOG_SIZE_MAX) { + string_cat_printf(nfc->text_box_store, "R:"); + for(uint16_t i = 0; i < reader_data->size; i++) { + string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]); + } + string_push_back(nfc->text_box_store, '\n'); + text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store)); + } + memset(reader_data, 0, sizeof(NfcReaderRequestData)); + consumed = true; + } else if(event.event == GuiButtonTypeCenter && state == NfcSceneDetectReaderStateWidget) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateTextBox); + consumed = true; + } else if(event.event == NfcCustomEventViewExit && state == NfcSceneDetectReaderStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state == NfcSceneDetectReaderStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_detect_reader_on_exit(void* context) { + Nfc* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + + // Clear view + widget_reset(nfc->widget); + text_box_reset(nfc->text_box); + string_reset(nfc->text_box_store); + + nfc_blink_stop(nfc); +} diff --git a/applications/nfc/scenes/nfc_scene_device_info.c b/applications/nfc/scenes/nfc_scene_device_info.c index 03464c66..b79c5104 100644 --- a/applications/nfc/scenes/nfc_scene_device_info.c +++ b/applications/nfc/scenes/nfc_scene_device_info.c @@ -190,7 +190,7 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard); consumed = true; } else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireData); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); consumed = true; } } else if(state == NfcSceneDeviceInfoData && event.event == NfcCustomEventViewExit) { diff --git a/applications/nfc/scenes/nfc_scene_dict_not_found.c b/applications/nfc/scenes/nfc_scene_dict_not_found.c index 19db68d8..dc21b08b 100644 --- a/applications/nfc/scenes/nfc_scene_dict_not_found.c +++ b/applications/nfc/scenes/nfc_scene_dict_not_found.c @@ -31,12 +31,9 @@ bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneScriptsMenu)) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) { consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneScriptsMenu); - } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneCardMenu)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneCardMenu); + nfc->scene_manager, NfcSceneExtraActions); } else { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneStart); diff --git a/applications/nfc/scenes/nfc_scene_emulate_uid.c b/applications/nfc/scenes/nfc_scene_emulate_uid.c index 3fabf495..0d92c9f0 100755 --- a/applications/nfc/scenes/nfc_scene_emulate_uid.c +++ b/applications/nfc/scenes/nfc_scene_emulate_uid.c @@ -8,11 +8,12 @@ enum { NfcSceneEmulateUidStateTextBox, }; -void nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) { +bool nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); furi_assert(context); Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); + return true; } void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) { @@ -76,7 +77,7 @@ void nfc_scene_emulate_uid_on_enter(void* context) { memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); nfc_worker_start( nfc->worker, - NfcWorkerStateEmulate, + NfcWorkerStateUidEmulate, &nfc->dev->dev_data, nfc_emulate_uid_worker_callback, nfc); @@ -90,9 +91,7 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateUid); bool consumed = false; - if(event.type == SceneManagerEventTypeTick) { - consumed = true; - } else if(event.type == SceneManagerEventTypeCustom) { + if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventWorkerExit) { // Add data button to widget if data is received for the first time if(!string_size(nfc->text_box_store)) { diff --git a/applications/nfc/scenes/nfc_scene_read_emv_data_success.c b/applications/nfc/scenes/nfc_scene_emv_read_success.c old mode 100755 new mode 100644 similarity index 78% rename from applications/nfc/scenes/nfc_scene_read_emv_data_success.c rename to applications/nfc/scenes/nfc_scene_emv_read_success.c index 4b3be9e1..eefe560e --- a/applications/nfc/scenes/nfc_scene_read_emv_data_success.c +++ b/applications/nfc/scenes/nfc_scene_emv_read_success.c @@ -2,7 +2,7 @@ #include "../helpers/nfc_emv_parser.h" #include -void nfc_scene_read_emv_data_success_widget_callback( +void nfc_scene_emv_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { @@ -12,7 +12,7 @@ void nfc_scene_read_emv_data_success_widget_callback( } } -void nfc_scene_read_emv_data_success_on_enter(void* context) { +void nfc_scene_emv_read_success_on_enter(void* context) { Nfc* nfc = context; EmvData* emv_data = &nfc->dev->dev_data.emv_data; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; @@ -23,17 +23,9 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { widget_add_frame_element(nfc->widget, 0, 0, 128, 64, 6); // Add buttons widget_add_button_element( - nfc->widget, - GuiButtonTypeLeft, - "Back", - nfc_scene_read_emv_data_success_widget_callback, - nfc); + nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc); widget_add_button_element( - nfc->widget, - GuiButtonTypeRight, - "Save", - nfc_scene_read_emv_data_success_widget_callback, - nfc); + nfc->widget, GuiButtonTypeRight, "Save", nfc_scene_emv_read_success_widget_callback, nfc); // Add card name widget_add_string_element( nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name); @@ -103,25 +95,17 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { widget_add_string_element(nfc->widget, 7, 32, AlignLeft, AlignTop, FontSecondary, exp_str); } - // Send notification - if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvDataSuccess) == - NFC_SEND_NOTIFICATION_TRUE) { - notification_message(nfc->notifications, &sequence_success); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_FALSE); - } - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } -bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeLeft) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneReadEmvAppSuccess); + scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); + consumed = true; } else if(event.event == GuiButtonTypeRight) { // Clear device name nfc_device_set_name(nfc->dev, ""); @@ -130,13 +114,13 @@ bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent e consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneReadEmvAppSuccess); + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; } return consumed; } -void nfc_scene_read_emv_data_success_on_exit(void* context) { +void nfc_scene_emv_read_success_on_exit(void* context) { Nfc* nfc = context; // Clear view diff --git a/applications/nfc/scenes/nfc_scene_exit_confirm.c b/applications/nfc/scenes/nfc_scene_exit_confirm.c new file mode 100644 index 00000000..24942bcd --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_exit_confirm.c @@ -0,0 +1,47 @@ +#include "../nfc_i.h" + +void nfc_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_exit_confirm_on_enter(void* context) { + Nfc* nfc = context; + DialogEx* dialog_ex = nfc->dialog_ex; + + dialog_ex_set_left_button_text(dialog_ex, "Exit"); + dialog_ex_set_right_button_text(dialog_ex, "Stay"); + dialog_ex_set_header(dialog_ex, "Exit to NFC menu?", 64, 11, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog_ex, "All unsaved data\nwill be lost.", 64, 25, AlignCenter, AlignTop); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_exit_confirm_dialog_callback); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else if(event.event == DialogExResultLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = true; + } + + return consumed; +} + +void nfc_scene_exit_confirm_on_exit(void* context) { + Nfc* nfc = context; + + // Clean view + dialog_ex_reset(nfc->dialog_ex); +} diff --git a/applications/nfc/scenes/nfc_scene_extra_actions.c b/applications/nfc/scenes/nfc_scene_extra_actions.c new file mode 100644 index 00000000..823a4ace --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_extra_actions.c @@ -0,0 +1,48 @@ +#include "../nfc_i.h" + +enum SubmenuIndex { + SubmenuIndexMfClassicKeys, +}; + +void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_extra_actions_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, + "Mf Classic Keys", + SubmenuIndexMfClassicKeys, + nfc_scene_extra_actions_submenu_callback, + nfc); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexMfClassicKeys) { + if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeys); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + } + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); + } + return consumed; +} + +void nfc_scene_extra_actions_on_exit(void* context) { + Nfc* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c new file mode 100644 index 00000000..0736f0f1 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -0,0 +1,137 @@ +#include "../nfc_i.h" + +typedef enum { + DictAttackStateIdle, + DictAttackStateUserDictInProgress, + DictAttackStateFlipperDictInProgress, +} DictAttackState; + +bool nfc_dict_attack_worker_callback(NfcWorkerEvent event, void* context) { + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + return true; +} + +void nfc_dict_attack_dict_attack_result_callback(void* context) { + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackSkip); +} + +static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) { + MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; + uint8_t sectors_read = 0; + uint8_t keys_found = 0; + + // Calculate found keys and read sectors + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + dict_attack_set_keys_found(nfc->dict_attack, keys_found); + dict_attack_set_sector_read(nfc->dict_attack, sectors_read); +} + +static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) { + MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; + NfcWorkerState worker_state = NfcWorkerStateReady; + + // Identify scene state + if(state == DictAttackStateIdle) { + if(mf_classic_dict_check_presence(MfClassicDictTypeUser)) { + state = DictAttackStateUserDictInProgress; + } else { + state = DictAttackStateFlipperDictInProgress; + } + } else if(state == DictAttackStateUserDictInProgress) { + state = DictAttackStateFlipperDictInProgress; + } + + // Setup view + if(state == DictAttackStateUserDictInProgress) { + worker_state = NfcWorkerStateMfClassicUserDictAttack; + dict_attack_set_header(nfc->dict_attack, "Mf Classic User Dict."); + } else if(state == DictAttackStateFlipperDictInProgress) { + worker_state = NfcWorkerStateMfClassicFlipperDictAttack; + dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict."); + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state); + dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc); + dict_attack_set_current_sector(nfc->dict_attack, 0); + dict_attack_set_card_detected(nfc->dict_attack, data->type); + nfc_scene_mf_classic_dict_attack_update_view(nfc); + nfc_worker_start( + nfc->worker, worker_state, &nfc->dev->dev_data, nfc_dict_attack_worker_callback, nfc); +} + +void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { + Nfc* nfc = context; + nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); + nfc_blink_start(nfc); +} + +bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; + bool consumed = false; + + uint32_t state = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack); + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventSuccess) { + if(state == DictAttackStateUserDictInProgress) { + nfc_worker_stop(nfc->worker); + nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); + consumed = true; + } else { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + consumed = true; + } + } else if(event.event == NfcWorkerEventAborted) { + if(state == DictAttackStateUserDictInProgress) { + nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); + consumed = true; + } else { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + consumed = true; + } + } else if(event.event == NfcWorkerEventCardDetected) { + dict_attack_set_card_detected(nfc->dict_attack, data->type); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + dict_attack_set_card_removed(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventFoundKeyA) { + dict_attack_inc_keys_found(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventFoundKeyB) { + dict_attack_inc_keys_found(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventNewSector) { + nfc_scene_mf_classic_dict_attack_update_view(nfc); + dict_attack_inc_current_sector(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcCustomEventDictAttackSkip) { + if(state == DictAttackStateUserDictInProgress) { + nfc_worker_stop(nfc->worker); + consumed = true; + } else if(state == DictAttackStateFlipperDictInProgress) { + nfc_worker_stop(nfc->worker); + consumed = true; + } + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + return consumed; +} + +void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { + Nfc* nfc = context; + // Stop worker + nfc_worker_stop(nfc->worker); + dict_attack_reset(nfc->dict_attack); + nfc_blink_stop(nfc); +} diff --git a/applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c b/applications/nfc/scenes/nfc_scene_mf_classic_emulate.c similarity index 57% rename from applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c rename to applications/nfc/scenes/nfc_scene_mf_classic_emulate.c index 97e86545..044388b8 100644 --- a/applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c +++ b/applications/nfc/scenes/nfc_scene_mf_classic_emulate.c @@ -4,51 +4,52 @@ #define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) #define NFC_MF_CLASSIC_DATA_CHANGED (1UL) -void nfc_emulate_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) { +bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); Nfc* nfc = context; scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateMifareClassic, NFC_MF_CLASSIC_DATA_CHANGED); + nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_CHANGED); + return true; } -void nfc_scene_emulate_mifare_classic_on_enter(void* context) { +void nfc_scene_mf_classic_emulate_on_enter(void* context) { Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcEmulate); // Setup view Popup* popup = nfc->popup; if(strcmp(nfc->dev->dev_name, "")) { - nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); + nfc_text_store_set(nfc, "Emulating\n%s", nfc->dev->dev_name); + } else { + nfc_text_store_set(nfc, "Emulating\nMf Classic", nfc->dev->dev_name); } popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); - popup_set_header(popup, "Emulating\nMf Classic", 56, 31, AlignLeft, AlignTop); + popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop); // Setup and start worker view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); nfc_worker_start( nfc->worker, - NfcWorkerStateEmulateMifareClassic, + NfcWorkerStateMfClassicEmulate, &nfc->dev->dev_data, - nfc_emulate_mifare_classic_worker_callback, + nfc_mf_classic_emulate_worker_callback, nfc); nfc_blink_start(nfc); } -bool nfc_scene_emulate_mifare_classic_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; - if(event.type == SceneManagerEventTypeTick) { - consumed = true; - } else if(event.type == SceneManagerEventTypeBack) { + if(event.type == SceneManagerEventTypeBack) { // Stop worker nfc_worker_stop(nfc->worker); // Check if data changed and save in shadow file - if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateMifareClassic) == + if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicEmulate) == NFC_MF_CLASSIC_DATA_CHANGED) { scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateMifareClassic, NFC_MF_CLASSIC_DATA_NOT_CHANGED); + nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_NOT_CHANGED); nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); } consumed = false; @@ -56,7 +57,7 @@ bool nfc_scene_emulate_mifare_classic_on_event(void* context, SceneManagerEvent return consumed; } -void nfc_scene_emulate_mifare_classic_on_exit(void* context) { +void nfc_scene_mf_classic_emulate_on_exit(void* context) { Nfc* nfc = context; // Clear view diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_keys.c b/applications/nfc/scenes/nfc_scene_mf_classic_keys.c new file mode 100644 index 00000000..0faa7367 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_classic_keys.c @@ -0,0 +1,59 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_keys_widget_callback(GuiButtonType result, InputType type, void* context) { + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_keys_on_enter(void* context) { + Nfc* nfc = context; + + // Load flipper dict keys total + uint32_t flipper_dict_keys_total = 0; + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper); + if(dict) { + flipper_dict_keys_total = mf_classic_dict_get_total_keys(dict); + mf_classic_dict_free(dict); + } + // Load user dict keys total + uint32_t user_dict_keys_total = 0; + dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + if(dict) { + user_dict_keys_total = mf_classic_dict_get_total_keys(dict); + mf_classic_dict_free(dict); + } + + widget_add_string_element( + nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MF Classic Keys"); + char temp_str[32]; + snprintf(temp_str, sizeof(temp_str), "Flipper dict: %ld", flipper_dict_keys_total); + widget_add_string_element(nfc->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, temp_str); + snprintf(temp_str, sizeof(temp_str), "User dict: %ld", user_dict_keys_total); + widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); + widget_add_button_element( + nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_classic_keys_on_exit(void* context) { + Nfc* nfc = context; + + widget_reset(nfc->widget); +} diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c b/applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c new file mode 100644 index 00000000..9f56b0f4 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c @@ -0,0 +1,57 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_mf_classic_keys_add_on_enter(void* context) { + Nfc* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter the key in hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_mf_classic_keys_add_byte_input_callback, + NULL, + nfc, + nfc->byte_input_store, + 6); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + // Add key to dict + bool key_added = false; + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + if(dict) { + if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { + key_added = true; + } + } + if(key_added) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + } + mf_classic_dict_free(dict); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_classic_keys_add_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c b/applications/nfc/scenes/nfc_scene_mf_classic_menu.c old mode 100755 new mode 100644 similarity index 64% rename from applications/nfc/scenes/nfc_scene_mifare_ul_menu.c rename to applications/nfc/scenes/nfc_scene_mf_classic_menu.c index 0099f1a0..4942292c --- a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -5,43 +5,43 @@ enum SubmenuIndex { SubmenuIndexEmulate, }; -void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) { +void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } -void nfc_scene_mifare_ul_menu_on_enter(void* context) { +void nfc_scene_mf_classic_menu_on_enter(void* context) { Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( - submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_ul_menu_submenu_callback, nfc); + submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); submenu_add_item( - submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mifare_ul_menu_submenu_callback, nfc); + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareUlMenu)); + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu)); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } -bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSave) { scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave); - nfc->dev->format = NfcDeviceSaveFormatMifareUl; + nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexSave); + nfc->dev->format = NfcDeviceSaveFormatMifareClassic; // Clear device name nfc_device_set_name(nfc->dev, ""); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; } else if(event.event == SubmenuIndexEmulate) { scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate); - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); + nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { @@ -52,7 +52,7 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) { return consumed; } -void nfc_scene_mifare_ul_menu_on_exit(void* context) { +void nfc_scene_mf_classic_menu_on_exit(void* context) { Nfc* nfc = context; // Clear view diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c new file mode 100644 index 00000000..bd782305 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -0,0 +1,104 @@ +#include "../nfc_i.h" +#include + +void nfc_scene_mf_classic_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + Nfc* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_read_success_on_enter(void* context) { + Nfc* nfc = context; + NfcDeviceData* dev_data = &nfc->dev->dev_data; + MfClassicData* mf_data = &dev_data->mf_classic_data; + string_t str_tmp; + string_init(str_tmp); + + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + + // Setup view + Widget* widget = nfc->widget; + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_classic_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc); + + if(string_size(nfc->dev->dev_data.parsed_data)) { + widget_add_text_box_element( + nfc->widget, + 0, + 0, + 128, + 32, + AlignLeft, + AlignTop, + string_get_cstr(nfc->dev->dev_data.parsed_data), + true); + } else { + widget_add_string_element( + widget, + 0, + 0, + AlignLeft, + AlignTop, + FontSecondary, + mf_classic_get_type_str(mf_data->type)); + widget_add_string_element( + widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)"); + string_printf(str_tmp, "UID:"); + for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { + string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]); + } + widget_add_string_element( + widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); + uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); + uint8_t keys_total = sectors_total * 2; + uint8_t keys_found = 0; + uint8_t sectors_read = 0; + mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); + string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total); + widget_add_string_element( + widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); + string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total); + widget_add_string_element( + widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); + } + + string_clear(str_tmp); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); + consumed = true; + } else if(event.event == GuiButtonTypeRight) { + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + + return consumed; +} + +void nfc_scene_mf_classic_read_success_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/nfc/scenes/nfc_scene_mifare_desfire_app.c b/applications/nfc/scenes/nfc_scene_mf_desfire_app.c similarity index 73% rename from applications/nfc/scenes/nfc_scene_mifare_desfire_app.c rename to applications/nfc/scenes/nfc_scene_mf_desfire_app.c index fdfbd2ec..7faafdcf 100644 --- a/applications/nfc/scenes/nfc_scene_mifare_desfire_app.c +++ b/applications/nfc/scenes/nfc_scene_mf_desfire_app.c @@ -1,15 +1,15 @@ #include "../nfc_i.h" -#define TAG "NfcSceneMifareDesfireApp" +#define TAG "NfcSceneMfDesfireApp" enum SubmenuIndex { SubmenuIndexAppInfo, SubmenuIndexDynamic, // dynamic indexes start here }; -MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) { - uint32_t app_idx = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp) >> 1; +MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(Nfc* nfc) { + uint32_t app_idx = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >> + 1; MifareDesfireApplication* app = nfc->dev->dev_data.mf_df_data.app_head; for(uint32_t i = 0; i < app_idx && app; i++) { app = app->next; @@ -17,16 +17,16 @@ MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) { return app; } -void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) { +void nfc_scene_mf_desfire_app_submenu_callback(void* context, uint32_t index) { Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } -void nfc_scene_mifare_desfire_app_on_enter(void* context) { +void nfc_scene_mf_desfire_app_on_enter(void* context) { Nfc* nfc = context; Submenu* submenu = nfc->submenu; - MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc); + MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc); if(!app) { popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42); popup_set_header(nfc->popup, "Internal Error!", 55, 12, AlignLeft, AlignBottom); @@ -45,11 +45,7 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) { text_box_set_font(nfc->text_box, TextBoxFontHex); submenu_add_item( - submenu, - "App info", - SubmenuIndexAppInfo, - nfc_scene_mifare_desfire_app_submenu_callback, - nfc); + submenu, "App info", SubmenuIndexAppInfo, nfc_scene_mf_desfire_app_submenu_callback, nfc); uint16_t cap = NFC_TEXT_STORE_SIZE; char* buf = nfc->text_store; @@ -65,20 +61,19 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) { char* label = buf; cap -= size + 1; buf += size + 1; - submenu_add_item( - submenu, label, idx++, nfc_scene_mifare_desfire_app_submenu_callback, nfc); + submenu_add_item(submenu, label, idx++, nfc_scene_mf_desfire_app_submenu_callback, nfc); } view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } -bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp); + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp); if(event.type == SceneManagerEventTypeCustom) { - MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc); + MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc); TextBox* text_box = nfc->text_box; string_reset(nfc->text_box_store); if(event.event == SubmenuIndexAppInfo) { @@ -95,14 +90,13 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even mf_df_cat_file(file, nfc->text_box_store); } text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state | 1); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); consumed = true; } else if(event.type == SceneManagerEventTypeBack) { if(state & 1) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state & ~1); consumed = true; } } @@ -110,7 +104,7 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even return consumed; } -void nfc_scene_mifare_desfire_app_on_exit(void* context) { +void nfc_scene_mf_desfire_app_on_exit(void* context) { Nfc* nfc = context; // Clear views diff --git a/applications/nfc/scenes/nfc_scene_mifare_desfire_data.c b/applications/nfc/scenes/nfc_scene_mf_desfire_data.c similarity index 74% rename from applications/nfc/scenes/nfc_scene_mifare_desfire_data.c rename to applications/nfc/scenes/nfc_scene_mf_desfire_data.c index 3eb23fc2..0019a084 100644 --- a/applications/nfc/scenes/nfc_scene_mifare_desfire_data.c +++ b/applications/nfc/scenes/nfc_scene_mf_desfire_data.c @@ -1,6 +1,6 @@ #include "../nfc_i.h" -#define TAG "NfcSceneMifareDesfireData" +#define TAG "NfcSceneMfDesfireData" enum { MifareDesfireDataStateMenu, @@ -12,16 +12,16 @@ enum SubmenuIndex { SubmenuIndexDynamic, // dynamic indexes start here }; -void nfc_scene_mifare_desfire_data_submenu_callback(void* context, uint32_t index) { +void nfc_scene_mf_desfire_data_submenu_callback(void* context, uint32_t index) { Nfc* nfc = (Nfc*)context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } -void nfc_scene_mifare_desfire_data_on_enter(void* context) { +void nfc_scene_mf_desfire_data_on_enter(void* context) { Nfc* nfc = context; Submenu* submenu = nfc->submenu; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; text_box_set_font(nfc->text_box, TextBoxFontHex); @@ -30,7 +30,7 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) { submenu, "Card info", SubmenuIndexCardInfo, - nfc_scene_mifare_desfire_data_submenu_callback, + nfc_scene_mf_desfire_data_submenu_callback, nfc); uint16_t cap = NFC_TEXT_STORE_SIZE; @@ -46,24 +46,23 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) { char* label = buf; cap -= size + 1; buf += size + 1; - submenu_add_item( - submenu, label, idx++, nfc_scene_mifare_desfire_data_submenu_callback, nfc); + submenu_add_item(submenu, label, idx++, nfc_scene_mf_desfire_data_submenu_callback, nfc); } if(state >= MifareDesfireDataStateItem) { submenu_set_selected_item( nfc->submenu, state - MifareDesfireDataStateItem + SubmenuIndexDynamic); scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu); + nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu); } view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } -bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; if(event.type == SceneManagerEventTypeCustom) { @@ -75,23 +74,22 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); scene_manager_set_scene_state( nfc->scene_manager, - NfcSceneMifareDesfireData, + NfcSceneMfDesfireData, MifareDesfireDataStateItem + SubmenuIndexCardInfo); consumed = true; } else { uint16_t index = event.event - SubmenuIndexDynamic; scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateItem + index); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp); + nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateItem + index); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, index << 1); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { if(state >= MifareDesfireDataStateItem) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu); + nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu); consumed = true; } } @@ -99,7 +97,7 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve return consumed; } -void nfc_scene_mifare_desfire_data_on_exit(void* context) { +void nfc_scene_mf_desfire_data_on_exit(void* context) { Nfc* nfc = context; // Clear views diff --git a/applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c b/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c similarity index 61% rename from applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c rename to applications/nfc/scenes/nfc_scene_mf_desfire_menu.c index f6171c8b..f1525114 100644 --- a/applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c @@ -4,33 +4,32 @@ enum SubmenuIndex { SubmenuIndexSave, }; -void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) { +void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } -void nfc_scene_mifare_desfire_menu_on_enter(void* context) { +void nfc_scene_mf_desfire_menu_on_enter(void* context) { Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( - submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_desfire_menu_submenu_callback, nfc); + submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc); submenu_set_selected_item( - nfc->submenu, - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireMenu)); + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu)); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } -bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSave) { scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMifareDesfireMenu, SubmenuIndexSave); + nfc->scene_manager, NfcSceneMfDesfireMenu, SubmenuIndexSave); nfc->dev->format = NfcDeviceSaveFormatMifareDesfire; // Clear device name nfc_device_set_name(nfc->dev, ""); @@ -42,7 +41,7 @@ bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent eve return consumed; } -void nfc_scene_mifare_desfire_menu_on_exit(void* context) { +void nfc_scene_mf_desfire_menu_on_exit(void* context) { Nfc* nfc = context; // Clear view diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c b/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c similarity index 64% rename from applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c rename to applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c index 17f62e41..673b316b 100644 --- a/applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c +++ b/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c @@ -4,22 +4,22 @@ #define NFC_SCENE_READ_SUCCESS_SHIFT " " enum { - ReadMifareDesfireSuccessStateShowUID, - ReadMifareDesfireSuccessStateShowData, + MfDesfireReadSuccessStateShowUID, + MfDesfireReadSuccessStateShowData, }; -void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) { +void nfc_scene_mf_desfire_read_success_dialog_callback(DialogExResult result, void* context) { Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } -void nfc_scene_read_mifare_desfire_success_on_enter(void* context) { +void nfc_scene_mf_desfire_read_success_on_enter(void* context) { Nfc* nfc = context; MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_left_button_text(dialog_ex, "Back"); + dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_center_button_text(dialog_ex, "Data"); dialog_ex_set_right_button_text(dialog_ex, "More"); dialog_ex_set_icon(dialog_ex, 8, 16, &I_Medium_chip_22x21); @@ -55,41 +55,40 @@ void nfc_scene_read_mifare_desfire_success_on_enter(void* context) { n_files == 1 ? "" : "s"); dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 6, AlignLeft, AlignTop); dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback( - dialog_ex, nfc_scene_read_mifare_desfire_success_dialog_callback); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_desfire_read_success_dialog_callback); scene_manager_set_scene_state( - nfc->scene_manager, - NfcSceneReadMifareDesfireSuccess, - ReadMifareDesfireSuccessStateShowUID); + nfc->scene_manager, NfcSceneMfDesfireReadSuccess, MfDesfireReadSuccessStateShowUID); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); } -bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); if(event.type == SceneManagerEventTypeCustom) { - if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) { - scene_manager_previous_scene(nfc->scene_manager); + if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultLeft) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); consumed = true; - } else if( - state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultCenter) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireData); + } else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultCenter) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); consumed = true; - } else if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultRight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireMenu); + } else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireMenu); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { - if(state == ReadMifareDesfireSuccessStateShowData) { + if(state == MfDesfireReadSuccessStateShowData) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); scene_manager_set_scene_state( nfc->scene_manager, - NfcSceneReadMifareDesfireSuccess, - ReadMifareDesfireSuccessStateShowUID); + NfcSceneMfDesfireReadSuccess, + MfDesfireReadSuccessStateShowUID); + consumed = true; + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); consumed = true; } } @@ -97,7 +96,7 @@ bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerE return consumed; } -void nfc_scene_read_mifare_desfire_success_on_exit(void* context) { +void nfc_scene_mf_desfire_read_success_on_exit(void* context) { Nfc* nfc = context; // Clean dialog diff --git a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_emulate.c similarity index 56% rename from applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c rename to applications/nfc/scenes/nfc_scene_mf_ultralight_emulate.c index f23f554e..ce375554 100755 --- a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -4,51 +4,52 @@ #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) #define NFC_MF_UL_DATA_CHANGED (1UL) -void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) { +bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); Nfc* nfc = context; scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED); + nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_CHANGED); + return true; } -void nfc_scene_emulate_mifare_ul_on_enter(void* context) { +void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcEmulate); // Setup view Popup* popup = nfc->popup; if(strcmp(nfc->dev->dev_name, "")) { - nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); + nfc_text_store_set(nfc, "Emulating\n%s", nfc->dev->dev_name); + } else { + nfc_text_store_set(nfc, "Emulating\nMf Ultralight", nfc->dev->dev_name); } popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); - popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop); + popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop); // Setup and start worker view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); nfc_worker_start( nfc->worker, - NfcWorkerStateEmulateMifareUltralight, + NfcWorkerStateMfUltralightEmulate, &nfc->dev->dev_data, - nfc_emulate_mifare_ul_worker_callback, + nfc_mf_ultralight_emulate_worker_callback, nfc); nfc_blink_start(nfc); } -bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; - if(event.type == SceneManagerEventTypeTick) { - consumed = true; - } else if(event.type == SceneManagerEventTypeBack) { + if(event.type == SceneManagerEventTypeBack) { // Stop worker nfc_worker_stop(nfc->worker); // Check if data changed and save in shadow file - if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateMifareUl) == + if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate) == NFC_MF_UL_DATA_CHANGED) { scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED); + nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_NOT_CHANGED); nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); } consumed = false; @@ -56,7 +57,7 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event return consumed; } -void nfc_scene_emulate_mifare_ul_on_exit(void* context) { +void nfc_scene_mf_ultralight_emulate_on_exit(void* context) { Nfc* nfc = context; // Clear view diff --git a/applications/nfc/scenes/nfc_scene_mifare_classic_menu.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c similarity index 66% rename from applications/nfc/scenes/nfc_scene_mifare_classic_menu.c rename to applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c index 4611d16b..615c516d 100644 --- a/applications/nfc/scenes/nfc_scene_mifare_classic_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -5,47 +5,47 @@ enum SubmenuIndex { SubmenuIndexEmulate, }; -void nfc_scene_mifare_classic_menu_submenu_callback(void* context, uint32_t index) { +void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } -void nfc_scene_mifare_classic_menu_on_enter(void* context) { +void nfc_scene_mf_ultralight_menu_on_enter(void* context) { Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( - submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_classic_menu_submenu_callback, nfc); + submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, - nfc_scene_mifare_classic_menu_submenu_callback, + nfc_scene_mf_ultralight_menu_submenu_callback, nfc); submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareUlMenu)); + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu)); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } -bool nfc_scene_mifare_classic_menu_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSave) { scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave); - nfc->dev->format = NfcDeviceSaveFormatMifareClassic; + nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexSave); + nfc->dev->format = NfcDeviceSaveFormatMifareUl; // Clear device name nfc_device_set_name(nfc->dev, ""); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; } else if(event.event == SubmenuIndexEmulate) { scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate); - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic); + nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexEmulate); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { @@ -56,7 +56,7 @@ bool nfc_scene_mifare_classic_menu_on_event(void* context, SceneManagerEvent eve return consumed; } -void nfc_scene_mifare_classic_menu_on_exit(void* context) { +void nfc_scene_mf_ultralight_menu_on_exit(void* context) { Nfc* nfc = context; // Clear view diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c similarity index 77% rename from applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c rename to applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index 5bcf1589..8b1b6c00 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -8,19 +8,16 @@ enum { ReadMifareUlStateShowData, }; -void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) { +void nfc_scene_mf_ultralight_read_success_dialog_callback(DialogExResult result, void* context) { Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } -void nfc_scene_read_mifare_ul_success_on_enter(void* context) { +void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - // Send notification - notification_message(nfc->notifications, &sequence_success); - // Setup dialog view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; @@ -48,7 +45,7 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { data->uid[6]); dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop); dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_read_success_dialog_callback); // Setup TextBox view TextBox* text_box = nfc->text_box; @@ -63,34 +60,37 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID); + nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); } -bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; bool consumed = false; uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess); + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); if(event.type == SceneManagerEventTypeCustom) { if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) { - scene_manager_previous_scene(nfc->scene_manager); + scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); consumed = true; } else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultRight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareUlMenu); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); consumed = true; } else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultCenter) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowData); + nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowData); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { if(state == ReadMifareUlStateShowData) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID); + nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID); + consumed = true; + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); consumed = true; } } @@ -98,7 +98,7 @@ bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent return consumed; } -void nfc_scene_read_mifare_ul_success_on_exit(void* context) { +void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { Nfc* nfc = context; // Clean views diff --git a/applications/nfc/scenes/nfc_scene_read.c b/applications/nfc/scenes/nfc_scene_read.c new file mode 100644 index 00000000..9e1c0109 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_read.c @@ -0,0 +1,108 @@ +#include "../nfc_i.h" +#include + +typedef enum { + NfcSceneReadStateIdle, + NfcSceneReadStateDetecting, + NfcSceneReadStateReading, +} NfcSceneReadState; + +bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) { + Nfc* nfc = context; + bool consumed = false; + if(event == NfcWorkerEventReadMfClassicLoadKeyCache) { + consumed = nfc_device_load_key_cache(nfc->dev); + } else { + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + consumed = true; + } + return consumed; +} + +void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { + uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneRead); + if(curr_state != state) { + if(state == NfcSceneReadStateDetecting) { + popup_set_header(nfc->popup, "Detecting\nNFC card", 90, 24, AlignCenter, AlignTop); + popup_set_icon(nfc->popup, 5, 7, &I_NFC_manual); + } else if(state == NfcSceneReadStateReading) { + popup_set_header( + nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); + popup_set_icon(nfc->popup, 19, 23, &A_Loading_24); + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, state); + } +} + +void nfc_scene_read_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcRead); + + nfc_device_clear(nfc->dev); + // Setup view + nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + // Start worker + nfc_worker_start( + nfc->worker, NfcWorkerStateRead, &nfc->dev->dev_data, nfc_scene_read_worker_callback, nfc); + + nfc_blink_start(nfc); +} + +bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if((event.event == NfcWorkerEventReadUidNfcB) || + (event.event == NfcWorkerEventReadUidNfcF) || + (event.event == NfcWorkerEventReadUidNfcV) || + (event.event == NfcWorkerEventReadUidNfcA)) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadMfUltralight) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadMfClassicDone) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadMfDesfire) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadBankCard) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { + if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + } + consumed = true; + } else if(event.event == NfcWorkerEventCardDetected) { + nfc_scene_read_set_state(nfc, NfcSceneReadStateReading); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_read_on_exit(void* context) { + Nfc* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + // Clear view + popup_reset(nfc->popup); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, NfcSceneReadStateIdle); + + nfc_blink_stop(nfc); +} diff --git a/applications/nfc/scenes/nfc_scene_read_card.c b/applications/nfc/scenes/nfc_scene_read_card.c deleted file mode 100755 index 0cd0fc89..00000000 --- a/applications/nfc/scenes/nfc_scene_read_card.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "../nfc_i.h" -#include - -void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); -} - -void nfc_scene_read_card_on_enter(void* context) { - Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcRead); - - // Setup view - Popup* popup = nfc->popup; - popup_set_header(popup, "Detecting\nNFC card", 70, 34, AlignLeft, AlignTop); - popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); - - // Start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfc_worker_start( - nfc->worker, NfcWorkerStateDetect, &nfc->dev->dev_data, nfc_read_card_worker_callback, nfc); - - nfc_blink_start(nfc); -} - -bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerExit) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeTick) { - consumed = true; - } - return consumed; -} - -void nfc_scene_read_card_on_exit(void* context) { - Nfc* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/nfc/scenes/nfc_scene_read_card_success.c b/applications/nfc/scenes/nfc_scene_read_card_success.c index c0a865bc..b889ce08 100755 --- a/applications/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/nfc/scenes/nfc_scene_read_card_success.c @@ -22,9 +22,6 @@ void nfc_scene_read_card_success_on_enter(void* context) { string_init(uid_str); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - // Send notification - notification_message(nfc->notifications, &sequence_success); - // Setup view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; Widget* widget = nfc->widget; @@ -38,18 +35,12 @@ void nfc_scene_read_card_success_on_enter(void* context) { widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); if(data->type == FuriHalNfcTypeA) { widget_add_button_element( - widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc); + widget, GuiButtonTypeRight, "Save", nfc_scene_read_card_success_widget_callback, nfc); widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21); - string_cat_printf(data_str, " may be:"); widget_add_string_element( widget, 37, 12, AlignLeft, AlignBottom, FontPrimary, string_get_cstr(data_str)); string_printf( - data_str, - "%s\nATQA: %02X%02X SAK: %02X", - nfc_guess_protocol(nfc->dev->dev_data.protocol), - data->atqa[0], - data->atqa[1], - data->sak); + data_str, "ATQA: %02X%02X\nSAK: %02X", data->atqa[0], data->atqa[1], data->sak); widget_add_string_multiline_element( widget, 37, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); widget_add_string_element( @@ -69,16 +60,15 @@ void nfc_scene_read_card_success_on_enter(void* context) { bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; - FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeLeft) { consumed = scene_manager_previous_scene(nfc->scene_manager); - } else if(data->type == FuriHalNfcTypeA && event.event == GuiButtonTypeRight) { - // Clear device name + } else if(event.event == GuiButtonTypeRight) { + nfc->dev->format = NfcDeviceSaveFormatUid; nfc_device_set_name(nfc->dev, ""); - scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; } } diff --git a/applications/nfc/scenes/nfc_scene_read_emv_app.c b/applications/nfc/scenes/nfc_scene_read_emv_app.c deleted file mode 100755 index 5bb8ac5f..00000000 --- a/applications/nfc/scenes/nfc_scene_read_emv_app.c +++ /dev/null @@ -1,58 +0,0 @@ -#include "../nfc_i.h" -#include - -void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); -} - -void nfc_scene_read_emv_app_on_enter(void* context) { - Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcRead); - - // Setup view - Popup* popup = nfc->popup; - popup_set_header(popup, "Reading\nbank card", 70, 34, AlignLeft, AlignTop); - popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - // Start worker - nfc_worker_start( - nfc->worker, - NfcWorkerStateReadEMVApp, - &nfc->dev->dev_data, - nfc_read_emv_app_worker_callback, - nfc); - nfc_blink_start(nfc); -} - -bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerExit) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeTick) { - consumed = true; - } - - return consumed; -} - -void nfc_scene_read_emv_app_on_exit(void* context) { - Nfc* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/nfc/scenes/nfc_scene_read_emv_app_success.c b/applications/nfc/scenes/nfc_scene_read_emv_app_success.c deleted file mode 100755 index b9bc5ba4..00000000 --- a/applications/nfc/scenes/nfc_scene_read_emv_app_success.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "../nfc_i.h" -#include "../helpers/nfc_emv_parser.h" -#include - -void nfc_scene_read_emv_app_widget_callback(GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_read_emv_app_success_on_enter(void* context) { - Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - - // Setup view - FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; - EmvData* emv_data = &nfc->dev->dev_data.emv_data; - Widget* widget = nfc->widget; - widget_add_button_element( - widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_emv_app_widget_callback, nfc); - widget_add_button_element( - widget, GuiButtonTypeRight, "Run app", nfc_scene_read_emv_app_widget_callback, nfc); - widget_add_string_element(widget, 36, 5, AlignLeft, AlignTop, FontPrimary, "Found EMV App"); - widget_add_icon_element(widget, 8, 5, &I_Medium_chip_22x21); - // Display UID - string_t temp_str; - string_init_printf(temp_str, "UID:"); - for(size_t i = 0; i < nfc_data->uid_len; i++) { - string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); - } - widget_add_string_element( - widget, 36, 18, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); - string_reset(temp_str); - // Display application - string_printf(temp_str, "App: "); - string_t aid; - string_init(aid); - bool aid_found = - nfc_emv_parser_get_aid_name(nfc->dev->storage, emv_data->aid, emv_data->aid_len, aid); - if(!aid_found) { - for(uint8_t i = 0; i < emv_data->aid_len; i++) { - string_cat_printf(aid, "%02X", emv_data->aid[i]); - } - } - string_cat(temp_str, aid); - widget_add_string_element( - widget, 7, 29, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); - string_clear(temp_str); - string_clear(aid); - - // Send notification - if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) == - NFC_SEND_NOTIFICATION_TRUE) { - notification_message(nfc->notifications, &sequence_success); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE); - } - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeLeft) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } else if(event.event == GuiButtonTypeRight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_read_emv_app_success_on_exit(void* context) { - Nfc* nfc = context; - - // Clear views - widget_reset(nfc->widget); -} diff --git a/applications/nfc/scenes/nfc_scene_read_emv_data.c b/applications/nfc/scenes/nfc_scene_read_emv_data.c deleted file mode 100755 index e1881cef..00000000 --- a/applications/nfc/scenes/nfc_scene_read_emv_data.c +++ /dev/null @@ -1,59 +0,0 @@ -#include "../nfc_i.h" -#include - -void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); -} - -void nfc_scene_read_emv_data_on_enter(void* context) { - Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcRead); - - // Setup view - Popup* popup = nfc->popup; - popup_set_header(popup, "Reading\nbank card", 70, 34, AlignLeft, AlignTop); - popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - // Clear emv data - memset(&nfc->dev->dev_data.emv_data, 0, sizeof(nfc->dev->dev_data.emv_data)); - // Start worker - nfc_worker_start( - nfc->worker, - NfcWorkerStateReadEMVData, - &nfc->dev->dev_data, - nfc_read_emv_data_worker_callback, - nfc); - - nfc_blink_start(nfc); -} - -bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerExit) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeTick) { - consumed = true; - } - return consumed; -} - -void nfc_scene_read_emv_data_on_exit(void* context) { - Nfc* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_classic.c b/applications/nfc/scenes/nfc_scene_read_mifare_classic.c deleted file mode 100644 index a901ecd4..00000000 --- a/applications/nfc/scenes/nfc_scene_read_mifare_classic.c +++ /dev/null @@ -1,96 +0,0 @@ -#include "../nfc_i.h" - -enum { - NfcSceneReadMifareClassicStateInProgress, - NfcSceneReadMifareClassicStateDone, -}; - -void nfc_read_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) { - furi_assert(context); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, event); -} - -void nfc_read_mifare_classic_dict_attack_result_callback(void* context) { - furi_assert(context); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackDone); -} - -void nfc_scene_read_mifare_classic_on_enter(void* context) { - Nfc* nfc = context; - - // Setup and start worker - memset(&nfc->dev->dev_data.mf_classic_data, 0, sizeof(MfClassicData)); - dict_attack_set_result_callback( - nfc->dict_attack, nfc_read_mifare_classic_dict_attack_result_callback, nfc); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateInProgress); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); - nfc_worker_start( - nfc->worker, - NfcWorkerStateReadMifareClassic, - &nfc->dev->dev_data, - nfc_read_mifare_classic_worker_callback, - nfc); - - nfc_blink_start(nfc); -} - -bool nfc_scene_read_mifare_classic_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeTick) { - consumed = true; - } else if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventDictAttackDone) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareClassicMenu); - consumed = true; - } else if(event.event == NfcWorkerEventDetectedClassic1k) { - dict_attack_card_detected(nfc->dict_attack, MfClassicType1k); - consumed = true; - } else if(event.event == NfcWorkerEventDetectedClassic4k) { - dict_attack_card_detected(nfc->dict_attack, MfClassicType4k); - consumed = true; - } else if(event.event == NfcWorkerEventNewSector) { - dict_attack_inc_curr_sector(nfc->dict_attack); - consumed = true; - } else if(event.event == NfcWorkerEventFoundKeyA) { - dict_attack_inc_found_key(nfc->dict_attack, MfClassicKeyA); - consumed = true; - } else if(event.event == NfcWorkerEventFoundKeyB) { - dict_attack_inc_found_key(nfc->dict_attack, MfClassicKeyB); - consumed = true; - } else if(event.event == NfcWorkerEventNoCardDetected) { - dict_attack_card_removed(nfc->dict_attack); - consumed = true; - } else if(event.event == NfcWorkerEventSuccess) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateDone); - nfc_blink_stop(nfc); - notification_message(nfc->notifications, &sequence_success); - dict_attack_set_result(nfc->dict_attack, true); - consumed = true; - } else if(event.event == NfcWorkerEventFail) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateDone); - nfc_blink_stop(nfc); - dict_attack_set_result(nfc->dict_attack, false); - consumed = true; - } else if(event.event == NfcWorkerEventNoDictFound) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_read_mifare_classic_on_exit(void* context) { - Nfc* nfc = context; - // Stop worker - nfc_worker_stop(nfc->worker); - dict_attack_reset(nfc->dict_attack); - - nfc_blink_stop(nfc); -} diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_desfire.c b/applications/nfc/scenes/nfc_scene_read_mifare_desfire.c deleted file mode 100644 index fc99b64c..00000000 --- a/applications/nfc/scenes/nfc_scene_read_mifare_desfire.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "../nfc_i.h" -#include - -void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); -} - -void nfc_scene_read_mifare_desfire_on_enter(void* context) { - Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcRead); - - // Setup view - Popup* popup = nfc->popup; - popup_set_header(popup, "Reading\nDESFire", 70, 34, AlignLeft, AlignTop); - popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - // Start worker - nfc_worker_start( - nfc->worker, - NfcWorkerStateReadMifareDesfire, - &nfc->dev->dev_data, - nfc_read_mifare_desfire_worker_callback, - nfc); - nfc_blink_start(nfc); -} - -bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerExit) { - notification_message(nfc->notifications, &sequence_success); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeTick) { - consumed = true; - } - return consumed; -} - -void nfc_scene_read_mifare_desfire_on_exit(void* context) { - Nfc* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul.c deleted file mode 100755 index 444f6253..00000000 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "../nfc_i.h" -#include - -void nfc_read_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); -} - -void nfc_scene_read_mifare_ul_on_enter(void* context) { - Nfc* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcRead); - - // Setup view - Popup* popup = nfc->popup; - popup_set_header(popup, "Detecting\nultralight", 70, 34, AlignLeft, AlignTop); - popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - // Start worker - nfc_worker_start( - nfc->worker, - NfcWorkerStateReadMifareUltralight, - &nfc->dev->dev_data, - nfc_read_mifare_ul_worker_callback, - nfc); - nfc_blink_start(nfc); -} - -bool nfc_scene_read_mifare_ul_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerExit) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUlSuccess); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeTick) { - consumed = true; - } - return consumed; -} - -void nfc_scene_read_mifare_ul_on_exit(void* context) { - Nfc* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/nfc/scenes/nfc_scene_retry_confirm.c b/applications/nfc/scenes/nfc_scene_retry_confirm.c new file mode 100644 index 00000000..f7b3991e --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_retry_confirm.c @@ -0,0 +1,47 @@ +#include "../nfc_i.h" + +void nfc_scene_retry_confirm_dialog_callback(DialogExResult result, void* context) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_retry_confirm_on_enter(void* context) { + Nfc* nfc = context; + DialogEx* dialog_ex = nfc->dialog_ex; + + dialog_ex_set_left_button_text(dialog_ex, "Retry"); + dialog_ex_set_right_button_text(dialog_ex, "Stay"); + dialog_ex_set_header(dialog_ex, "Retry reading?", 64, 11, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog_ex, "All unsaved data will be\nlost.", 64, 25, AlignCenter, AlignTop); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else if(event.event == DialogExResultLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneRead); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = true; + } + + return consumed; +} + +void nfc_scene_retry_confirm_on_exit(void* context) { + Nfc* nfc = context; + + // Clean view + dialog_ex_reset(nfc->dialog_ex); +} diff --git a/applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c b/applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c deleted file mode 100755 index 5ee9f442..00000000 --- a/applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "../nfc_i.h" - -void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); -} - -void nfc_scene_run_emv_app_confirm_on_enter(void* context) { - Nfc* nfc = context; - - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_left_button_text(dialog_ex, "Back"); - dialog_ex_set_right_button_text(dialog_ex, "Run"); - dialog_ex_set_header(dialog_ex, "Run EMV app?", 64, 8, AlignCenter, AlignCenter); - dialog_ex_set_text( - dialog_ex, - "It will try to run card's app\nand detect unencrypted\ndata", - 64, - 18, - AlignCenter, - AlignTop); - dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback(dialog_ex, nfc_scene_run_emv_app_confirm_dialog_callback); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); -} - -bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == DialogExResultLeft) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } else if(event.event == DialogExResultRight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_run_emv_app_confirm_on_exit(void* context) { - Nfc* nfc = context; - - // Clean view - dialog_ex_reset(nfc->dialog_ex); -} diff --git a/applications/nfc/scenes/nfc_scene_save_success.c b/applications/nfc/scenes/nfc_scene_save_success.c index 5c15a509..355f4a80 100644 --- a/applications/nfc/scenes/nfc_scene_save_success.c +++ b/applications/nfc/scenes/nfc_scene_save_success.c @@ -27,13 +27,9 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneCardMenu)) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfDesfireMenu)) { consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneCardMenu); - } else if(scene_manager_has_previous_scene( - nfc->scene_manager, NfcSceneMifareDesfireMenu)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMifareDesfireMenu); + nfc->scene_manager, NfcSceneMfDesfireMenu); } else { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneStart); diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/nfc/scenes/nfc_scene_saved_menu.c index f2b2dea3..269864ca 100644 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/nfc/scenes/nfc_scene_saved_menu.c @@ -61,9 +61,9 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); if(event.event == SubmenuIndexEmulate) { if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } diff --git a/applications/nfc/scenes/nfc_scene_scripts_menu.c b/applications/nfc/scenes/nfc_scene_scripts_menu.c deleted file mode 100755 index 446b9d82..00000000 --- a/applications/nfc/scenes/nfc_scene_scripts_menu.c +++ /dev/null @@ -1,82 +0,0 @@ -#include "../nfc_i.h" - -enum SubmenuIndex { - SubmenuIndexBankCard, - SubmenuIndexMifareUltralight, - SubmenuIdexReadMfClassic, - SubmenuIndexMifareDesfire, -}; - -void nfc_scene_scripts_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_scripts_menu_on_enter(void* context) { - Nfc* nfc = context; - Submenu* submenu = nfc->submenu; - - submenu_add_item( - submenu, - "Read Bank Card", - SubmenuIndexBankCard, - nfc_scene_scripts_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Read Mifare Ultral/Ntag", - SubmenuIndexMifareUltralight, - nfc_scene_scripts_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Read Mifare Classic", - SubmenuIdexReadMfClassic, - nfc_scene_scripts_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Read Mifare DESFire", - SubmenuIndexMifareDesfire, - nfc_scene_scripts_menu_submenu_callback, - nfc); - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneScriptsMenu)); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_scripts_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexBankCard) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexBankCard); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp); - consumed = true; - } else if(event.event == SubmenuIndexMifareUltralight) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexMifareUltralight); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl); - consumed = true; - } else if(event.event == SubmenuIdexReadMfClassic) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIdexReadMfClassic); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic); - consumed = true; - } else if(event.event == SubmenuIndexMifareDesfire) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexMifareDesfire); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_scripts_menu_on_exit(void* context) { - Nfc* nfc = context; - submenu_reset(nfc->submenu); -} diff --git a/applications/nfc/scenes/nfc_scene_start.c b/applications/nfc/scenes/nfc_scene_start.c index d64aa76e..01ffb46b 100644 --- a/applications/nfc/scenes/nfc_scene_start.c +++ b/applications/nfc/scenes/nfc_scene_start.c @@ -2,8 +2,9 @@ enum SubmenuIndex { SubmenuIndexRead, - SubmenuIndexRunScript, + SubmenuIndexDetectReader, SubmenuIndexSaved, + SubmenuIndexExtraAction, SubmenuIndexAddManualy, SubmenuIndexDebug, }; @@ -18,15 +19,12 @@ void nfc_scene_start_on_enter(void* context) { Nfc* nfc = context; Submenu* submenu = nfc->submenu; + submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc); submenu_add_item( - submenu, "Read Card", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc); - submenu_add_item( - submenu, - "Run Special Action", - SubmenuIndexRunScript, - nfc_scene_start_submenu_callback, - nfc); + submenu, "Detect Reader", SubmenuIndexDetectReader, nfc_scene_start_submenu_callback, nfc); submenu_add_item(submenu, "Saved", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc); + submenu_add_item( + submenu, "Extra Actions", SubmenuIndexExtraAction, nfc_scene_start_submenu_callback, nfc); submenu_add_item( submenu, "Add Manually", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc); @@ -48,14 +46,17 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexRead) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCard); + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); consumed = true; - } else if(event.event == SubmenuIndexRunScript) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu); + } else if(event.event == SubmenuIndexDetectReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); consumed = true; } else if(event.event == SubmenuIndexSaved) { scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect); consumed = true; + } else if(event.event == SubmenuIndexExtraAction) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions); + consumed = true; } else if(event.event == SubmenuIndexAddManualy) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); consumed = true; diff --git a/applications/nfc/views/dict_attack.c b/applications/nfc/views/dict_attack.c index 0f9da494..25690005 100644 --- a/applications/nfc/views/dict_attack.c +++ b/applications/nfc/views/dict_attack.c @@ -1,83 +1,60 @@ #include "dict_attack.h" -#include +#include #include typedef enum { - DictAttackStateSearchCard, - DictAttackStateSearchKeys, + DictAttackStateRead, DictAttackStateCardRemoved, - DictAttackStateSuccess, - DictAttackStateFail, } DictAttackState; struct DictAttack { View* view; - DictAttackResultCallback callback; + DictAttackCallback callback; void* context; }; typedef struct { DictAttackState state; MfClassicType type; - uint8_t current_sector; - uint8_t total_sectors; - uint8_t keys_a_found; - uint8_t keys_a_total; - uint8_t keys_b_found; - uint8_t keys_b_total; + string_t header; + uint8_t sectors_total; + uint8_t sectors_read; + uint8_t sector_current; + uint8_t keys_total; + uint8_t keys_found; } DictAttackViewModel; static void dict_attack_draw_callback(Canvas* canvas, void* model) { DictAttackViewModel* m = model; - if(m->state == DictAttackStateSearchCard) { + if(m->state == DictAttackStateCardRemoved) { canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, 64, 32, AlignCenter, AlignCenter, "Detecting Mifare Classic"); - } else if(m->state == DictAttackStateCardRemoved) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, 64, 32, AlignCenter, AlignTop, "Place card back to flipper"); - } else { - char draw_str[32]; - if(m->state == DictAttackStateSearchKeys) { - snprintf( - draw_str, sizeof(draw_str), "Searching keys for sector %d", m->current_sector); - canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, draw_str); - } else if(m->state == DictAttackStateSuccess) { - canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Complete!"); - elements_button_right(canvas, "More"); - } else if(m->state == DictAttackStateFail) { - canvas_draw_str_aligned( - canvas, 64, 2, AlignCenter, AlignTop, "Failed to read any sector"); - } - uint16_t keys_found = m->keys_a_found + m->keys_b_found; - uint16_t keys_total = m->keys_a_total + m->keys_b_total; - float progress = (float)(m->current_sector) / (float)(m->total_sectors); - elements_progress_bar(canvas, 5, 12, 120, progress); + canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!"); canvas_set_font(canvas, FontSecondary); - snprintf(draw_str, sizeof(draw_str), "Total keys found: %d/%d", keys_found, keys_total); - canvas_draw_str_aligned(canvas, 1, 23, AlignLeft, AlignTop, draw_str); + elements_multiline_text_aligned( + canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly."); + } else if(m->state == DictAttackStateRead) { + char draw_str[32] = {}; + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, string_get_cstr(m->header)); + canvas_set_font(canvas, FontSecondary); + float progress = + m->sectors_total == 0 ? 0 : (float)(m->sector_current) / (float)(m->sectors_total); + elements_progress_bar(canvas, 5, 15, 120, progress); + canvas_set_font(canvas, FontSecondary); + snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); + canvas_draw_str_aligned(canvas, 1, 28, AlignLeft, AlignTop, draw_str); snprintf( - draw_str, sizeof(draw_str), "A keys found: %d/%d", m->keys_a_found, m->keys_a_total); - canvas_draw_str_aligned(canvas, 1, 34, AlignLeft, AlignTop, draw_str); - snprintf( - draw_str, sizeof(draw_str), "B keys found: %d/%d", m->keys_b_found, m->keys_b_total); - canvas_draw_str_aligned(canvas, 1, 45, AlignLeft, AlignTop, draw_str); + draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total); + canvas_draw_str_aligned(canvas, 1, 40, AlignLeft, AlignTop, draw_str); } + elements_button_center(canvas, "Skip"); } static bool dict_attack_input_callback(InputEvent* event, void* context) { DictAttack* dict_attack = context; bool consumed = false; - DictAttackState state; - with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - state = model->state; - return false; - }); - if(state == DictAttackStateSuccess && event->type == InputTypeShort && - event->key == InputKeyRight) { + if(event->type == InputTypeShort && event->key == InputKeyOk) { if(dict_attack->callback) { dict_attack->callback(dict_attack->context); } @@ -93,11 +70,21 @@ DictAttack* dict_attack_alloc() { view_set_draw_callback(dict_attack->view, dict_attack_draw_callback); view_set_input_callback(dict_attack->view, dict_attack_input_callback); view_set_context(dict_attack->view, dict_attack); + with_view_model( + dict_attack->view, (DictAttackViewModel * model) { + string_init(model->header); + return false; + }); return dict_attack; } void dict_attack_free(DictAttack* dict_attack) { furi_assert(dict_attack); + with_view_model( + dict_attack->view, (DictAttackViewModel * model) { + string_clear(model->header); + return false; + }); view_free(dict_attack->view); free(dict_attack); } @@ -106,8 +93,15 @@ void dict_attack_reset(DictAttack* dict_attack) { furi_assert(dict_attack); with_view_model( dict_attack->view, (DictAttackViewModel * model) { - memset(model, 0, sizeof(DictAttackViewModel)); - return true; + model->state = DictAttackStateRead; + model->type = MfClassicType1k; + model->sectors_total = 0; + model->sectors_read = 0; + model->sector_current = 0; + model->keys_total = 0; + model->keys_found = 0; + string_reset(model->header); + return false; }); } @@ -116,78 +110,88 @@ View* dict_attack_get_view(DictAttack* dict_attack) { return dict_attack->view; } -void dict_attack_set_result_callback( - DictAttack* dict_attack, - DictAttackResultCallback callback, - void* context) { +void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context) { furi_assert(dict_attack); furi_assert(callback); dict_attack->callback = callback; dict_attack->context = context; } -void dict_attack_card_detected(DictAttack* dict_attack, MfClassicType type) { +void dict_attack_set_header(DictAttack* dict_attack, const char* header) { + furi_assert(dict_attack); + furi_assert(header); + + with_view_model( + dict_attack->view, (DictAttackViewModel * model) { + string_set_str(model->header, header); + return true; + }); +} + +void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) { furi_assert(dict_attack); with_view_model( dict_attack->view, (DictAttackViewModel * model) { - model->state = DictAttackStateSearchKeys; - if(type == MfClassicType1k) { - model->total_sectors = 16; - model->keys_a_total = 16; - model->keys_b_total = 16; - } else if(type == MfClassicType4k) { - model->total_sectors = 40; - model->keys_a_total = 40; - model->keys_b_total = 40; + model->state = DictAttackStateRead; + model->sectors_total = mf_classic_get_total_sectors_num(type); + model->keys_total = model->sectors_total * 2; + return true; + }); +} + +void dict_attack_set_card_removed(DictAttack* dict_attack) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, (DictAttackViewModel * model) { + model->state = DictAttackStateCardRemoved; + return true; + }); +} + +void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, (DictAttackViewModel * model) { + model->sectors_read = sec_read; + return true; + }); +} + +void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, (DictAttackViewModel * model) { + model->keys_found = keys_found; + return true; + }); +} + +void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, (DictAttackViewModel * model) { + model->sector_current = curr_sec; + return true; + }); +} + +void dict_attack_inc_current_sector(DictAttack* dict_attack) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, (DictAttackViewModel * model) { + if(model->sector_current < model->sectors_total) { + model->sector_current++; } return true; }); } -void dict_attack_card_removed(DictAttack* dict_attack) { +void dict_attack_inc_keys_found(DictAttack* dict_attack) { furi_assert(dict_attack); with_view_model( dict_attack->view, (DictAttackViewModel * model) { - if(model->state == DictAttackStateSearchKeys) { - model->state = DictAttackStateCardRemoved; - } else { - model->state = DictAttackStateSearchCard; - } - return true; - }); -} - -void dict_attack_inc_curr_sector(DictAttack* dict_attack) { - furi_assert(dict_attack); - with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - model->current_sector++; - return true; - }); -} - -void dict_attack_inc_found_key(DictAttack* dict_attack, MfClassicKey key) { - furi_assert(dict_attack); - with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - model->state = DictAttackStateSearchKeys; - if(key == MfClassicKeyA) { - model->keys_a_found++; - } else if(key == MfClassicKeyB) { - model->keys_b_found++; - } - return true; - }); -} - -void dict_attack_set_result(DictAttack* dict_attack, bool success) { - furi_assert(dict_attack); - with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - if(success) { - model->state = DictAttackStateSuccess; - } else { - model->state = DictAttackStateFail; + if(model->keys_found < model->keys_total) { + model->keys_found++; } return true; }); diff --git a/applications/nfc/views/dict_attack.h b/applications/nfc/views/dict_attack.h index f8d5afca..3f557b19 100644 --- a/applications/nfc/views/dict_attack.h +++ b/applications/nfc/views/dict_attack.h @@ -3,11 +3,11 @@ #include #include -#include +#include typedef struct DictAttack DictAttack; -typedef void (*DictAttackResultCallback)(void* context); +typedef void (*DictAttackCallback)(void* context); DictAttack* dict_attack_alloc(); @@ -17,17 +17,20 @@ void dict_attack_reset(DictAttack* dict_attack); View* dict_attack_get_view(DictAttack* dict_attack); -void dict_attack_set_result_callback( - DictAttack* dict_attack, - DictAttackResultCallback callback, - void* context); +void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context); -void dict_attack_card_detected(DictAttack* dict_attack, MfClassicType type); +void dict_attack_set_header(DictAttack* dict_attack, const char* header); -void dict_attack_card_removed(DictAttack* dict_attack); +void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type); -void dict_attack_inc_curr_sector(DictAttack* dict_attack); +void dict_attack_set_card_removed(DictAttack* dict_attack); -void dict_attack_inc_found_key(DictAttack* dict_attack, MfClassicKey key); +void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read); -void dict_attack_set_result(DictAttack* dict_attack, bool success); +void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found); + +void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec); + +void dict_attack_inc_current_sector(DictAttack* dict_attack); + +void dict_attack_inc_keys_found(DictAttack* dict_attack); diff --git a/applications/unit_tests/nfc/nfc_test.c b/applications/unit_tests/nfc/nfc_test.c index 13060a6d..dcd162d1 100644 --- a/applications/unit_tests/nfc/nfc_test.c +++ b/applications/unit_tests/nfc/nfc_test.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include diff --git a/assets/icons/NFC/NFC_manual.png b/assets/icons/NFC/NFC_manual.png new file mode 100644 index 0000000000000000000000000000000000000000..d142f0fcf6c043f990efad9cfa7eca1417499b2f GIT binary patch literal 3785 zcmaJ^c|26@+dq~HWl5Hhj1f-@W(*@HV_!y%Ft$;NF=iNMYm8-xl%$d^Th@d~4W$&x zmdH*N31!KW&{#sUz0>o1dVcR8Z}0hh&bhDqzOV21TF>X)=bFt)3t=HyApih`Em5Wz z?x@YZ;R1ZzCsOo_5da98kW5T$EKN*6bOwz`A`<{0us_o-0GqHPr9ZSn5Op-}n=45n zUj)EPY=I^*=Nz${0PeDwxM4%YRUtKMdLPK=FA5GTo;?+rPdK65m%zT*7QX5|fDen9MGC#TL_ISvTCDb;qVjPkx`!&YiQ$?sux7pQH4*G)HK|QK8G+ z-OYiZIpAEHVQNurZurJI9M!)V6EoS$Z>&LGnN-?rjJU87bEs=ntK^KTH=(DA$dbEAwU>lU$L$|`E1A2R&s6VHy++75p1_VU>Lfnc0+b& zJRs(&1!JuMKtj!Gtl<$Jpgkq;GXPY6*?Z<*qBQ!o005X~Up)NCXveOX66{)$jF+3ekEBVwg5HFSh0hsDoaoTf`} zciWp)x3}_&Aiq(Qz#g0;;_7bqm_BfafOKjMKNyG7x*3)Snz|}s3vOs)}9b!@};;q3oIIIa!+|isZ_i|z)3LtvPRus;DmeDrOH9#tM!5Ih>|$0 zIa}qM;(o;}<+Fc@>~T#%9S~{0Id)P=Q8^A~xzo}IHGopfv&+-(79(Y#Ri@)8&7Z~u z9*40(De+}-qH)$Y*P36Al}R8Pu8yJwa}Hqg62*_h2?pc*cW=XtQ?u{ewijl-6S#jB zar=}dCEMQyVi#GsN6RlwxjkLVq%}`1x93e7$&<9=1({-22!0ITZI3!JvnAf2aKe2hj&-9YgZX9iG^HE);wx^`NIv-r+@|c5w$L026D| zY3rI>?YeR4CtmpRl?e0fE2vz1eA#Q6Xho^lFv2|6xR>F`H?8V(%gX)q(+5Vux@?uo|D5fm%tgcM-8DwCHGmP=9s5 z`z&KtYIeGx<44al%v8->LQoJZeu5R+6}A--6$5^qU-jSOr&&{iOD#(xQy;r5mMGtI zm!!XPdO2MRN1<8*+Ho>u4ITVkTO9t2&n;4U*WBfid%Ih`D&p(Ca=R>Z|0-Ac7U}sJ z9w@C(WYhM!v$Z}E27UB!?j+biUVUD}SoNXyM4vQbMOW!tW?Ng6>L9z1-8>Vc+mqpw zg{%HhIj|lban~%P;dqpGRAX{~^7+|2idjx5I|$MHj-N!a$L&$?QEA@1_W|vn;j?wqI73}D_w$GUb=>>I*ag&g< z{%4)fu2t=~ev+Y*)eEIG4b-0=u4)Z-L+B$3KRc%Q^k3`q-VVAQS)E@E9zs?th4zM~ zhVEF;T08c$btCpi%?N8jYX0OlH=dU~<2+RtWiLMA^WjtAPvyV61HLVK+l%dxUHX#7 zy99-u6&MM$TImJ3RlMe)r)pZ4WQ#ziHsJk?;qS@zCS%C> zne_6o^84i%10#Q!&8LVn_Z$$My*5_gSC72**_U^coTiyEmS&&K#21eb<~*04nCfWF z3eakeu4YJHr%VKa)w zI4pRx1{Y#5;oW!dnjE?0q?J^d*xX7j{(kB?UJ{q&;lS}u={fCq;jna)E1S-~SN!9V zdHKYs(@EE!^GhsBfB&cBWi7MQsOh|EDtpDb=Hc-wZ=;?!SLTF^%?ORn$y`ek`{Lux`kT4Za(^W7&)|?aic-2OrkdJQk#2 zw4?W<5cKi%Fj{~5Y+Arm`l-Vrbw=Ya{~F3aAN<+o%bku_gRk0$QZJM(2~49{N4gO; zer&Z|N;dLN73a&1+)Vki@)p%)TcI3{&v?H^c&t-acIH9k{OZ`HgwF*Y1zDLV4Uq3r z2U#oV^;91hTbC+Nlg=yyY34U{nd?gP;-|@2m$^#%ckqh)fO6T1B4jbrB9y){f_iwG zHceP*opsVHW`4JtKGwx~d*P>dZIAE!AMe#&ZnLU5uV>`Ss45@#l`B^){qSF&l@1X4 zh8}bYiVb|YUfsX(b;nQ9uNO);O9-`;;U8|bZk?~3ML8mZky)FGTW=#rx-Hr)dX&tS zqGK}^6y$_us}?*u5=IIh7wqY533c3JP5VBW9NHLNJJE?<@0;7X8r4}-%qm=Da2^ys zL^LWjDpYo`kn{QLMI8enoN`XZP-B%s>cMrxO`FB8pZLatH`Xiqljk?rAuE>`*TQs_ zcXLmbGE6fp(~d@D2H+S3z{rEKp&(Rh~N@X2uvI(kV2;VA_9@%zj+Z{`PVW84EkGz>4OCS$0@9p4akJXAb^gl z!_@FlC=_&5R~@dcO>oD<-L+IfFenTLfx;nBT{Wl<0tQFG;h=vmFxMc%gNVSGn*U>t zJ41rKm`pkX0tpBRP!G^lr!hPs8oIi=5GV`+gQ;;f)O=Y~CN5Bo>Z|md!Ia>OXOQSj z5{(M_#fWpK`7x1TuCxD%fYZs44eL3pdfwFf%oRo9mbx z=|atn;TmQ~%{6{wO=);P3W3V}jrI61R_Bk{UkyQ_b1j<^7$kp!hdF~r0sS2{g7jx! z;D6-%2kY@?U$p;-g>apL{HpE$s`c+BZUg-i|7~9GF^l|QmiG6zL|?Z9Mjo<1=7qv{VsCIy9lXQ* zhEJ=17~6Wsy)-;EbvzO$E^=GEWx4I%K}^G)j5oHHrJAy<-Nu52r2*^`Kh4v*5nf)G z^Gz*P)ZQT<3^oRrY@{e+%Q!RS?eevkM?3J(_1~R?ehm=VLB7#)$dbfdRYYgpEp5t+ s3XUk+l1M+)O`IlT5V=EGecoN%KT@84gF@y2H$uSD?4)V2vD>Bp0cbL;?f?J) literal 0 HcmV?d00001 diff --git a/assets/icons/NFC/Reader_detect.png b/assets/icons/NFC/Reader_detect.png new file mode 100644 index 0000000000000000000000000000000000000000..56d3663eaa2666f68493fa3088f9beab1bcf0717 GIT binary patch literal 3771 zcmaJ@c{r4N`+r3CEm@Lu#*i&$jI|kKn;E+yjEtpaFvg@=jH$7dsBA4H*&AuGFO@Z+ zY@vjZvP(#E@E%K?#JuCYr}O^)`1L;5^E}`C{$BUzb1&b|b6rpTQAcYr;r+q@0EpSz zU|hKCVeX?Y$jf~nm0R%!0AWiq8hz9jjRw&fG=K6LA^?O8vt3Cz*Ev~}_3>4deO%;i zdzy=kAjk!EEmAs3RZ~ew(k@Qv-jIxQ(;iDpK822)INpSW$m=rBTB28l2L+~;?k8M+ z5O?+U=4AMT!1wj*pS!lJKA6sytgtJ31R4cJQ*HE|4I)JgQ3v;YyxiW}HaQJ3j}lg) z1CoLjeoDbx$~?eE1QK}|+$iuI;0fs$5d<2sS&cdeVmT6DQ5oJmkym&cnMp_N1tX;a z^RNU|9$;?86Uk0jbp>+xfK#2mK2yL^ZQzvJ#n1gfBzq$xoCol_tt7*flLUbF65}vH zfH6?gbL^@mfY$+}{q0-fz@RpuW9#m313az)8oMP$$^k)9K*u>QS_9w<2TpY;D~AAA zG5~3-Wq0Hshsz{qHMx_@C`Z<+z%8S^1hs<%+}$Au)w^xw4oe#nb`dhoA2 z?ptU6j6nWaU;Fs{lS-8C@hEG)jgQT5RvmH=^xP7<;xqa=(fUV?2@JFlz_>+zM`88jz`_nczLLg!T@-D+LR|eNxR^kF8E|>Bhs9Yk+p^9%1VsAV-UxTDc-xdc*3@4hR+jSbh>=V#yJ);9@Ye79Zq9v5<+xY}sB3j(G|M9UB-n#fT z-<~HdKB*|nMj=B!779c-XkmkQz&j4w6o3w>=fd$?!OItC5OSJX%++_U10zCl7IbQhio^R2Strt->sQoBhhkuZH~s z%LU-KwLphEqNmx@Ez^3_3e!rsq)y$aEPi zxQE+gkm!jjy;tq>$T_xPum0Igc-LiFTl?J7`zihV1LOkM$&bD;pY0h-Ip~=7*1fND z&iYH*7v5Ets9225<@Pv|x_s6?fqf)-*1kvS4tetZ*W}xAI!3Vh^w|uF44NBWvs&}K zOww!N6uT7F6a`HvuCOStXuL?oZN;quSY?MK(>XWXa^XD|{ z(zg`ru9*}S-h-p{?DX6#Tvl%Tn+Z&%2W{M8IttCI=clbiTpgEQ()gsIkf-lZ3nO|5 z7Nw@8;)`vHor|sK8w|@9^4WO}mUSMRQQ{Wuc52>g)}+Ml-RxP{A=j~d;e1)F31Y1b zQWTi0aIX%-dO^)!OwWFPA~M^7mOmcaF#G+$1?U!Ti}F2x%~}-CUm>c(KO)+_5Bbs{ zh=x>zwvYVbj6U9Cj?N{d5Yi^EB-QpJ9}HOCu#&h=Zu6c}nWD5&+8(I#t17A5W4~e- zGhMK?c^Y}f4#p1cU2nSXcfHRr$TER_(4Ebi&H9ivQFF>O#8a!fp!zA%wtU(%&ttK= zo*L~5_sGS&c^rfz zNIr6;nwMoQi^&bi7oJ_Xv1KA47CR(ftmvs25nRcTMjS(oXLjFNG`sL}HFXY3!uLq_ z4C+l)@9orRC9_?#`mITFq}t%iD{mZVSQ`ttctAW zg@Tbsi-wEj#n{oiZ}jhKWP9iZzisJ2e{`PdH50j;q7yh#65)h)iXv6bDnostN$#Z| z9@pfuiq;8Ba;D!*8F!~lr;tYDy5k-v-xxL4bkuY@wa~IpMo*wGDs%ieVVqtdKk^U{ zi8nsVBFbym=0@0gr56cih!Ntq@}UKb>p8U+G8T!KN-xbcl_~{v{C=}kX?-@mJE@y2 z9(^?8%lo$igwKR)EfJz>(Xr9)F=h$$IQ;%zSegN=cN85wf%%R}#f)c>U{3Hy+I9w- zrbUp`$YG;r`p?YTApRb22JmdW?HT(6aENA^A@$7ji609qv7gwVM5e;!(xDy4>7n@YK1rJ9mE{QvJly_ndd+hT@yqD?DDOon?a}|C2Vpv=_~28 z|GCZ*Vs!cTOX{^6=)n|$SAi8bOLlu`3sf9K6cWp)d=Z2Eg@N#5O=!o!?%sYPj@)5NJ_L&KF~6UQnS*1lPe zK-0R^N9rzDqiY|$Kt8P}=D+IhGB(3K#I54K;|v%3#;OP(HmJRe3gPwN^nV{1@v2|n zGJW-Y#Er)dJK#S++_c@SST`$+FPhs(-J~2Zb)*C>wDb1yZV4!hSAVE|H=x*Of^$iH ze|X+ny#2T5+w3KlwwR%q+l@PIpOopC(CN8#p^5c_Vu;~$*TYLD1^RzGr$|zSosW^Q`v-4?>yh6i?&u>uLhV*?ugJr5m->@Q%RSfGDeMaokUvLH zjohyepY`pYI4wb2dM3%7?6c%tn>DUC?)F}O%3LlVnc3_9)IIYN;w0rO^DA;Yx!?q?P6F%Rk;89oIbwBD)y5GUyo|G-1hzL&N4Y!XvD_A{Dt(7 z89`v$zB)QOAR{=0=tt1?(eo$xYJqfhbYV~!_cqdo86kA_5HL9C?+eUL$nf(=xL~aQ zPRI33zyVAq9RY>1SS$!j4?<&*pfETb4%N|x>gsB9Bea7re9Ltzk|ovwZcVzK`_ltTF@I+*D~ z{BOPgFL5v~lum@Y5QAxF8NS@J^H<(UMMt0+L;{n>z|m-Deh%_z0F6lt4xrINx_S^8 zNF7V?B~y2HH2#8Mu?SmgFq1&_CE8+4z+4gtne2zKFwn-<1Ycc#K7RoIKx^uSw=d6EjaRszv{v%$l^N;+ARIcV3TydkQgM-`;ga4=l z&XT)wIGo&}yJK8y7t_Vjl>^Mw=-6?+r?waiT*z?cK(Evlkf3>QCx^32O*o`}v$7O= zLoc5{N^(!zEvAy^^v2;N?D_L4B*T~5p4me}6@#favJF&P$70~$N+Z4>sq{OSKzO+{ zC^Io*QIEVcQfxSwTXHA&OH~GWUV$l>_^fcccLE1n)z($>w47$&FfNX(QvUvSI5`@2 z1n(7YC?Nn>F3l?3owvs((0fU7yZ^;*ukRD6Iy3uQlkMBTPo-serVnhg%x9 #include -#include +#include #ifdef __cplusplus extern "C" { diff --git a/furi/core/common_defines.h b/furi/core/common_defines.h index d75f7592..e95e45f7 100644 --- a/furi/core/common_defines.h +++ b/furi/core/common_defines.h @@ -88,6 +88,10 @@ extern "C" { #define FURI_BIT(x, n) (((x) >> (n)) & 1) #endif +#ifndef FURI_BIT_SET +#define FURI_BIT_SET(x, n) ((x) |= (1 << (n))) +#endif + #ifndef FURI_IS_IRQ_MASKED #define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U) #endif diff --git a/lib/SConscript b/lib/SConscript index a3617c5d..c5bc3947 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -70,6 +70,7 @@ libs = env.BuildModules( "infrared", "littlefs", "subghz", + "nfc", "appframe", "misc", "mbedtls", diff --git a/lib/misc.scons b/lib/misc.scons index 91a11ff6..5a826b18 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -7,7 +7,6 @@ env.Append( "#/lib/heatshrink", "#/lib/micro-ecc", "#/lib/nanopb", - "#/lib/nfc_protocols", "#/lib/u8g2", ], CPPDEFINES=[ @@ -24,7 +23,6 @@ sources = [] libs_recurse = [ "digital_signal", "micro-ecc", - "nfc_protocols", "one_wire", "u8g2", "update_util", diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript new file mode 100644 index 00000000..657f3a9e --- /dev/null +++ b/lib/nfc/SConscript @@ -0,0 +1,16 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/nfc", + ], +) + +libenv = env.Clone(FW_LIB_NAME="nfc") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c*") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/nfc/helpers/mf_classic_dict.c b/lib/nfc/helpers/mf_classic_dict.c new file mode 100644 index 00000000..410ddbd8 --- /dev/null +++ b/lib/nfc/helpers/mf_classic_dict.c @@ -0,0 +1,148 @@ +#include "mf_classic_dict.h" + +#include +#include + +#define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") +#define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc") + +#define TAG "MfClassicDict" + +#define NFC_MF_CLASSIC_KEY_LEN (13) + +struct MfClassicDict { + Stream* stream; + uint32_t total_keys; +}; + +bool mf_classic_dict_check_presence(MfClassicDictType dict_type) { + Storage* storage = furi_record_open(RECORD_STORAGE); + + bool dict_present = false; + if(dict_type == MfClassicDictTypeFlipper) { + dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_FLIPPER_PATH, NULL) == FSE_OK; + } else if(dict_type == MfClassicDictTypeUser) { + dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_USER_PATH, NULL) == FSE_OK; + } + + furi_record_close(RECORD_STORAGE); + + return dict_present; +} + +MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) { + MfClassicDict* dict = malloc(sizeof(MfClassicDict)); + Storage* storage = furi_record_open(RECORD_STORAGE); + dict->stream = buffered_file_stream_alloc(storage); + furi_record_close(RECORD_STORAGE); + + bool dict_loaded = false; + do { + if(dict_type == MfClassicDictTypeFlipper) { + if(!buffered_file_stream_open( + dict->stream, MF_CLASSIC_DICT_FLIPPER_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + buffered_file_stream_close(dict->stream); + break; + } + } else if(dict_type == MfClassicDictTypeUser) { + if(!buffered_file_stream_open( + dict->stream, MF_CLASSIC_DICT_USER_PATH, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) { + buffered_file_stream_close(dict->stream); + break; + } + } + + // Read total amount of keys + string_t next_line; + string_init(next_line); + while(true) { + if(!stream_read_line(dict->stream, next_line)) break; + if(string_get_char(next_line, 0) == '#') continue; + if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + dict->total_keys++; + } + string_clear(next_line); + stream_rewind(dict->stream); + + dict_loaded = true; + FURI_LOG_I(TAG, "Loaded dictionary with %d keys", dict->total_keys); + } while(false); + + if(!dict_loaded) { + buffered_file_stream_close(dict->stream); + free(dict); + dict = NULL; + } + + return dict; +} + +void mf_classic_dict_free(MfClassicDict* dict) { + furi_assert(dict); + furi_assert(dict->stream); + + buffered_file_stream_close(dict->stream); + stream_free(dict->stream); + free(dict); +} + +uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict) { + furi_assert(dict); + + return dict->total_keys; +} + +bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key) { + furi_assert(dict); + furi_assert(dict->stream); + + uint8_t key_byte_tmp = 0; + string_t next_line; + string_init(next_line); + + bool key_read = false; + *key = 0ULL; + while(!key_read) { + if(!stream_read_line(dict->stream, next_line)) break; + if(string_get_char(next_line, 0) == '#') continue; + if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + for(uint8_t i = 0; i < 12; i += 2) { + args_char_to_hex( + string_get_char(next_line, i), string_get_char(next_line, i + 1), &key_byte_tmp); + *key |= (uint64_t)key_byte_tmp << 8 * (5 - i / 2); + } + key_read = true; + } + + string_clear(next_line); + return key_read; +} + +bool mf_classic_dict_rewind(MfClassicDict* dict) { + furi_assert(dict); + furi_assert(dict->stream); + + return stream_rewind(dict->stream); +} + +bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key) { + furi_assert(dict); + furi_assert(dict->stream); + + string_t key_str; + string_init(key_str); + for(size_t i = 0; i < 6; i++) { + string_cat_printf(key_str, "%02X", key[i]); + } + string_cat_printf(key_str, "\n"); + + bool key_added = false; + do { + if(!stream_seek(dict->stream, 0, StreamOffsetFromEnd)) break; + if(!stream_insert_string(dict->stream, key_str)) break; + key_added = true; + } while(false); + + string_clear(key_str); + return key_added; +} diff --git a/lib/nfc/helpers/mf_classic_dict.h b/lib/nfc/helpers/mf_classic_dict.h new file mode 100644 index 00000000..2654e668 --- /dev/null +++ b/lib/nfc/helpers/mf_classic_dict.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include +#include + +typedef enum { + MfClassicDictTypeUser, + MfClassicDictTypeFlipper, +} MfClassicDictType; + +typedef struct MfClassicDict MfClassicDict; + +bool mf_classic_dict_check_presence(MfClassicDictType dict_type); + +MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type); + +void mf_classic_dict_free(MfClassicDict* dict); + +uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict); + +bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key); + +bool mf_classic_dict_rewind(MfClassicDict* dict); + +bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key); diff --git a/applications/nfc/helpers/nfc_debug_pcap.c b/lib/nfc/helpers/nfc_debug_pcap.c similarity index 100% rename from applications/nfc/helpers/nfc_debug_pcap.c rename to lib/nfc/helpers/nfc_debug_pcap.c diff --git a/applications/nfc/helpers/nfc_debug_pcap.h b/lib/nfc/helpers/nfc_debug_pcap.h similarity index 100% rename from applications/nfc/helpers/nfc_debug_pcap.h rename to lib/nfc/helpers/nfc_debug_pcap.h diff --git a/applications/nfc/nfc_device.c b/lib/nfc/nfc_device.c similarity index 79% rename from applications/nfc/nfc_device.c rename to lib/nfc/nfc_device.c index a3bff23a..649a2c5f 100644 --- a/applications/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -3,20 +3,29 @@ #include "m-string.h" #include "nfc_types.h" -#include +#include +#include +#include #include +#define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/cache") +#define NFC_DEVICE_KEYS_EXTENSION ".keys" + static const char* nfc_file_header = "Flipper NFC device"; static const uint32_t nfc_file_version = 2; +static const char* nfc_keys_file_header = "Flipper NFC keys"; +static const uint32_t nfc_keys_file_version = 1; + // Protocols format versions -static const uint32_t nfc_mifare_classic_data_format_version = 1; +static const uint32_t nfc_mifare_classic_data_format_version = 2; NfcDevice* nfc_device_alloc() { NfcDevice* nfc_dev = malloc(sizeof(NfcDevice)); nfc_dev->storage = furi_record_open(RECORD_STORAGE); nfc_dev->dialogs = furi_record_open(RECORD_DIALOGS); string_init(nfc_dev->load_path); + string_init(nfc_dev->dev_data.parsed_data); return nfc_dev; } @@ -26,6 +35,7 @@ void nfc_device_free(NfcDevice* nfc_dev) { furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_DIALOGS); string_clear(nfc_dev->load_path); + string_clear(nfc_dev->dev_data.parsed_data); free(nfc_dev); } @@ -648,6 +658,52 @@ bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) { return parsed; } +static void nfc_device_write_mifare_classic_block( + string_t block_str, + MfClassicData* data, + uint8_t block_num) { + string_reset(block_str); + bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); + if(is_sec_trailer) { + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); + // Write key A + for(size_t i = 0; i < sizeof(sec_tr->key_a); i++) { + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { + string_cat_printf(block_str, "%02X ", sec_tr->key_a[i]); + } else { + string_cat_printf(block_str, "?? "); + } + } + // Write Access bytes + for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i++) { + if(mf_classic_is_block_read(data, block_num)) { + string_cat_printf(block_str, "%02X ", sec_tr->access_bits[i]); + } else { + string_cat_printf(block_str, "?? "); + } + } + // Write key B + for(size_t i = 0; i < sizeof(sec_tr->key_b); i++) { + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { + string_cat_printf(block_str, "%02X ", sec_tr->key_b[i]); + } else { + string_cat_printf(block_str, "?? "); + } + } + } else { + // Write data block + for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) { + if(mf_classic_is_block_read(data, block_num)) { + string_cat_printf(block_str, "%02X ", data->block[block_num].value[i]); + } else { + string_cat_printf(block_str, "?? "); + } + } + } + string_strim(block_str); +} + static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) { bool saved = false; MfClassicData* data = &dev->dev_data.mf_classic_data; @@ -669,23 +725,21 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* if(!flipper_format_write_uint32( file, "Data format version", &nfc_mifare_classic_data_format_version, 1)) break; - if(!flipper_format_write_comment_cstr( - file, "Key map is the bit mask indicating valid key in each sector")) + file, "Mifare Classic blocks, \'??\' means unknown data")) break; - if(!flipper_format_write_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break; - if(!flipper_format_write_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break; - - if(!flipper_format_write_comment_cstr(file, "Mifare Classic blocks")) break; bool block_saved = true; + string_t block_str; + string_init(block_str); for(size_t i = 0; i < blocks; i++) { string_printf(temp_str, "Block %d", i); - if(!flipper_format_write_hex( - file, string_get_cstr(temp_str), data->block[i].value, 16)) { + nfc_device_write_mifare_classic_block(block_str, data, i); + if(!flipper_format_write_string(file, string_get_cstr(temp_str), block_str)) { block_saved = false; break; } } + string_clear(block_str); if(!block_saved) break; saved = true; } while(false); @@ -694,6 +748,59 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* return saved; } +static void nfc_device_load_mifare_classic_block( + string_t block_str, + MfClassicData* data, + uint8_t block_num) { + string_strim(block_str); + MfClassicBlock block_tmp = {}; + bool is_sector_trailer = mf_classic_is_sector_trailer(block_num); + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + uint16_t block_unknown_bytes_mask = 0; + + string_strim(block_str); + for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) { + char hi = string_get_char(block_str, 3 * i); + char low = string_get_char(block_str, 3 * i + 1); + uint8_t byte = 0; + if(hex_chars_to_uint8(hi, low, &byte)) { + block_tmp.value[i] = byte; + } else { + FURI_BIT_SET(block_unknown_bytes_mask, i); + } + } + + if(block_unknown_bytes_mask == 0xffff) { + // All data is unknown, exit + return; + } + + if(is_sector_trailer) { + MfClassicSectorTrailer* sec_tr_tmp = (MfClassicSectorTrailer*)&block_tmp; + // Load Key A + // Key A mask 0b0000000000111111 = 0x003f + if((block_unknown_bytes_mask & 0x003f) == 0) { + uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_a, sizeof(sec_tr_tmp->key_a)); + mf_classic_set_key_found(data, sector_num, MfClassicKeyA, key); + } + // Load Access Bits + // Access bits mask 0b0000001111000000 = 0x03c0 + if((block_unknown_bytes_mask & 0x03c0) == 0) { + mf_classic_set_block_read(data, block_num, &block_tmp); + } + // Load Key B + // Key B mask 0b1111110000000000 = 0xfc00 + if((block_unknown_bytes_mask & 0xfc00) == 0) { + uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_b, sizeof(sec_tr_tmp->key_b)); + mf_classic_set_key_found(data, sector_num, MfClassicKeyB, key); + } + } else { + if(block_unknown_bytes_mask == 0) { + mf_classic_set_block_read(data, block_num, &block_tmp); + } + } +} + static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; MfClassicData* data = &dev->dev_data.mf_classic_data; @@ -701,6 +808,7 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* uint32_t data_format_version = 0; string_init(temp_str); uint16_t data_blocks = 0; + memset(data, 0, sizeof(MfClassicData)); do { // Read Mifare Classic type @@ -715,29 +823,40 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* break; } + bool old_format = false; // Read Mifare Classic format version if(!flipper_format_read_uint32(file, "Data format version", &data_format_version, 1)) { // Load unread sectors with zero keys access for backward compatability if(!flipper_format_rewind(file)) break; - data->key_a_mask = 0xffffffffffffffff; - data->key_b_mask = 0xffffffffffffffff; + old_format = true; } else { - if(data_format_version != nfc_mifare_classic_data_format_version) break; - if(!flipper_format_read_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break; - if(!flipper_format_read_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break; + if(data_format_version < nfc_mifare_classic_data_format_version) { + old_format = true; + } } // Read Mifare Classic blocks bool block_read = true; + string_t block_str; + string_init(block_str); for(size_t i = 0; i < data_blocks; i++) { string_printf(temp_str, "Block %d", i); - if(!flipper_format_read_hex( - file, string_get_cstr(temp_str), data->block[i].value, 16)) { + if(!flipper_format_read_string(file, string_get_cstr(temp_str), block_str)) { block_read = false; break; } + nfc_device_load_mifare_classic_block(block_str, data, i); } + string_clear(block_str); if(!block_read) break; + + // Set keys and blocks as unknown for backward compatibility + if(old_format) { + data->key_a_mask = 0ULL; + data->key_b_mask = 0ULL; + memset(data->block_read_mask, 0, sizeof(data->block_read_mask)); + } + parsed = true; } while(false); @@ -745,6 +864,113 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* return parsed; } +static void nfc_device_get_key_cache_file_path(NfcDevice* dev, string_t file_path) { + uint8_t* uid = dev->dev_data.nfc_data.uid; + uint8_t uid_len = dev->dev_data.nfc_data.uid_len; + string_set_str(file_path, NFC_DEVICE_KEYS_FOLDER "/"); + for(size_t i = 0; i < uid_len; i++) { + string_cat_printf(file_path, "%02X", uid[i]); + } + string_cat_printf(file_path, NFC_DEVICE_KEYS_EXTENSION); +} + +static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) { + FlipperFormat* file = flipper_format_file_alloc(dev->storage); + MfClassicData* data = &dev->dev_data.mf_classic_data; + string_t temp_str; + string_init(temp_str); + + nfc_device_get_key_cache_file_path(dev, temp_str); + bool save_success = false; + do { + if(!storage_simply_mkdir(dev->storage, NFC_DEVICE_KEYS_FOLDER)) break; + if(!storage_simply_remove(dev->storage, string_get_cstr(temp_str))) break; + if(!flipper_format_file_open_always(file, string_get_cstr(temp_str))) break; + if(!flipper_format_write_header_cstr(file, nfc_keys_file_header, nfc_keys_file_version)) + break; + if(data->type == MfClassicType1k) { + if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break; + } else if(data->type == MfClassicType4k) { + if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "4K")) break; + } + if(!flipper_format_write_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break; + if(!flipper_format_write_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break; + uint8_t sector_num = mf_classic_get_total_sectors_num(data->type); + bool key_save_success = true; + for(size_t i = 0; (i < sector_num) && (key_save_success); i++) { + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i); + if(FURI_BIT(data->key_a_mask, i)) { + string_printf(temp_str, "Key A sector %d", i); + key_save_success = + flipper_format_write_hex(file, string_get_cstr(temp_str), sec_tr->key_a, 6); + } + if(!key_save_success) break; + if(FURI_BIT(data->key_a_mask, i)) { + string_printf(temp_str, "Key B sector %d", i); + key_save_success = + flipper_format_write_hex(file, string_get_cstr(temp_str), sec_tr->key_b, 6); + } + } + save_success = key_save_success; + } while(false); + + flipper_format_free(file); + string_clear(temp_str); + return save_success; +} + +bool nfc_device_load_key_cache(NfcDevice* dev) { + furi_assert(dev); + string_t temp_str; + string_init(temp_str); + + MfClassicData* data = &dev->dev_data.mf_classic_data; + nfc_device_get_key_cache_file_path(dev, temp_str); + FlipperFormat* file = flipper_format_file_alloc(dev->storage); + + bool load_success = false; + do { + if(storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) != FSE_OK) break; + if(!flipper_format_file_open_existing(file, string_get_cstr(temp_str))) break; + uint32_t version = 0; + if(!flipper_format_read_header(file, temp_str, &version)) break; + if(string_cmp_str(temp_str, nfc_keys_file_header)) break; + if(version != nfc_keys_file_version) break; + if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break; + if(!string_cmp_str(temp_str, "1K")) { + data->type = MfClassicType1k; + } else if(!string_cmp_str(temp_str, "4K")) { + data->type = MfClassicType4k; + } else { + break; + } + if(!flipper_format_read_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break; + if(!flipper_format_read_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break; + uint8_t sectors = mf_classic_get_total_sectors_num(data->type); + bool key_read_success = true; + for(size_t i = 0; (i < sectors) && (key_read_success); i++) { + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i); + if(FURI_BIT(data->key_a_mask, i)) { + string_printf(temp_str, "Key A sector %d", i); + key_read_success = + flipper_format_read_hex(file, string_get_cstr(temp_str), sec_tr->key_a, 6); + } + if(!key_read_success) break; + if(FURI_BIT(data->key_b_mask, i)) { + string_printf(temp_str, "Key B sector %d", i); + key_read_success = + flipper_format_read_hex(file, string_get_cstr(temp_str), sec_tr->key_b, 6); + } + } + load_success = key_read_success; + } while(false); + + string_clear(temp_str); + flipper_format_free(file); + + return load_success; +} + void nfc_device_set_name(NfcDevice* dev, const char* name) { furi_assert(dev); @@ -815,7 +1041,10 @@ static bool nfc_device_save_file( } else if(dev->format == NfcDeviceSaveFormatBankCard) { if(!nfc_device_save_bank_card_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { + // Save data if(!nfc_device_save_mifare_classic_data(file, dev)) break; + // Save keys cache + if(!nfc_device_save_mifare_classic_keys(dev)) break; } saved = true; } while(0); @@ -954,14 +1183,22 @@ bool nfc_file_select(NfcDevice* dev) { void nfc_device_data_clear(NfcDeviceData* dev_data) { if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) { mf_df_clear(&dev_data->mf_df_data); + } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { + memset(&dev_data->mf_classic_data, 0, sizeof(MfClassicData)); + } else if(dev_data->protocol == NfcDeviceProtocolMifareUl) { + memset(&dev_data->mf_ul_data, 0, sizeof(MfUltralightData)); + } else if(dev_data->protocol == NfcDeviceProtocolEMV) { + memset(&dev_data->emv_data, 0, sizeof(EmvData)); } + memset(&dev_data->nfc_data, 0, sizeof(FuriHalNfcDevData)); + dev_data->protocol = NfcDeviceProtocolUnknown; + string_reset(dev_data->parsed_data); } void nfc_device_clear(NfcDevice* dev) { furi_assert(dev); nfc_device_data_clear(&dev->dev_data); - memset(&dev->dev_data, 0, sizeof(dev->dev_data)); dev->format = NfcDeviceSaveFormatUid; string_reset(dev->load_path); } diff --git a/applications/nfc/nfc_device.h b/lib/nfc/nfc_device.h similarity index 89% rename from applications/nfc/nfc_device.h rename to lib/nfc/nfc_device.h index 5ffca5ca..e1ff6d42 100644 --- a/applications/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -6,10 +6,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include #define NFC_DEV_NAME_MAX_LEN 22 #define NFC_READER_DATA_MAX_SIZE 64 @@ -51,6 +51,7 @@ typedef struct { MfClassicData mf_classic_data; MifareDesfireData mf_df_data; }; + string_t parsed_data; } NfcDeviceData; typedef struct { @@ -78,6 +79,8 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name); bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog); +bool nfc_device_load_key_cache(NfcDevice* dev); + bool nfc_file_select(NfcDevice* dev); void nfc_device_data_clear(NfcDeviceData* dev); diff --git a/applications/nfc/nfc_types.c b/lib/nfc/nfc_types.c similarity index 100% rename from applications/nfc/nfc_types.c rename to lib/nfc/nfc_types.c diff --git a/applications/nfc/nfc_types.h b/lib/nfc/nfc_types.h similarity index 100% rename from applications/nfc/nfc_types.h rename to lib/nfc/nfc_types.h diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c new file mode 100644 index 00000000..4a3176ff --- /dev/null +++ b/lib/nfc/nfc_worker.c @@ -0,0 +1,510 @@ +#include "nfc_worker_i.h" +#include + +#include +#include "parsers/nfc_supported_card.h" + +#define TAG "NfcWorker" + +/***************************** NFC Worker API *******************************/ + +NfcWorker* nfc_worker_alloc() { + NfcWorker* nfc_worker = malloc(sizeof(NfcWorker)); + + // Worker thread attributes + nfc_worker->thread = furi_thread_alloc(); + furi_thread_set_name(nfc_worker->thread, "NfcWorker"); + furi_thread_set_stack_size(nfc_worker->thread, 8192); + furi_thread_set_callback(nfc_worker->thread, nfc_worker_task); + furi_thread_set_context(nfc_worker->thread, nfc_worker); + + nfc_worker->callback = NULL; + nfc_worker->context = NULL; + nfc_worker->storage = furi_record_open(RECORD_STORAGE); + + // Initialize rfal + while(furi_hal_nfc_is_busy()) { + furi_delay_ms(10); + } + nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + nfc_worker->debug_pcap_worker = nfc_debug_pcap_alloc(nfc_worker->storage); + } + + return nfc_worker; +} + +void nfc_worker_free(NfcWorker* nfc_worker) { + furi_assert(nfc_worker); + + furi_thread_free(nfc_worker->thread); + + furi_record_close(RECORD_STORAGE); + + if(nfc_worker->debug_pcap_worker) nfc_debug_pcap_free(nfc_worker->debug_pcap_worker); + + free(nfc_worker); +} + +NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker) { + return nfc_worker->state; +} + +void nfc_worker_start( + NfcWorker* nfc_worker, + NfcWorkerState state, + NfcDeviceData* dev_data, + NfcWorkerCallback callback, + void* context) { + furi_assert(nfc_worker); + furi_assert(dev_data); + while(furi_hal_nfc_is_busy()) { + furi_delay_ms(10); + } + + nfc_worker->callback = callback; + nfc_worker->context = context; + nfc_worker->dev_data = dev_data; + nfc_worker_change_state(nfc_worker, state); + furi_thread_start(nfc_worker->thread); +} + +void nfc_worker_stop(NfcWorker* nfc_worker) { + furi_assert(nfc_worker); + if(nfc_worker->state == NfcWorkerStateBroken || nfc_worker->state == NfcWorkerStateReady) { + return; + } + furi_hal_nfc_stop(); + nfc_worker_change_state(nfc_worker, NfcWorkerStateStop); + furi_thread_join(nfc_worker->thread); +} + +void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state) { + nfc_worker->state = state; +} + +/***************************** NFC Worker Thread *******************************/ + +int32_t nfc_worker_task(void* context) { + NfcWorker* nfc_worker = context; + + furi_hal_nfc_exit_sleep(); + + if(nfc_worker->state == NfcWorkerStateRead) { + nfc_worker_read(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateUidEmulate) { + nfc_worker_emulate_uid(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateEmulateApdu) { + nfc_worker_emulate_apdu(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateMfUltralightEmulate) { + nfc_worker_emulate_mf_ultralight(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { + nfc_worker_emulate_mf_classic(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) { + nfc_worker_mf_classic_dict_attack(nfc_worker, MfClassicDictTypeUser); + } else if(nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack) { + nfc_worker_mf_classic_dict_attack(nfc_worker, MfClassicDictTypeFlipper); + } + furi_hal_nfc_sleep(); + nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); + + return 0; +} + +static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + bool read_success = false; + MfUltralightReader reader = {}; + MfUltralightData data = {}; + + nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + do { + // Read card + if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break; + if(!mf_ul_read_card(tx_rx, &reader, &data)) break; + // Copy data + nfc_worker->dev_data->mf_ul_data = data; + read_success = true; + } while(false); + + return read_success; +} + +static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker->callback); + bool read_success = false; + + nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + do { + // Try to read supported card + FURI_LOG_I(TAG, "Try read supported card ..."); + for(size_t i = 0; i < NfcSupportedCardTypeEnd; i++) { + if(nfc_supported_card[i].protocol == NfcDeviceProtocolMifareClassic) { + if(nfc_supported_card[i].verify(nfc_worker, tx_rx)) { + if(nfc_supported_card[i].read(nfc_worker, tx_rx)) { + read_success = true; + nfc_supported_card[i].parse(nfc_worker); + } + } + } + } + if(read_success) break; + // Try to read card with key cache + FURI_LOG_I(TAG, "Search for key cache ..."); + if(nfc_worker->callback(NfcWorkerEventReadMfClassicLoadKeyCache, nfc_worker->context)) { + FURI_LOG_I(TAG, "Load keys cache success. Start reading"); + uint8_t sectors_read = + mf_classic_update_card(tx_rx, &nfc_worker->dev_data->mf_classic_data); + uint8_t sectors_total = + mf_classic_get_total_sectors_num(nfc_worker->dev_data->mf_classic_data.type); + FURI_LOG_I(TAG, "Read %d sectors out of %d total", sectors_read, sectors_total); + read_success = (sectors_read == sectors_total); + } + } while(false); + + return read_success; +} + +static bool nfc_worker_read_mf_desfire(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + bool read_success = false; + MifareDesfireData* data = &nfc_worker->dev_data->mf_df_data; + + nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + do { + if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break; + if(!mf_df_read_card(tx_rx, data)) break; + read_success = true; + } while(false); + + return read_success; +} + +static bool nfc_worker_read_bank_card(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + bool read_success = false; + EmvApplication emv_app = {}; + EmvData* result = &nfc_worker->dev_data->emv_data; + + nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false); + do { + // Read card + if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break; + if(!emv_read_bank_card(tx_rx, &emv_app)) break; + // Copy data + // TODO Set EmvData to reader or like in mifare ultralight! + result->number_len = emv_app.card_number_len; + memcpy(result->number, emv_app.card_number, result->number_len); + result->aid_len = emv_app.aid_len; + memcpy(result->aid, emv_app.aid, result->aid_len); + if(emv_app.name_found) { + memcpy(result->name, emv_app.name, sizeof(emv_app.name)); + } + if(emv_app.exp_month) { + result->exp_mon = emv_app.exp_month; + result->exp_year = emv_app.exp_year; + } + if(emv_app.country_code) { + result->country_code = emv_app.country_code; + } + if(emv_app.currency_code) { + result->currency_code = emv_app.currency_code; + } + read_success = true; + } while(false); + + return read_success; +} + +static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + + bool card_read = false; + furi_hal_nfc_sleep(); + if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { + FURI_LOG_I(TAG, "Mifare Ultralight / NTAG detected"); + nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareUl; + card_read = nfc_worker_read_mf_ultralight(nfc_worker, tx_rx); + } else if(mf_classic_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { + FURI_LOG_I(TAG, "Mifare Classic detected"); + nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic; + nfc_worker->dev_data->mf_classic_data.type = + mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + card_read = nfc_worker_read_mf_classic(nfc_worker, tx_rx); + } else if(mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { + FURI_LOG_I(TAG, "Mifare DESFire detected"); + nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareDesfire; + if(!nfc_worker_read_mf_desfire(nfc_worker, tx_rx)) { + FURI_LOG_I(TAG, "Unknown card. Save UID"); + nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown; + } + card_read = true; + } else if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) { + FURI_LOG_I(TAG, "ISO14443-4 card detected"); + nfc_worker->dev_data->protocol = NfcDeviceProtocolEMV; + if(!nfc_worker_read_bank_card(nfc_worker, tx_rx)) { + FURI_LOG_I(TAG, "Unknown card. Save UID"); + nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown; + } + card_read = true; + } + + return card_read; +} + +void nfc_worker_read(NfcWorker* nfc_worker) { + furi_assert(nfc_worker); + furi_assert(nfc_worker->callback); + + nfc_device_data_clear(nfc_worker->dev_data); + NfcDeviceData* dev_data = nfc_worker->dev_data; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + FuriHalNfcTxRxContext tx_rx = {}; + NfcWorkerEvent event = 0; + bool card_not_detected_notified = false; + + while(nfc_worker->state == NfcWorkerStateRead) { + if(furi_hal_nfc_detect(nfc_data, 300)) { + // Process first found device + nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); + card_not_detected_notified = false; + if(nfc_data->type == FuriHalNfcTypeA) { + if(nfc_worker_read_nfca(nfc_worker, &tx_rx)) { + if(dev_data->protocol == NfcDeviceProtocolMifareUl) { + event = NfcWorkerEventReadMfUltralight; + break; + } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { + event = NfcWorkerEventReadMfClassicDone; + break; + } else if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) { + event = NfcWorkerEventReadMfDesfire; + break; + } else if(dev_data->protocol == NfcDeviceProtocolEMV) { + event = NfcWorkerEventReadBankCard; + break; + } else if(dev_data->protocol == NfcDeviceProtocolUnknown) { + event = NfcWorkerEventReadUidNfcA; + break; + } + } else { + if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { + event = NfcWorkerEventReadMfClassicDictAttackRequired; + break; + } + } + } else if(nfc_data->type == FuriHalNfcTypeB) { + event = NfcWorkerEventReadUidNfcB; + break; + } else if(nfc_data->type == FuriHalNfcTypeF) { + event = NfcWorkerEventReadUidNfcF; + break; + } else if(nfc_data->type == FuriHalNfcTypeV) { + event = NfcWorkerEventReadUidNfcV; + break; + } + } else { + if(!card_not_detected_notified) { + nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); + card_not_detected_notified = true; + } + } + furi_hal_nfc_sleep(); + furi_delay_ms(100); + } + // Notify caller and exit + if(event > NfcWorkerEventReserved) { + nfc_worker->callback(event, nfc_worker->context); + } +} + +void nfc_worker_emulate_uid(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); + FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data; + NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data; + + while(nfc_worker->state == NfcWorkerStateUidEmulate) { + if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, true, 100)) { + if(furi_hal_nfc_tx_rx(&tx_rx, 100)) { + reader_data->size = tx_rx.rx_bits / 8; + if(reader_data->size > 0) { + memcpy(reader_data->data, tx_rx.rx_data, reader_data->size); + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); + } + } + } else { + FURI_LOG_E(TAG, "Failed to get reader commands"); + } + } + } +} + +void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); + FuriHalNfcDevData params = { + .uid = {0xCF, 0x72, 0xd4, 0x40}, + .uid_len = 4, + .atqa = {0x00, 0x04}, + .sak = 0x20, + .type = FuriHalNfcTypeA, + }; + + while(nfc_worker->state == NfcWorkerStateEmulateApdu) { + if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { + FURI_LOG_D(TAG, "POS terminal detected"); + if(emv_card_emulation(&tx_rx)) { + FURI_LOG_D(TAG, "EMV card emulated"); + } + } else { + FURI_LOG_D(TAG, "Can't find reader"); + } + furi_hal_nfc_sleep(); + furi_delay_ms(20); + } +} + +void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) { + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + MfUltralightEmulator emulator = {}; + mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data); + while(nfc_worker->state == NfcWorkerStateMfUltralightEmulate) { + mf_ul_reset_emulation(&emulator, true); + furi_hal_nfc_emulate_nfca( + nfc_data->uid, + nfc_data->uid_len, + nfc_data->atqa, + nfc_data->sak, + mf_ul_prepare_emulation_response, + &emulator, + 5000); + // Check if data was modified + if(emulator.data_changed) { + nfc_worker->dev_data->mf_ul_data = emulator.data; + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); + } + emulator.data_changed = false; + } + } +} + +void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker, MfClassicDictType type) { + furi_assert(nfc_worker); + furi_assert(nfc_worker->callback); + + MfClassicData* data = &nfc_worker->dev_data->mf_classic_data; + uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type); + uint64_t key = 0; + FuriHalNfcTxRxContext tx_rx = {}; + bool card_found_notified = true; + bool card_removed_notified = false; + + // Load dictionary + MfClassicDict* dict = mf_classic_dict_alloc(type); + if(!dict) { + FURI_LOG_E(TAG, "Dictionary not found"); + nfc_worker->callback(NfcWorkerEventNoDictFound, nfc_worker->context); + mf_classic_dict_free(dict); + return; + } + + FURI_LOG_D(TAG, "Start Dictionary attack"); + for(size_t i = 0; i < total_sectors; i++) { + FURI_LOG_I(TAG, "Sector %d", i); + nfc_worker->callback(NfcWorkerEventNewSector, nfc_worker->context); + uint8_t block_num = mf_classic_get_sector_trailer_block_num_by_sector(i); + if(mf_classic_is_sector_read(data, i)) continue; + bool is_key_a_found = mf_classic_is_key_found(data, i, MfClassicKeyA); + bool is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); + while(mf_classic_dict_get_next_key(dict, &key)) { + furi_hal_nfc_sleep(); + if(furi_hal_nfc_activate_nfca(200, NULL)) { + furi_hal_nfc_sleep(); + if(!card_found_notified) { + nfc_worker->callback(NfcWorkerEventCardDetected, 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", + i, + (uint32_t)(key >> 32), + (uint32_t)key); + if(!is_key_a_found) { + 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); + nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); + } + 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)) { + mf_classic_set_key_found(data, i, MfClassicKeyB, key); + nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); + } + } + if(is_key_a_found && is_key_b_found) break; + if(!((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) || + (nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack))) + break; + } else { + if(!card_removed_notified) { + nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); + card_removed_notified = true; + card_found_notified = false; + } + if(!((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) || + (nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack))) + break; + } + } + if(!((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) || + (nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack))) + break; + mf_classic_read_sector(&tx_rx, data, i); + mf_classic_dict_rewind(dict); + } + mf_classic_dict_free(dict); + if((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) || + (nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack)) { + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); + } else { + nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context); + } +} + +void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true); + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + MfClassicEmulator emulator = { + .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), + .data = nfc_worker->dev_data->mf_classic_data, + .data_changed = false, + }; + NfcaSignal* nfca_signal = nfca_signal_alloc(); + tx_rx.nfca_signal = nfca_signal; + + rfal_platform_spi_acquire(); + + furi_hal_nfc_listen_start(nfc_data); + while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { + if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { + mf_classic_emulator(&emulator, &tx_rx); + } + } + if(emulator.data_changed) { + nfc_worker->dev_data->mf_classic_data = emulator.data; + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); + } + emulator.data_changed = false; + } + + nfca_signal_free(nfca_signal); + + rfal_platform_spi_release(); +} diff --git a/applications/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h similarity index 59% rename from applications/nfc/nfc_worker.h rename to lib/nfc/nfc_worker.h index a68f42d7..f6df406b 100755 --- a/applications/nfc/nfc_worker.h +++ b/lib/nfc/nfc_worker.h @@ -10,17 +10,15 @@ typedef enum { NfcWorkerStateBroken, NfcWorkerStateReady, // Main worker states - NfcWorkerStateDetect, - NfcWorkerStateEmulate, - NfcWorkerStateReadEMVApp, - NfcWorkerStateReadEMVData, + NfcWorkerStateRead, + NfcWorkerStateUidEmulate, + NfcWorkerStateMfUltralightEmulate, + NfcWorkerStateMfClassicEmulate, + NfcWorkerStateMfClassicUserDictAttack, + NfcWorkerStateMfClassicFlipperDictAttack, + // Debug NfcWorkerStateEmulateApdu, NfcWorkerStateField, - NfcWorkerStateReadMifareUltralight, - NfcWorkerStateEmulateMifareUltralight, - NfcWorkerStateReadMifareClassic, - NfcWorkerStateEmulateMifareClassic, - NfcWorkerStateReadMifareDesfire, // Transition NfcWorkerStateStop, } NfcWorkerState; @@ -29,21 +27,33 @@ typedef enum { // Reserve first 50 events for application events NfcWorkerEventReserved = 50, + // Nfc read events + NfcWorkerEventReadUidNfcB, + NfcWorkerEventReadUidNfcV, + NfcWorkerEventReadUidNfcF, + NfcWorkerEventReadUidNfcA, + NfcWorkerEventReadMfUltralight, + NfcWorkerEventReadMfDesfire, + NfcWorkerEventReadMfClassicDone, + NfcWorkerEventReadMfClassicLoadKeyCache, + NfcWorkerEventReadMfClassicDictAttackRequired, + NfcWorkerEventReadBankCard, + // Nfc worker common events NfcWorkerEventSuccess, NfcWorkerEventFail, + NfcWorkerEventAborted, + NfcWorkerEventCardDetected, NfcWorkerEventNoCardDetected, + // Mifare Classic events NfcWorkerEventNoDictFound, - NfcWorkerEventDetectedClassic1k, - NfcWorkerEventDetectedClassic4k, NfcWorkerEventNewSector, NfcWorkerEventFoundKeyA, NfcWorkerEventFoundKeyB, - NfcWorkerEventStartReading, } NfcWorkerEvent; -typedef void (*NfcWorkerCallback)(NfcWorkerEvent event, void* context); +typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context); NfcWorker* nfc_worker_alloc(); diff --git a/lib/nfc/nfc_worker_i.h b/lib/nfc/nfc_worker_i.h new file mode 100644 index 00000000..f19f58d5 --- /dev/null +++ b/lib/nfc/nfc_worker_i.h @@ -0,0 +1,48 @@ +#pragma once + +#include "nfc_worker.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "helpers/mf_classic_dict.h" +#include "helpers/nfc_debug_pcap.h" + +struct NfcWorker { + FuriThread* thread; + Storage* storage; + Stream* dict_stream; + + NfcDeviceData* dev_data; + + NfcWorkerCallback callback; + void* context; + + NfcWorkerState state; + + NfcDebugPcapWorker* debug_pcap_worker; +}; + +void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state); + +int32_t nfc_worker_task(void* context); + +void nfc_worker_read(NfcWorker* nfc_worker); + +void nfc_worker_emulate_uid(NfcWorker* nfc_worker); + +void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker); + +void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker); + +void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker, MfClassicDictType type); + +void nfc_worker_emulate_apdu(NfcWorker* nfc_worker); diff --git a/lib/nfc/parsers/nfc_supported_card.c b/lib/nfc/parsers/nfc_supported_card.c new file mode 100644 index 00000000..44eee838 --- /dev/null +++ b/lib/nfc/parsers/nfc_supported_card.c @@ -0,0 +1,12 @@ +#include "nfc_supported_card.h" + +#include "troyka_parser.h" + +NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { + [NfcSupportedCardTypeTroyka] = { + .protocol = NfcDeviceProtocolMifareClassic, + .verify = troyka_parser_verify, + .read = troyka_parser_read, + .parse = troyka_parser_parse, + }, +}; diff --git a/lib/nfc/parsers/nfc_supported_card.h b/lib/nfc/parsers/nfc_supported_card.h new file mode 100644 index 00000000..5c94c78c --- /dev/null +++ b/lib/nfc/parsers/nfc_supported_card.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include "../nfc_worker.h" + +#include + +typedef enum { + NfcSupportedCardTypeTroyka, + + NfcSupportedCardTypeEnd, +} NfcSupportedCardType; + +typedef bool (*NfcSupportedCardVerify)(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +typedef bool (*NfcSupportedCardRead)(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +typedef bool (*NfcSupportedCardParse)(NfcWorker* nfc_worker); + +typedef struct { + NfcProtocol protocol; + NfcSupportedCardVerify verify; + NfcSupportedCardRead read; + NfcSupportedCardParse parse; +} NfcSupportedCard; + +extern NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd]; diff --git a/lib/nfc/parsers/troyka_parser.c b/lib/nfc/parsers/troyka_parser.c new file mode 100644 index 00000000..653887cb --- /dev/null +++ b/lib/nfc/parsers/troyka_parser.c @@ -0,0 +1,70 @@ +#include "nfc_supported_card.h" + +#include +#include + +static const MfClassicAuthContext troyka_keys[] = { + {.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58}, + {.sector = 1, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880}, + {.sector = 2, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 3, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 4, .key_a = 0x73068f118c13, .key_b = 0x2b7f3253fac5}, + {.sector = 5, .key_a = 0xfbc2793d540b, .key_b = 0xd3a297dc2698}, + {.sector = 6, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, + {.sector = 7, .key_a = 0xae3d65a3dad4, .key_b = 0x0f1c63013dba}, + {.sector = 8, .key_a = 0xa73f5dc1d333, .key_b = 0xe35173494a81}, + {.sector = 9, .key_a = 0x69a32f1c2f19, .key_b = 0x6b8bd9860763}, + {.sector = 10, .key_a = 0x9becdf3d9273, .key_b = 0xf8493407799d}, + {.sector = 11, .key_a = 0x08b386463229, .key_b = 0x5efbaecef46b}, + {.sector = 12, .key_a = 0xcd4c61c26e3d, .key_b = 0x31c7610de3b0}, + {.sector = 13, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880}, + {.sector = 14, .key_a = 0x0e8f64340ba4, .key_b = 0x4acec1205d75}, + {.sector = 15, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, +}; + +bool troyka_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + UNUSED(nfc_worker); + + MfClassicAuthContext auth_ctx = { + .key_a = MF_CLASSIC_NO_KEY, + .key_b = MF_CLASSIC_NO_KEY, + .sector = 8, + }; + return mf_classic_auth_attempt(tx_rx, &auth_ctx, 0xa73f5dc1d333); +} + +bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + + MfClassicReader reader = {}; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + mf_classic_get_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak, &reader); + for(size_t i = 0; i < COUNT_OF(troyka_keys); i++) { + mf_classic_reader_add_sector( + &reader, troyka_keys[i].sector, troyka_keys[i].key_a, troyka_keys[i].key_b); + } + + return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; +} + +bool troyka_parser_parse(NfcWorker* nfc_worker) { + MfClassicData* data = &nfc_worker->dev_data->mf_classic_data; + uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5]; + uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25; + temp_ptr = &data->block[8 * 4].value[3]; + uint32_t number = 0; + for(size_t i = 0; i < 4; i++) { + number <<= 8; + number |= temp_ptr[i]; + } + number >>= 4; + + string_printf( + nfc_worker->dev_data->parsed_data, + "Troyka Transport card\nNumber: %ld\nBalance: %d rub", + number, + balance); + + return true; +} diff --git a/lib/nfc/parsers/troyka_parser.h b/lib/nfc/parsers/troyka_parser.h new file mode 100644 index 00000000..0d5cee23 --- /dev/null +++ b/lib/nfc/parsers/troyka_parser.h @@ -0,0 +1,9 @@ +#pragma once + +#include "nfc_supported_card.h" + +bool troyka_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); + +bool troyka_parser_parse(NfcWorker* nfc_worker); diff --git a/lib/nfc_protocols/crypto1.c b/lib/nfc/protocols/crypto1.c similarity index 100% rename from lib/nfc_protocols/crypto1.c rename to lib/nfc/protocols/crypto1.c diff --git a/lib/nfc_protocols/crypto1.h b/lib/nfc/protocols/crypto1.h similarity index 100% rename from lib/nfc_protocols/crypto1.h rename to lib/nfc/protocols/crypto1.h diff --git a/lib/nfc_protocols/emv.c b/lib/nfc/protocols/emv.c similarity index 100% rename from lib/nfc_protocols/emv.c rename to lib/nfc/protocols/emv.c diff --git a/lib/nfc_protocols/emv.h b/lib/nfc/protocols/emv.h similarity index 100% rename from lib/nfc_protocols/emv.h rename to lib/nfc/protocols/emv.h diff --git a/lib/nfc_protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c similarity index 71% rename from lib/nfc_protocols/mifare_classic.c rename to lib/nfc/protocols/mifare_classic.c index e35a1d6c..93fe6f69 100644 --- a/lib/nfc_protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -25,6 +25,16 @@ typedef enum { MfClassicActionACWrite, } MfClassicAction; +const char* mf_classic_get_type_str(MfClassicType type) { + if(type == MfClassicType1k) { + return "MIFARE Classic 1K"; + } else if(type == MfClassicType4k) { + return "MIFARE Classic 4K"; + } else { + return "Unknown"; + } +} + static uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector) { furi_assert(sector < 40); if(sector < 32) { @@ -34,7 +44,16 @@ static uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector) { } } -static uint8_t mf_classic_get_sector_by_block(uint8_t block) { +uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector) { + furi_assert(sector < 40); + if(sector < 32) { + return sector * 4 + 3; + } else { + return 32 * 4 + (sector - 32) * 16 + 15; + } +} + +uint8_t mf_classic_get_sector_by_block(uint8_t block) { if(block < 128) { return (block | 0x03) / 4; } else { @@ -47,7 +66,7 @@ static uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector) { return sector < 32 ? 4 : 16; } -static uint8_t mf_classic_get_sector_trailer(uint8_t block) { +uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block) { if(block < 128) { return block | 0x03; } else { @@ -55,15 +74,21 @@ static uint8_t mf_classic_get_sector_trailer(uint8_t block) { } } -static bool mf_classic_is_sector_trailer(uint8_t block) { - return block == mf_classic_get_sector_trailer(block); +bool mf_classic_is_sector_trailer(uint8_t block) { + return block == mf_classic_get_sector_trailer_num_by_block(block); } -uint8_t mf_classic_get_total_sectors_num(MfClassicReader* reader) { - furi_assert(reader); - if(reader->type == MfClassicType1k) { +MfClassicSectorTrailer* + mf_classic_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector) { + furi_assert(data); + uint8_t sec_tr_block_num = mf_classic_get_sector_trailer_block_num_by_sector(sector); + return (MfClassicSectorTrailer*)data->block[sec_tr_block_num].value; +} + +uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { + if(type == MfClassicType1k) { return MF_CLASSIC_1K_TOTAL_SECTORS_NUM; - } else if(reader->type == MfClassicType4k) { + } else if(type == MfClassicType4k) { return MF_CLASSIC_4K_TOTAL_SECTORS_NUM; } else { return 0; @@ -80,6 +105,104 @@ static uint16_t mf_classic_get_total_block_num(MfClassicType type) { } } +bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num) { + furi_assert(data); + + return (FURI_BIT(data->block_read_mask[block_num / 32], block_num % 32) == 1); +} + +void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data) { + furi_assert(data); + + if(mf_classic_is_sector_trailer(block_num)) { + memcpy(&data->block[block_num].value[6], &block_data->value[6], 4); + } else { + memcpy(data->block[block_num].value, block_data->value, MF_CLASSIC_BLOCK_SIZE); + } + FURI_BIT_SET(data->block_read_mask[block_num / 32], block_num % 32); +} + +bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { + furi_assert(data); + + bool key_found = false; + if(key_type == MfClassicKeyA) { + key_found = (FURI_BIT(data->key_a_mask, sector_num) == 1); + } else if(key_type == MfClassicKeyB) { + key_found = (FURI_BIT(data->key_b_mask, sector_num) == 1); + } + + return key_found; +} + +void mf_classic_set_key_found( + MfClassicData* data, + uint8_t sector_num, + MfClassicKey key_type, + uint64_t key) { + furi_assert(data); + + uint8_t key_arr[6] = {}; + MfClassicSectorTrailer* sec_trailer = + mf_classic_get_sector_trailer_by_sector(data, sector_num); + nfc_util_num2bytes(key, 6, key_arr); + if(key_type == MfClassicKeyA) { + memcpy(sec_trailer->key_a, key_arr, sizeof(sec_trailer->key_a)); + FURI_BIT_SET(data->key_a_mask, sector_num); + } else if(key_type == MfClassicKeyB) { + memcpy(sec_trailer->key_b, key_arr, sizeof(sec_trailer->key_b)); + FURI_BIT_SET(data->key_b_mask, sector_num); + } +} + +bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num) { + furi_assert(data); + + bool sector_read = false; + do { + if(!mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) break; + if(!mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) break; + uint8_t start_block = mf_classic_get_first_block_num_of_sector(sector_num); + uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sector_num); + uint8_t block_read = true; + for(size_t i = start_block; i < start_block + total_blocks; i++) { + block_read = mf_classic_is_block_read(data, i); + if(!block_read) break; + } + sector_read = block_read; + } while(false); + + return sector_read; +} + +void mf_classic_get_read_sectors_and_keys( + MfClassicData* data, + uint8_t* sectors_read, + uint8_t* keys_found) { + furi_assert(data); + *sectors_read = 0; + *keys_found = 0; + uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); + for(size_t i = 0; i < sectors_total; i++) { + if(mf_classic_is_key_found(data, i, MfClassicKeyA)) { + *keys_found += 1; + } + if(mf_classic_is_key_found(data, i, MfClassicKeyB)) { + *keys_found += 1; + } + uint8_t first_block = mf_classic_get_first_block_num_of_sector(i); + uint8_t total_blocks_in_sec = mf_classic_get_blocks_num_in_sector(i); + bool blocks_read = true; + for(size_t i = first_block; i < first_block + total_blocks_in_sec; i++) { + blocks_read = mf_classic_is_block_read(data, i); + if(!blocks_read) break; + } + if(blocks_read) { + *sectors_read += 1; + } + } +} + static bool mf_classic_is_allowed_access_sector_trailer( MfClassicEmulator* emulator, uint8_t block_num, @@ -126,7 +249,8 @@ static bool mf_classic_is_allowed_access_data_block( uint8_t block_num, MfClassicKey key, MfClassicAction action) { - uint8_t* sector_trailer = emulator->data.block[mf_classic_get_sector_trailer(block_num)].value; + uint8_t* sector_trailer = + emulator->data.block[mf_classic_get_sector_trailer_num_by_block(block_num)].value; uint8_t sector_block; if(block_num <= 128) { @@ -207,15 +331,18 @@ bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { } } -bool mf_classic_get_type( - uint8_t* uid, - uint8_t uid_len, - uint8_t ATQA0, - uint8_t ATQA1, - uint8_t SAK, - MfClassicReader* reader) { +MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { + UNUSED(ATQA1); + if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) { + return MfClassicType1k; + } else if((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18)) { + return MfClassicType4k; + } + return MfClassicType1k; +} + +bool mf_classic_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK, MfClassicReader* reader) { UNUSED(ATQA1); - furi_assert(uid); furi_assert(reader); memset(reader, 0, sizeof(MfClassicReader)); @@ -226,14 +353,6 @@ bool mf_classic_get_type( } else { return false; } - - uint8_t* cuid_start = uid; - if(uid_len == 7) { - cuid_start = &uid[3]; - } - reader->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | - (cuid_start[3]); - return true; } @@ -246,7 +365,7 @@ void mf_classic_reader_add_sector( furi_assert(sector < MF_CLASSIC_SECTORS_MAX); furi_assert((key_a != MF_CLASSIC_NO_KEY) || (key_b != MF_CLASSIC_NO_KEY)); - if(reader->sectors_to_read < MF_CLASSIC_SECTORS_MAX - 1) { + if(reader->sectors_to_read < MF_CLASSIC_SECTORS_MAX) { reader->sector_reader[reader->sectors_to_read].key_a = key_a; reader->sector_reader[reader->sectors_to_read].key_b = key_b; reader->sector_reader[reader->sectors_to_read].sector_num = sector; @@ -254,9 +373,8 @@ void mf_classic_reader_add_sector( } } -void mf_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint32_t cuid, uint8_t sector) { +void mf_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint8_t sector) { furi_assert(auth_ctx); - auth_ctx->cuid = cuid; auth_ctx->sector = sector; auth_ctx->key_a = MF_CLASSIC_NO_KEY; auth_ctx->key_b = MF_CLASSIC_NO_KEY; @@ -264,17 +382,18 @@ void mf_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint32_t cuid, static bool mf_classic_auth( FuriHalNfcTxRxContext* tx_rx, - uint32_t cuid, uint32_t block, uint64_t key, MfClassicKey key_type, Crypto1* crypto) { bool auth_success = false; + uint32_t cuid = 0; memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data)); memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity)); tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; do { + if(!furi_hal_nfc_activate_nfca(200, &cuid)) break; if(key_type == MfClassicKeyA) { tx_rx->tx_data[0] = MF_CLASSIC_AUTH_KEY_A_CMD; } else { @@ -315,6 +434,19 @@ static bool mf_classic_auth( return auth_success; } +bool mf_classic_authenticate( + FuriHalNfcTxRxContext* tx_rx, + uint8_t block_num, + uint64_t key, + MfClassicKey key_type) { + furi_assert(tx_rx); + + Crypto1 crypto = {}; + bool key_found = mf_classic_auth(tx_rx, block_num, key, key_type, &crypto); + furi_hal_nfc_sleep(); + return key_found; +} + bool mf_classic_auth_attempt( FuriHalNfcTxRxContext* tx_rx, MfClassicAuthContext* auth_ctx, @@ -330,7 +462,6 @@ bool mf_classic_auth_attempt( // Try AUTH with key A if(mf_classic_auth( tx_rx, - auth_ctx->cuid, mf_classic_get_first_block_num_of_sector(auth_ctx->sector), key, MfClassicKeyA, @@ -342,14 +473,12 @@ bool mf_classic_auth_attempt( if(need_halt) { furi_hal_nfc_sleep(); - furi_hal_nfc_activate_nfca(300, &auth_ctx->cuid); } if(auth_ctx->key_b == MF_CLASSIC_NO_KEY) { // Try AUTH with key B if(mf_classic_auth( tx_rx, - auth_ctx->cuid, mf_classic_get_first_block_num_of_sector(auth_ctx->sector), key, MfClassicKeyB, @@ -410,7 +539,60 @@ bool mf_classic_read_block( return read_block_success; } -bool mf_classic_read_sector( +void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, uint8_t sec_num) { + furi_assert(tx_rx); + furi_assert(data); + + furi_hal_nfc_sleep(); + bool key_a_found = mf_classic_is_key_found(data, sec_num, MfClassicKeyA); + bool key_b_found = mf_classic_is_key_found(data, sec_num, MfClassicKeyB); + uint8_t start_block = mf_classic_get_first_block_num_of_sector(sec_num); + uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sec_num); + MfClassicBlock block_tmp = {}; + uint64_t key = 0; + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sec_num); + Crypto1 crypto = {}; + + uint8_t blocks_read = 0; + do { + if(!key_a_found) break; + FURI_LOG_D(TAG, "Try to read blocks with key A"); + key = nfc_util_bytes2num(sec_tr->key_a, sizeof(sec_tr->key_a)); + if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyA, &crypto)) break; + for(size_t i = start_block; i < start_block + total_blocks; i++) { + if(!mf_classic_is_block_read(data, i)) { + if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { + mf_classic_set_block_read(data, i, &block_tmp); + blocks_read++; + } + } else { + blocks_read++; + } + } + FURI_LOG_D(TAG, "Read %d blocks out of %d", blocks_read, total_blocks); + } while(false); + do { + if(blocks_read == total_blocks) break; + if(!key_b_found) break; + FURI_LOG_D(TAG, "Try to read blocks with key B"); + key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b)); + furi_hal_nfc_sleep(); + if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto)) break; + for(size_t i = start_block; i < start_block + total_blocks; i++) { + if(!mf_classic_is_block_read(data, i)) { + if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { + mf_classic_set_block_read(data, i, &block_tmp); + blocks_read++; + } + } else { + blocks_read++; + } + } + FURI_LOG_D(TAG, "Read %d blocks out of %d", blocks_read, total_blocks); + } while(false); +} + +static bool mf_classic_read_sector_with_reader( FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, MfClassicSectorReader* sector_reader, @@ -419,7 +601,6 @@ bool mf_classic_read_sector( furi_assert(sector_reader); furi_assert(sector); - uint32_t cuid = 0; uint64_t key; MfClassicKey key_type; uint8_t first_block; @@ -428,7 +609,6 @@ bool mf_classic_read_sector( furi_hal_nfc_sleep(); do { // Activate card - if(!furi_hal_nfc_activate_nfca(200, &cuid)) break; first_block = mf_classic_get_first_block_num_of_sector(sector_reader->sector_num); if(sector_reader->key_a != MF_CLASSIC_NO_KEY) { key = sector_reader->key_a; @@ -441,7 +621,7 @@ bool mf_classic_read_sector( } // Auth to first block in sector - if(!mf_classic_auth(tx_rx, cuid, first_block, key, key_type, crypto)) break; + if(!mf_classic_auth(tx_rx, first_block, key, key_type, crypto)) break; sector->total_blocks = mf_classic_get_blocks_num_in_sector(sector_reader->sector_num); // Read blocks @@ -478,18 +658,26 @@ uint8_t mf_classic_read_card( data->key_b_mask = 0; MfClassicSector temp_sector = {}; for(uint8_t i = 0; i < reader->sectors_to_read; i++) { - if(mf_classic_read_sector( + if(mf_classic_read_sector_with_reader( tx_rx, &reader->crypto, &reader->sector_reader[i], &temp_sector)) { uint8_t first_block = mf_classic_get_first_block_num_of_sector(reader->sector_reader[i].sector_num); for(uint8_t j = 0; j < temp_sector.total_blocks; j++) { - data->block[first_block + j] = temp_sector.block[j]; + mf_classic_set_block_read(data, first_block + j, &temp_sector.block[j]); } if(reader->sector_reader[i].key_a != MF_CLASSIC_NO_KEY) { - data->key_a_mask |= 1 << reader->sector_reader[i].sector_num; + mf_classic_set_key_found( + data, + reader->sector_reader[i].sector_num, + MfClassicKeyA, + reader->sector_reader[i].key_a); } if(reader->sector_reader[i].key_b != MF_CLASSIC_NO_KEY) { - data->key_b_mask |= 1 << reader->sector_reader[i].sector_num; + mf_classic_set_key_found( + data, + reader->sector_reader[i].sector_num, + MfClassicKeyB, + reader->sector_reader[i].key_b); } sectors_read++; } @@ -498,6 +686,46 @@ uint8_t mf_classic_read_card( return sectors_read; } +uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data) { + furi_assert(tx_rx); + furi_assert(data); + + uint8_t sectors_read = 0; + Crypto1 crypto = {}; + uint8_t total_sectors = mf_classic_get_total_sectors_num(data->type); + uint64_t key_a = 0; + uint64_t key_b = 0; + MfClassicSectorReader sec_reader = {}; + MfClassicSector temp_sector = {}; + + for(size_t i = 0; i < total_sectors; i++) { + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i); + // Load key A + if(mf_classic_is_key_found(data, i, MfClassicKeyA)) { + sec_reader.key_a = nfc_util_bytes2num(sec_tr->key_a, 6); + } else { + sec_reader.key_a = MF_CLASSIC_NO_KEY; + } + // Load key B + if(mf_classic_is_key_found(data, i, MfClassicKeyB)) { + sec_reader.key_b = nfc_util_bytes2num(sec_tr->key_b, 6); + } else { + sec_reader.key_b = MF_CLASSIC_NO_KEY; + } + if((key_a != MF_CLASSIC_NO_KEY) || (key_b != MF_CLASSIC_NO_KEY)) { + sec_reader.sector_num = i; + if(mf_classic_read_sector_with_reader(tx_rx, &crypto, &sec_reader, &temp_sector)) { + uint8_t first_block = mf_classic_get_first_block_num_of_sector(i); + for(uint8_t j = 0; j < temp_sector.total_blocks; j++) { + mf_classic_set_block_read(data, first_block + j, &temp_sector.block[j]); + } + sectors_read++; + } + } + } + return sectors_read; +} + void mf_crypto1_decrypt( Crypto1* crypto, uint8_t* encrypted_data, @@ -573,7 +801,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ } else if(plain_data[0] == 0x60 || plain_data[0] == 0x61) { uint8_t block = plain_data[1]; uint64_t key = 0; - uint8_t sector_trailer_block = mf_classic_get_sector_trailer(block); + uint8_t sector_trailer_block = mf_classic_get_sector_trailer_num_by_block(block); MfClassicSectorTrailer* sector_trailer = (MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value; if(plain_data[0] == 0x60) { @@ -635,21 +863,6 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ nr, ar); - // Check if we store valid key - if(access_key == MfClassicKeyA) { - if(FURI_BIT(emulator->data.key_a_mask, mf_classic_get_sector_by_block(block)) == - 0) { - FURI_LOG_D(TAG, "Unsupported sector key A for block %d", sector_trailer_block); - break; - } - } else if(access_key == MfClassicKeyB) { - if(FURI_BIT(emulator->data.key_b_mask, mf_classic_get_sector_by_block(block)) == - 0) { - FURI_LOG_D(TAG, "Unsupported sector key B for block %d", sector_trailer_block); - break; - } - } - crypto1_word(&emulator->crypto, nr, 1); uint32_t cardRr = ar ^ crypto1_word(&emulator->crypto, 0, 0); if(cardRr != prng_successor(nonce, 64)) { diff --git a/lib/nfc_protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h similarity index 54% rename from lib/nfc_protocols/mifare_classic.h rename to lib/nfc/protocols/mifare_classic.h index bbf34b2d..85f67b11 100644 --- a/lib/nfc_protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -14,6 +14,8 @@ #define MF_CLASSIC_NO_KEY (0xFFFFFFFFFFFFFFFF) #define MF_CLASSIC_MAX_DATA_SIZE (16) +#define MF_CLASSIC_KEY_SIZE (6) +#define MF_CLASSIC_ACCESS_BYTES_SIZE (4) typedef enum { MfClassicType1k, @@ -30,9 +32,9 @@ typedef struct { } MfClassicBlock; typedef struct { - uint8_t key_a[6]; - uint8_t access_bits[4]; - uint8_t key_b[6]; + uint8_t key_a[MF_CLASSIC_KEY_SIZE]; + uint8_t access_bits[MF_CLASSIC_ACCESS_BYTES_SIZE]; + uint8_t key_b[MF_CLASSIC_KEY_SIZE]; } MfClassicSectorTrailer; typedef struct { @@ -42,13 +44,13 @@ typedef struct { typedef struct { MfClassicType type; + uint32_t block_read_mask[MF_CLASSIC_TOTAL_BLOCKS_MAX / 32]; uint64_t key_a_mask; uint64_t key_b_mask; MfClassicBlock block[MF_CLASSIC_TOTAL_BLOCKS_MAX]; } MfClassicData; typedef struct { - uint32_t cuid; uint8_t sector; uint64_t key_a; uint64_t key_b; @@ -62,9 +64,8 @@ typedef struct { typedef struct { MfClassicType type; - uint32_t cuid; - uint8_t sectors_to_read; Crypto1 crypto; + uint8_t sectors_to_read; MfClassicSectorReader sector_reader[MF_CLASSIC_SECTORS_MAX]; } MfClassicReader; @@ -75,19 +76,51 @@ typedef struct { bool data_changed; } MfClassicEmulator; +const char* mf_classic_get_type_str(MfClassicType type); + bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); -bool mf_classic_get_type( - uint8_t* uid, - uint8_t uid_len, - uint8_t ATQA0, - uint8_t ATQA1, - uint8_t SAK, - MfClassicReader* reader); +MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t SAK); -uint8_t mf_classic_get_total_sectors_num(MfClassicReader* reader); +bool mf_classic_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK, MfClassicReader* reader); -void mf_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint32_t cuid, uint8_t sector); +uint8_t mf_classic_get_total_sectors_num(MfClassicType type); + +uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector); + +bool mf_classic_is_sector_trailer(uint8_t block); + +uint8_t mf_classic_get_sector_by_block(uint8_t block); + +bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); + +void mf_classic_set_key_found( + MfClassicData* data, + uint8_t sector_num, + MfClassicKey key_type, + uint64_t key); + +bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num); + +void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); + +bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num); + +void mf_classic_get_read_sectors_and_keys( + MfClassicData* data, + uint8_t* sectors_read, + uint8_t* keys_found); + +MfClassicSectorTrailer* + mf_classic_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector); + +void mf_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint8_t sector); + +bool mf_classic_authenticate( + FuriHalNfcTxRxContext* tx_rx, + uint8_t block_num, + uint64_t key, + MfClassicKey key_type); bool mf_classic_auth_attempt( FuriHalNfcTxRxContext* tx_rx, @@ -100,15 +133,13 @@ void mf_classic_reader_add_sector( uint64_t key_a, uint64_t key_b); -bool mf_classic_read_sector( - FuriHalNfcTxRxContext* tx_rx, - Crypto1* crypto, - MfClassicSectorReader* sector_reader, - MfClassicSector* sector); +void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, uint8_t sec_num); uint8_t mf_classic_read_card( FuriHalNfcTxRxContext* tx_rx, MfClassicReader* reader, MfClassicData* data); +uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data); + bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx); diff --git a/lib/nfc_protocols/mifare_common.c b/lib/nfc/protocols/mifare_common.c similarity index 100% rename from lib/nfc_protocols/mifare_common.c rename to lib/nfc/protocols/mifare_common.c diff --git a/lib/nfc_protocols/mifare_common.h b/lib/nfc/protocols/mifare_common.h similarity index 100% rename from lib/nfc_protocols/mifare_common.h rename to lib/nfc/protocols/mifare_common.h diff --git a/lib/nfc_protocols/mifare_desfire.c b/lib/nfc/protocols/mifare_desfire.c similarity index 62% rename from lib/nfc_protocols/mifare_desfire.c rename to lib/nfc/protocols/mifare_desfire.c index 6f28dc5d..1822d5c1 100644 --- a/lib/nfc_protocols/mifare_desfire.c +++ b/lib/nfc/protocols/mifare_desfire.c @@ -2,6 +2,8 @@ #include #include +#define TAG "MifareDESFire" + void mf_df_clear(MifareDesfireData* data) { free(data->free_memory); if(data->master_key_settings) { @@ -449,3 +451,173 @@ bool mf_df_parse_read_data_response(uint8_t* buf, uint16_t len, MifareDesfireFil memcpy(out->contents, buf, len); return true; } + +bool mf_df_read_card(FuriHalNfcTxRxContext* tx_rx, MifareDesfireData* data) { + furi_assert(tx_rx); + furi_assert(data); + + bool card_read = false; + do { + // Get version + tx_rx->tx_bits = 8 * mf_df_prepare_get_version(tx_rx->tx_data); + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting version"); + break; + } + if(!mf_df_parse_get_version_response(tx_rx->rx_data, tx_rx->rx_bits / 8, &data->version)) { + FURI_LOG_W(TAG, "Bad DESFire GET_VERSION responce"); + } + + // Get free memory + tx_rx->tx_bits = 8 * mf_df_prepare_get_free_memory(tx_rx->tx_data); + if(furi_hal_nfc_tx_rx_full(tx_rx)) { + data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); + if(!mf_df_parse_get_free_memory_response( + tx_rx->rx_data, tx_rx->rx_bits / 8, data->free_memory)) { + FURI_LOG_D(TAG, "Bad DESFire GET_FREE_MEMORY response (normal for pre-EV1 cards)"); + free(data->free_memory); + data->free_memory = NULL; + } + } + + // Get key settings + tx_rx->tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx->tx_data); + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_D(TAG, "Bad exchange getting key settings"); + } else { + data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); + if(!mf_df_parse_get_key_settings_response( + tx_rx->rx_data, tx_rx->rx_bits / 8, data->master_key_settings)) { + FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); + free(data->master_key_settings); + data->master_key_settings = NULL; + } else { + MifareDesfireKeyVersion** key_version_head = + &data->master_key_settings->key_version_head; + for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { + tx_rx->tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx->tx_data, key_id); + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting key version"); + continue; + } + MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); + memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); + key_version->id = key_id; + if(!mf_df_parse_get_key_version_response( + tx_rx->rx_data, tx_rx->rx_bits / 8, key_version)) { + FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); + free(key_version); + continue; + } + *key_version_head = key_version; + key_version_head = &key_version->next; + } + } + } + + // Get application IDs + tx_rx->tx_bits = 8 * mf_df_prepare_get_application_ids(tx_rx->tx_data); + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting application IDs"); + break; + } else { + if(!mf_df_parse_get_application_ids_response( + tx_rx->rx_data, tx_rx->rx_bits / 8, &data->app_head)) { + FURI_LOG_W(TAG, "Bad DESFire GET_APPLICATION_IDS response"); + break; + } + } + + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + tx_rx->tx_bits = 8 * mf_df_prepare_select_application(tx_rx->tx_data, app->id); + if(!furi_hal_nfc_tx_rx_full(tx_rx) || + !mf_df_parse_select_application_response(tx_rx->rx_data, tx_rx->rx_bits / 8)) { + FURI_LOG_W(TAG, "Bad exchange selecting application"); + continue; + } + tx_rx->tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx->tx_data); + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting key settings"); + } else { + app->key_settings = malloc(sizeof(MifareDesfireKeySettings)); + memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings)); + if(!mf_df_parse_get_key_settings_response( + tx_rx->rx_data, tx_rx->rx_bits / 8, app->key_settings)) { + FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); + free(app->key_settings); + app->key_settings = NULL; + continue; + } + + MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head; + for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) { + tx_rx->tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx->tx_data, key_id); + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting key version"); + continue; + } + MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); + memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); + key_version->id = key_id; + if(!mf_df_parse_get_key_version_response( + tx_rx->rx_data, tx_rx->rx_bits / 8, key_version)) { + FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); + free(key_version); + continue; + } + *key_version_head = key_version; + key_version_head = &key_version->next; + } + } + + tx_rx->tx_bits = 8 * mf_df_prepare_get_file_ids(tx_rx->tx_data); + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting file IDs"); + } else { + if(!mf_df_parse_get_file_ids_response( + tx_rx->rx_data, tx_rx->rx_bits / 8, &app->file_head)) { + FURI_LOG_W(TAG, "Bad DESFire GET_FILE_IDS response"); + } + } + + for(MifareDesfireFile* file = app->file_head; file; file = file->next) { + tx_rx->tx_bits = 8 * mf_df_prepare_get_file_settings(tx_rx->tx_data, file->id); + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting file settings"); + continue; + } + if(!mf_df_parse_get_file_settings_response( + tx_rx->rx_data, tx_rx->rx_bits / 8, file)) { + FURI_LOG_W(TAG, "Bad DESFire GET_FILE_SETTINGS response"); + continue; + } + switch(file->type) { + case MifareDesfireFileTypeStandard: + case MifareDesfireFileTypeBackup: + tx_rx->tx_bits = 8 * mf_df_prepare_read_data(tx_rx->tx_data, file->id, 0, 0); + break; + case MifareDesfireFileTypeValue: + tx_rx->tx_bits = 8 * mf_df_prepare_get_value(tx_rx->tx_data, file->id); + break; + case MifareDesfireFileTypeLinearRecord: + case MifareDesfireFileTypeCyclicRecord: + tx_rx->tx_bits = + 8 * mf_df_prepare_read_records(tx_rx->tx_data, file->id, 0, 0); + break; + } + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange reading file %d", file->id); + continue; + } + if(!mf_df_parse_read_data_response(tx_rx->rx_data, tx_rx->rx_bits / 8, file)) { + FURI_LOG_W(TAG, "Bad response reading file %d", file->id); + continue; + } + } + } + + card_read = true; + } while(false); + + return card_read; +} diff --git a/lib/nfc_protocols/mifare_desfire.h b/lib/nfc/protocols/mifare_desfire.h similarity index 98% rename from lib/nfc_protocols/mifare_desfire.h rename to lib/nfc/protocols/mifare_desfire.h index dbe0802e..e59743a2 100644 --- a/lib/nfc_protocols/mifare_desfire.h +++ b/lib/nfc/protocols/mifare_desfire.h @@ -4,6 +4,8 @@ #include #include +#include + #define MF_DF_GET_VERSION (0x60) #define MF_DF_GET_FREE_MEMORY (0x6E) #define MF_DF_GET_KEY_SETTINGS (0x45) @@ -163,3 +165,5 @@ uint16_t mf_df_prepare_read_data(uint8_t* dest, uint8_t file_id, uint32_t offset uint16_t mf_df_prepare_get_value(uint8_t* dest, uint8_t file_id); uint16_t mf_df_prepare_read_records(uint8_t* dest, uint8_t file_id, uint32_t offset, uint32_t len); bool mf_df_parse_read_data_response(uint8_t* buf, uint16_t len, MifareDesfireFile* out); + +bool mf_df_read_card(FuriHalNfcTxRxContext* tx_rx, MifareDesfireData* data); diff --git a/lib/nfc_protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c similarity index 100% rename from lib/nfc_protocols/mifare_ultralight.c rename to lib/nfc/protocols/mifare_ultralight.c diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc/protocols/mifare_ultralight.h similarity index 100% rename from lib/nfc_protocols/mifare_ultralight.h rename to lib/nfc/protocols/mifare_ultralight.h diff --git a/lib/nfc_protocols/nfc_util.c b/lib/nfc/protocols/nfc_util.c similarity index 100% rename from lib/nfc_protocols/nfc_util.c rename to lib/nfc/protocols/nfc_util.c diff --git a/lib/nfc_protocols/nfc_util.h b/lib/nfc/protocols/nfc_util.h similarity index 100% rename from lib/nfc_protocols/nfc_util.h rename to lib/nfc/protocols/nfc_util.h diff --git a/lib/nfc_protocols/nfca.c b/lib/nfc/protocols/nfca.c similarity index 100% rename from lib/nfc_protocols/nfca.c rename to lib/nfc/protocols/nfca.c diff --git a/lib/nfc_protocols/nfca.h b/lib/nfc/protocols/nfca.h similarity index 100% rename from lib/nfc_protocols/nfca.h rename to lib/nfc/protocols/nfca.h