Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/flipperzero-firmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgornekich <n.gorbadey@gmail.com>2022-07-26 18:30:49 +0300
committerGitHub <noreply@github.com>2022-07-26 18:30:49 +0300
commit9c59bcd7763cbe9b0132b0f2698543e2dfb11623 (patch)
tree95e88240a98270ee1960f3371c89e3a7b2341598
parentec19c11dbe4a81147947cc3a8dd2d182374ed67a (diff)
[FL-2605] NFC new design (#1364)
* 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 <astra@astrra.space> Co-authored-by: あく <alleteam@gmail.com>
-rw-r--r--.github/CODEOWNERS2
-rw-r--r--applications/nfc/helpers/nfc_custom_event.h1
-rw-r--r--applications/nfc/helpers/nfc_generators.c26
-rw-r--r--applications/nfc/helpers/nfc_mf_classic_dict.c53
-rw-r--r--applications/nfc/helpers/nfc_mf_classic_dict.h15
-rw-r--r--applications/nfc/nfc.c24
-rwxr-xr-xapplications/nfc/nfc_cli.c5
-rwxr-xr-xapplications/nfc/nfc_i.h11
-rw-r--r--applications/nfc/nfc_worker.c708
-rw-r--r--applications/nfc/nfc_worker_i.h57
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_card_menu.c90
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_config.h53
-rw-r--r--applications/nfc/scenes/nfc_scene_detect_reader.c143
-rw-r--r--applications/nfc/scenes/nfc_scene_device_info.c2
-rw-r--r--applications/nfc/scenes/nfc_scene_dict_not_found.c7
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_emulate_uid.c9
-rw-r--r--[-rwxr-xr-x]applications/nfc/scenes/nfc_scene_emv_read_success.c (renamed from applications/nfc/scenes/nfc_scene_read_emv_data_success.c)36
-rw-r--r--applications/nfc/scenes/nfc_scene_exit_confirm.c47
-rw-r--r--applications/nfc/scenes/nfc_scene_extra_actions.c48
-rw-r--r--applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c137
-rw-r--r--applications/nfc/scenes/nfc_scene_mf_classic_emulate.c (renamed from applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c)29
-rw-r--r--applications/nfc/scenes/nfc_scene_mf_classic_keys.c59
-rw-r--r--applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c57
-rw-r--r--[-rwxr-xr-x]applications/nfc/scenes/nfc_scene_mf_classic_menu.c (renamed from applications/nfc/scenes/nfc_scene_mifare_ul_menu.c)22
-rw-r--r--applications/nfc/scenes/nfc_scene_mf_classic_read_success.c104
-rw-r--r--applications/nfc/scenes/nfc_scene_mf_desfire_app.c (renamed from applications/nfc/scenes/nfc_scene_mifare_desfire_app.c)36
-rw-r--r--applications/nfc/scenes/nfc_scene_mf_desfire_data.c (renamed from applications/nfc/scenes/nfc_scene_mifare_desfire_data.c)32
-rw-r--r--applications/nfc/scenes/nfc_scene_mf_desfire_menu.c (renamed from applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c)15
-rw-r--r--applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c (renamed from applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c)45
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_mf_ultralight_emulate.c (renamed from applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c)29
-rw-r--r--applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c (renamed from applications/nfc/scenes/nfc_scene_mifare_classic_menu.c)22
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c (renamed from applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c)28
-rw-r--r--applications/nfc/scenes/nfc_scene_read.c108
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_read_card.c51
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_read_card_success.c20
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_read_emv_app.c58
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_read_emv_app_success.c83
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_read_emv_data.c59
-rw-r--r--applications/nfc/scenes/nfc_scene_read_mifare_classic.c96
-rw-r--r--applications/nfc/scenes/nfc_scene_read_mifare_desfire.c56
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_read_mifare_ul.c54
-rw-r--r--applications/nfc/scenes/nfc_scene_retry_confirm.c47
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_run_emv_app_confirm.c49
-rw-r--r--applications/nfc/scenes/nfc_scene_save_success.c8
-rw-r--r--applications/nfc/scenes/nfc_scene_saved_menu.c4
-rwxr-xr-xapplications/nfc/scenes/nfc_scene_scripts_menu.c82
-rw-r--r--applications/nfc/scenes/nfc_scene_start.c23
-rw-r--r--applications/nfc/views/dict_attack.c176
-rw-r--r--applications/nfc/views/dict_attack.h25
-rw-r--r--applications/unit_tests/nfc/nfc_test.c2
-rw-r--r--assets/icons/NFC/NFC_manual.pngbin0 -> 3785 bytes
-rw-r--r--assets/icons/NFC/Reader_detect.pngbin0 -> 3771 bytes
-rw-r--r--firmware.scons1
-rw-r--r--firmware/targets/furi_hal_include/furi_hal_nfc.h2
-rw-r--r--furi/core/common_defines.h4
-rw-r--r--lib/SConscript1
-rw-r--r--lib/misc.scons2
-rw-r--r--lib/nfc/SConscript16
-rw-r--r--lib/nfc/helpers/mf_classic_dict.c148
-rw-r--r--lib/nfc/helpers/mf_classic_dict.h28
-rw-r--r--lib/nfc/helpers/nfc_debug_pcap.c (renamed from applications/nfc/helpers/nfc_debug_pcap.c)0
-rw-r--r--lib/nfc/helpers/nfc_debug_pcap.h (renamed from applications/nfc/helpers/nfc_debug_pcap.h)0
-rw-r--r--lib/nfc/nfc_device.c (renamed from applications/nfc/nfc_device.c)273
-rw-r--r--lib/nfc/nfc_device.h (renamed from applications/nfc/nfc_device.h)11
-rw-r--r--lib/nfc/nfc_types.c (renamed from applications/nfc/nfc_types.c)0
-rw-r--r--lib/nfc/nfc_types.h (renamed from applications/nfc/nfc_types.h)0
-rw-r--r--lib/nfc/nfc_worker.c510
-rwxr-xr-xlib/nfc/nfc_worker.h (renamed from applications/nfc/nfc_worker.h)36
-rw-r--r--lib/nfc/nfc_worker_i.h48
-rw-r--r--lib/nfc/parsers/nfc_supported_card.c12
-rw-r--r--lib/nfc/parsers/nfc_supported_card.h27
-rw-r--r--lib/nfc/parsers/troyka_parser.c70
-rw-r--r--lib/nfc/parsers/troyka_parser.h9
-rw-r--r--lib/nfc/protocols/crypto1.c (renamed from lib/nfc_protocols/crypto1.c)0
-rw-r--r--lib/nfc/protocols/crypto1.h (renamed from lib/nfc_protocols/crypto1.h)0
-rw-r--r--lib/nfc/protocols/emv.c (renamed from lib/nfc_protocols/emv.c)0
-rwxr-xr-xlib/nfc/protocols/emv.h (renamed from lib/nfc_protocols/emv.h)0
-rw-r--r--lib/nfc/protocols/mifare_classic.c (renamed from lib/nfc_protocols/mifare_classic.c)325
-rw-r--r--lib/nfc/protocols/mifare_classic.h (renamed from lib/nfc_protocols/mifare_classic.h)71
-rw-r--r--lib/nfc/protocols/mifare_common.c (renamed from lib/nfc_protocols/mifare_common.c)0
-rw-r--r--lib/nfc/protocols/mifare_common.h (renamed from lib/nfc_protocols/mifare_common.h)0
-rw-r--r--lib/nfc/protocols/mifare_desfire.c (renamed from lib/nfc_protocols/mifare_desfire.c)172
-rw-r--r--lib/nfc/protocols/mifare_desfire.h (renamed from lib/nfc_protocols/mifare_desfire.h)4
-rw-r--r--lib/nfc/protocols/mifare_ultralight.c (renamed from lib/nfc_protocols/mifare_ultralight.c)0
-rw-r--r--lib/nfc/protocols/mifare_ultralight.h (renamed from lib/nfc_protocols/mifare_ultralight.h)0
-rw-r--r--lib/nfc/protocols/nfc_util.c (renamed from lib/nfc_protocols/nfc_util.c)0
-rw-r--r--lib/nfc/protocols/nfc_util.h (renamed from lib/nfc_protocols/nfc_util.h)0
-rwxr-xr-xlib/nfc/protocols/nfca.c (renamed from lib/nfc_protocols/nfca.c)0
-rw-r--r--lib/nfc/protocols/nfca.h (renamed from lib/nfc_protocols/nfca.h)0
89 files changed, 2733 insertions, 1990 deletions
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 <flipper_format/flipper_format.h>
-#include <lib/toolbox/args.h>
-
-#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 <stdbool.h>
-#include <storage/storage.h>
-#include <lib/toolbox/stream/file_stream.h>
-
-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 <furi.h>
#include <furi_hal.h>
#include <cli/cli.h>
-#include <toolbox/args.h>
+#include <lib/toolbox/args.h>
-#include "nfc_types.h"
+#include <lib/nfc/nfc_types.h>
+#include <lib/nfc/nfc_device.h>
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 <furi.h>
#include <furi_hal.h>
@@ -24,6 +21,11 @@
#include <gui/modules/text_box.h>
#include <gui/modules/widget.h>
+#include <lib/nfc/nfc_types.h>
+#include <lib/nfc/nfc_worker.h>
+#include <lib/nfc/nfc_device.h>
+#include <lib/nfc/helpers/mf_classic_dict.h>
+
#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 <furi_hal.h>
-
-#include <platform.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 == 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 <furi.h>
-#include <lib/toolbox/stream/file_stream.h>
-
-#include <lib/nfc_protocols/nfc_util.h>
-#include <lib/nfc_protocols/emv.h>
-#include <lib/nfc_protocols/mifare_common.h>
-#include <lib/nfc_protocols/mifare_ultralight.h>
-#include <lib/nfc_protocols/mifare_classic.h>
-#include <lib/nfc_protocols/mifare_desfire.h>
-#include <lib/nfc_protocols/nfca.h>
-
-#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 <dolphin/dolphin.h>
+
+#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
index 4b3be9e1..eefe560e 100755..100644
--- 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 <dolphin/dolphin.h>
-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, &sectors_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
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
index 0099f1a0..4942292c 100755..100644
--- 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 <dolphin/dolphin.h>
+
+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, &sectors_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
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
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
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
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
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
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
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 <dolphin/dolphin.h>
+
+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 <dolphin/dolphin.h>
-
-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 <dolphin/dolphin.h>
-
-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 <dolphin/dolphin.h>
-
-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 <dolphin/dolphin.h>
-
-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 <dolphin/dolphin.h>
-
-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 <dolphin/dolphin.h>
-
-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,16 +19,13 @@ 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);
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
@@ -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 <m-string.h>
+#include <m-string.h>
#include <gui/elements.h>
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_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!");
+ canvas_set_font(canvas, FontSecondary);
+ 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, 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, 2, AlignCenter, AlignTop, string_get_cstr(m->header));
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);
- 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);
+ 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), "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) {
- 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;
- }
+ string_set_str(model->header, header);
return true;
});
}
-void dict_attack_card_removed(DictAttack* dict_attack) {
+void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
- if(model->state == DictAttackStateSearchKeys) {
- model->state = DictAttackStateCardRemoved;
- } else {
- model->state = DictAttackStateSearchCard;
- }
+ 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_inc_curr_sector(DictAttack* dict_attack) {
+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->current_sector++;
+ model->sector_current = curr_sec;
return true;
});
}
-void dict_attack_inc_found_key(DictAttack* dict_attack, MfClassicKey key) {
+void dict_attack_inc_current_sector(DictAttack* dict_attack) {
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++;
+ if(model->sector_current < model->sectors_total) {
+ model->sector_current++;
}
return true;
});
}
-void dict_attack_set_result(DictAttack* dict_attack, bool success) {
+void dict_attack_inc_keys_found(DictAttack* dict_attack) {
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 <gui/view.h>
#include <gui/modules/widget.h>
-#include <lib/nfc_protocols/mifare_classic.h>
+#include <lib/nfc/protocols/mifare_classic.h>
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 <furi_hal.h>
#include <applications/storage/storage.h>
#include <lib/flipper_format/flipper_format.h>
-#include <lib/nfc_protocols/nfca.h>
+#include <lib/nfc/protocols/nfca.h>
#include <lib/digital_signal/digital_signal.h>
#include <lib/flipper_format/flipper_format_i.h>
diff --git a/assets/icons/NFC/NFC_manual.png b/assets/icons/NFC/NFC_manual.png
new file mode 100644
index 00000000..d142f0fc
--- /dev/null
+++ b/assets/icons/NFC/NFC_manual.png
Binary files differ
diff --git a/assets/icons/NFC/Reader_detect.png b/assets/icons/NFC/Reader_detect.png
new file mode 100644
index 00000000..56d3663e
--- /dev/null
+++ b/assets/icons/NFC/Reader_detect.png
Binary files differ
diff --git a/firmware.scons b/firmware.scons
index 0d120592..438ac8e7 100644
--- a/firmware.scons
+++ b/firmware.scons
@@ -186,6 +186,7 @@ fwelf = fwenv["FW_ELF"] = fwenv.Program(
"subghz",
"flipperformat",
"toolbox",
+ "nfc",
"microtar",
"usb_stm32",
"st25rfal002",
diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h
index a25e7c6d..71186076 100644
--- a/firmware/targets/furi_hal_include/furi_hal_nfc.h
+++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h
@@ -10,7 +10,7 @@
#include <stdbool.h>
#include <stdint.h>
-#include <lib/nfc_protocols/nfca.h>
+#include <lib/nfc/protocols/nfca.h>
#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 <lib/toolbox/args.h>
+#include <lib/flipper_format/flipper_format.h>
+
+#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 <stdbool.h>
+#include <storage/storage.h>
+#include <lib/flipper_format/flipper_format.h>
+#include <lib/toolbox/stream/file_stream.h>
+#include <lib/toolbox/stream/buffered_file_stream.h>
+
+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
index 48d72bfb..48d72bfb 100644
--- a/applications/nfc/helpers/nfc_debug_pcap.c
+++ b/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
index 6d2a449a..6d2a449a 100644
--- a/applications/nfc/helpers/nfc_debug_pcap.h
+++ b/lib/nfc/helpers/nfc_debug_pcap.h
diff --git a/applications/nfc/nfc_device.c b/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 <toolbox/path.h>
+#include <lib/toolbox/path.h>
+#include <lib/toolbox/hex.h>
+#include <lib/nfc/protocols/nfc_util.h>
#include <flipper_format/flipper_format.h>
+#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
index 5ffca5ca..e1ff6d42 100644
--- a/applications/nfc/nfc_device.h
+++ b/lib/nfc/nfc_device.h
@@ -6,10 +6,10 @@
#include <dialogs/dialogs.h>
#include <furi_hal_nfc.h>
-#include <lib/nfc_protocols/emv.h>
-#include <lib/nfc_protocols/mifare_ultralight.h>
-#include <lib/nfc_protocols/mifare_classic.h>
-#include <lib/nfc_protocols/mifare_desfire.h>
+#include <lib/nfc/protocols/emv.h>
+#include <lib/nfc/protocols/mifare_ultralight.h>
+#include <lib/nfc/protocols/mifare_classic.h>
+#include <lib/nfc/protocols/mifare_desfire.h>
#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
index 42762876..42762876 100644
--- a/applications/nfc/nfc_types.c
+++ b/lib/nfc/nfc_types.c
diff --git a/applications/nfc/nfc_types.h b/lib/nfc/nfc_types.h
index fb53ce7c..fb53ce7c 100644
--- a/applications/nfc/nfc_types.h
+++ b/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 <furi_hal.h>
+
+#include <platform.h>
+#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
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 <furi.h>
+#include <lib/toolbox/stream/file_stream.h>
+
+#include <lib/nfc/protocols/nfc_util.h>
+#include <lib/nfc/protocols/emv.h>
+#include <lib/nfc/protocols/mifare_common.h>
+#include <lib/nfc/protocols/mifare_ultralight.h>
+#include <lib/nfc/protocols/mifare_classic.h>
+#include <lib/nfc/protocols/mifare_desfire.h>
+#include <lib/nfc/protocols/nfca.h>
+
+#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 <furi_hal_nfc.h>
+#include "../nfc_worker.h"
+
+#include <m-string.h>
+
+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 <gui/modules/widget.h>
+#include <nfc_worker_i.h>
+
+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
index f08164ba..f08164ba 100644
--- a/lib/nfc_protocols/crypto1.c
+++ b/lib/nfc/protocols/crypto1.c
diff --git a/lib/nfc_protocols/crypto1.h b/lib/nfc/protocols/crypto1.h
index 07b39c22..07b39c22 100644
--- a/lib/nfc_protocols/crypto1.h
+++ b/lib/nfc/protocols/crypto1.h
diff --git a/lib/nfc_protocols/emv.c b/lib/nfc/protocols/emv.c
index 935c9f63..935c9f63 100644
--- a/lib/nfc_protocols/emv.c
+++ b/lib/nfc/protocols/emv.c
diff --git a/lib/nfc_protocols/emv.h b/lib/nfc/protocols/emv.h
index b5a0c574..b5a0c574 100755
--- a/lib/nfc_protocols/emv.h
+++ b/lib/nfc/protocols/emv.h
diff --git a/lib/nfc_protocols/mifare_classic.c b/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
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);
+
+bool mf_classic_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK, MfClassicReader* reader);
-uint8_t mf_classic_get_total_sectors_num(MfClassicReader* reader);
+uint8_t mf_classic_get_total_sectors_num(MfClassicType type);
-void mf_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint32_t cuid, uint8_t sector);
+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
index fd622765..fd622765 100644
--- a/lib/nfc_protocols/mifare_common.c
+++ b/lib/nfc/protocols/mifare_common.c
diff --git a/lib/nfc_protocols/mifare_common.h b/lib/nfc/protocols/mifare_common.h
index 2b694d90..2b694d90 100644
--- a/lib/nfc_protocols/mifare_common.h
+++ b/lib/nfc/protocols/mifare_common.h
diff --git a/lib/nfc_protocols/mifare_desfire.c b/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 <furi.h>
#include <furi_hal_nfc.h>
+#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
index dbe0802e..e59743a2 100644
--- a/lib/nfc_protocols/mifare_desfire.h
+++ b/lib/nfc/protocols/mifare_desfire.h
@@ -4,6 +4,8 @@
#include <stdint.h>
#include <stdbool.h>
+#include <furi_hal_nfc.h>
+
#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
index 9dcd1d6a..9dcd1d6a 100644
--- a/lib/nfc_protocols/mifare_ultralight.c
+++ b/lib/nfc/protocols/mifare_ultralight.c
diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc/protocols/mifare_ultralight.h
index 77dbd1e4..77dbd1e4 100644
--- a/lib/nfc_protocols/mifare_ultralight.h
+++ b/lib/nfc/protocols/mifare_ultralight.h
diff --git a/lib/nfc_protocols/nfc_util.c b/lib/nfc/protocols/nfc_util.c
index 9de6f982..9de6f982 100644
--- a/lib/nfc_protocols/nfc_util.c
+++ b/lib/nfc/protocols/nfc_util.c
diff --git a/lib/nfc_protocols/nfc_util.h b/lib/nfc/protocols/nfc_util.h
index d530badc..d530badc 100644
--- a/lib/nfc_protocols/nfc_util.h
+++ b/lib/nfc/protocols/nfc_util.h
diff --git a/lib/nfc_protocols/nfca.c b/lib/nfc/protocols/nfca.c
index c401f8cc..c401f8cc 100755
--- a/lib/nfc_protocols/nfca.c
+++ b/lib/nfc/protocols/nfca.c
diff --git a/lib/nfc_protocols/nfca.h b/lib/nfc/protocols/nfca.h
index 498ef284..498ef284 100644
--- a/lib/nfc_protocols/nfca.h
+++ b/lib/nfc/protocols/nfca.h