[FL-1526] Mifare Ultralight emulation (#645)

* rfal: add discovery parameter for passing listen activation
* nfc: add discovery parameter to furi_hal_nfc_listen
* mifare_ul: add emulation parsing commands
* nfc: add mifare ul emulation
* nfc: switch to mifare ultralight emulation form menu
* furi-hal-nfc: add first frame reception in emulation mode
* nfc: change argument check
* nfc: rework nfc worker and mifare ul lib
* mifare_ul: add write and cnt increment commands
* nfc: add card modification check
* mifare_ul: add data changed flag
* nfc: add shodow files
* nfc: add restore original file

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
gornekich
2021-08-17 00:45:04 +03:00
committed by GitHub
parent e1d80d5402
commit c122317468
16 changed files with 354 additions and 69 deletions

View File

@@ -26,3 +26,4 @@ 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)

View File

@@ -1,38 +1,33 @@
#include "../nfc_i.h"
#define NFC_MF_UL_DATA_NOT_CHANGED (0UL)
#define NFC_MF_UL_DATA_CHANGED (1UL)
void nfc_emulate_mifare_ul_worker_callback(void* context) {
Nfc* nfc = (Nfc*)context;
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
}
const void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
// Setup view
Popup* popup = nfc->popup;
NfcDeviceCommomData* data = &nfc->dev.dev_data.nfc_data;
if(strcmp(nfc->dev.dev_name, "")) {
nfc_text_store_set(nfc, "%s", nfc->dev.dev_name);
} else if(data->uid_len == 4) {
nfc_text_store_set(
nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]);
} else if(data->uid_len == 7) {
nfc_text_store_set(
nfc,
"%02X %02X %02X %02X\n%02X %02X %02X",
data->uid[0],
data->uid[1],
data->uid[2],
data->uid[3],
data->uid[4],
data->uid[5],
data->uid[6]);
}
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
popup_set_header(popup, "Emulating Mf Ul", 56, 31, AlignLeft, AlignTop);
popup_set_text(popup, nfc->text_store, 56, 43, AlignLeft, AlignTop);
popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop);
// Setup and start worker
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
nfc_worker_start(nfc->worker, NfcWorkerStateEmulateMifareUl, &nfc->dev.dev_data, NULL, nfc);
nfc_worker_start(
nfc->worker,
NfcWorkerStateEmulateMifareUl,
&nfc->dev.dev_data,
nfc_emulate_mifare_ul_worker_callback,
nfc);
}
const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) {
@@ -42,6 +37,17 @@ const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent
if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10);
consumed = true;
} else 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) ==
NFC_MF_UL_DATA_CHANGED) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED);
nfc_device_save_shadow(&nfc->dev, nfc->dev.dev_name);
}
consumed = false;
}
return consumed;
}
@@ -49,9 +55,6 @@ const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent
const void nfc_scene_emulate_mifare_ul_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);

View File

@@ -38,7 +38,7 @@ const bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent ev
} else if(event.event == SubmenuIndexEmulate) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented);
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
return true;
}
} else if(event.type == SceneManagerEventTypeBack) {

View File

@@ -0,0 +1,48 @@
#include "../nfc_i.h"
#define SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT (0UL)
void nfc_scene_restore_original_popup_callback(void* context) {
Nfc* nfc = (Nfc*)context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT);
}
const void nfc_scene_restore_original_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
// Setup view
Popup* popup = nfc->popup;
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Original file\nrestored", 13, 22, AlignLeft, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, nfc);
popup_set_callback(popup, nfc_scene_restore_original_popup_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
}
const bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
}
}
return consumed;
}
const void nfc_scene_restore_original_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
}

View File

@@ -5,6 +5,7 @@ enum SubmenuIndex {
SubmenuIndexEdit,
SubmenuIndexDelete,
SubmenuIndexInfo,
SubmenuIndexRestoreOriginal,
};
void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
@@ -29,36 +30,52 @@ const void nfc_scene_saved_menu_on_enter(void* context) {
submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc);
submenu_set_selected_item(
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu));
if(nfc->dev.shadow_file_exist) {
submenu_add_item(
submenu,
"Restore original",
SubmenuIndexRestoreOriginal,
nfc_scene_saved_menu_submenu_callback,
nfc);
}
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
const bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event);
if(event.event == SubmenuIndexEmulate) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexEmulate);
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
return true;
if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
}
consumed = true;
} else if(event.event == SubmenuIndexEdit) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexEdit);
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
return true;
consumed = true;
} else if(event.event == SubmenuIndexDelete) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexDelete);
scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete);
return true;
consumed = true;
} else if(event.event == SubmenuIndexInfo) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexInfo);
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
return true;
consumed = true;
} else if(event.event == SubmenuIndexRestoreOriginal) {
if(!nfc_device_restore(&nfc->dev)) {
scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart);
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginal);
}
consumed = true;
}
}
return false;
return consumed;
}
const void nfc_scene_saved_menu_on_exit(void* context) {