Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nfc: collect nonces during mf classic emulation #154

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions applications/nfc/nfc_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct Nfc {
SceneManager* scene_manager;
NfcDevice* dev;
FuriHalNfcDevData dev_edit_data;
bool card_data_changed;

char text_store[NFC_TEXT_STORE_SIZE + 1];
string_t text_box_store;
Expand Down
133 changes: 111 additions & 22 deletions applications/nfc/scenes/nfc_scene_mf_classic_emulate.c
Original file line number Diff line number Diff line change
@@ -1,34 +1,70 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>

#define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL)
#define NFC_MF_CLASSIC_DATA_CHANGED (1UL)
enum {
NfcSceneMfClassicEmulateStateWidget,
NfcSceneMfClassicEmulateStateTextBox,
};

bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
Nfc* nfc = context;

scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_CHANGED);
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
return true;
}

void nfc_scene_mf_classic_emulate_on_enter(void* context) {
static void nfc_scene_mf_classic_emulate_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
furi_assert(context);
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcEmulate);
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}

// Setup view
Popup* popup = nfc->popup;
// Add widget with device name or inform that data received
static void nfc_scene_mf_classic_emulate_widget_config(Nfc* nfc, bool has_data) {
Widget* widget = nfc->widget;
widget_reset(widget);

widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61);
if(strcmp(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);
nfc_text_store_set(nfc, "Emulating\nMf Classic");
}
widget_add_string_multiline_element(
widget, 56, 31, AlignLeft, AlignTop, FontPrimary, nfc->text_store);

if(has_data) {
widget_add_button_element(
widget, GuiButtonTypeLeft, "Log", nfc_scene_mf_classic_emulate_widget_callback, nfc);
widget_add_button_element(
widget, GuiButtonTypeRight, "Save", nfc_scene_mf_classic_emulate_widget_callback, nfc);
}
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop);
}

void nfc_scene_mf_classic_emulate_on_enter(void* context) {
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcEmulate);

// Setup view
nfc_scene_mf_classic_emulate_widget_config(nfc, false);

// Setup and start worker
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);

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);

string_init(nfc->dev->dev_data.mf_classic_emulator_output.nonce_log);
nfc->dev->dev_data.mf_classic_emulator_output.data_changed = false;

nfc_worker_start(
nfc->worker,
NfcWorkerStateMfClassicEmulate,
Expand All @@ -41,27 +77,80 @@ void nfc_scene_mf_classic_emulate_on_enter(void* context) {
bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
NfcMfClassicEmulatorOutput* emulator_output = &nfc->dev->dev_data.mf_classic_emulator_output;
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicEmulate);

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, NfcSceneMfClassicEmulate) ==
NFC_MF_CLASSIC_DATA_CHANGED) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventWorkerExit) {
consumed = true;
if(string_size(emulator_output->nonce_log)) {
// Add data button to widget if data is received for the first time
if(!string_size(nfc->text_box_store)) {
nfc_scene_mf_classic_emulate_widget_config(nfc, true);
}

// TODO(indutny): worry about concurrency?

// Copy and display log
string_set(nfc->text_box_store, emulator_output->nonce_log);
string_strim(nfc->text_box_store);
text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store));
}
} else if(event.event == GuiButtonTypeLeft && state == NfcSceneMfClassicEmulateStateWidget) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_NOT_CHANGED);
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
nfc->scene_manager,
NfcSceneMfClassicEmulate,
NfcSceneMfClassicEmulateStateTextBox);
consumed = true;
} else if(event.event == GuiButtonTypeRight && state == NfcSceneMfClassicEmulateStateWidget) {
// Stop worker without deallocating the nonce log
nfc_worker_stop(nfc->worker);

// Check if data changed and save in shadow file
if(emulator_output->data_changed) {
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
}

// Enter next scene
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
} else if(
event.event == NfcCustomEventViewExit &&
state == NfcSceneMfClassicEmulateStateTextBox) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfClassicEmulate, NfcSceneMfClassicEmulateStateWidget);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
// Close TextBox
if(state == NfcSceneMfClassicEmulateStateTextBox) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfClassicEmulate, NfcSceneMfClassicEmulateStateWidget);
consumed = true;
} else {
// Stop worker
nfc_worker_stop(nfc->worker);
string_clear(emulator_output->nonce_log);

// Check if data changed and save in shadow file
if(emulator_output->data_changed) {
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
}
}
consumed = false;
}

return consumed;
}

void nfc_scene_mf_classic_emulate_on_exit(void* context) {
Nfc* nfc = context;

// Clear view
popup_reset(nfc->popup);
widget_reset(nfc->widget);
string_reset(nfc->text_box_store);

nfc_blink_stop(nfc);
}
32 changes: 26 additions & 6 deletions applications/nfc/scenes/nfc_scene_save_name.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ void nfc_scene_save_name_on_enter(void* context) {
} else {
nfc_text_store_set(nfc, nfc->dev->dev_name);
}
text_input_set_header_text(text_input, "Name the card");
const char* extension;
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicEmulate)) {
extension = NFC_APP_LOG_EXTENSION;
text_input_set_header_text(text_input, "Name the nonce file");
} else {
extension = NFC_APP_EXTENSION;
text_input_set_header_text(text_input, "Name the card");
}
text_input_set_result_callback(
text_input,
nfc_scene_save_name_text_input_callback,
Expand All @@ -34,14 +41,14 @@ void nfc_scene_save_name_on_enter(void* context) {
string_t folder_path;
string_init(folder_path);

if(string_end_with_str_p(nfc->dev->load_path, NFC_APP_EXTENSION)) {
if(string_end_with_str_p(nfc->dev->load_path, extension)) {
path_extract_dirname(string_get_cstr(nfc->dev->load_path), folder_path);
} else {
string_set_str(folder_path, NFC_APP_FOLDER);
}

ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
string_get_cstr(folder_path), NFC_APP_EXTENSION, nfc->dev->dev_name);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(string_get_cstr(folder_path), extension, nfc->dev->dev_name);
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);

view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput);
Expand All @@ -53,8 +60,21 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventTextInputDone) {
if(event.type == SceneManagerEventTypeCustom && event.event == NfcCustomEventTextInputDone) {
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicEmulate)) {
NfcMfClassicEmulatorOutput* mf_classic_emulate =
&nfc->dev->dev_data.mf_classic_emulator_output;
string_t nonce_log;
string_move(nonce_log, mf_classic_emulate->nonce_log);
if(nfc_device_save_mf_classic_nonces(nfc->dev, nfc->text_store, nonce_log)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
consumed = true;
} else {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart);
}
string_reset(nonce_log);
} else {
if(strcmp(nfc->dev->dev_name, "")) {
nfc_device_delete(nfc->dev, true);
}
Expand Down
4 changes: 4 additions & 0 deletions applications/nfc/scenes/nfc_scene_save_success.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneSavedMenu);
} else if(scene_manager_has_previous_scene(
nfc->scene_manager, NfcSceneMfClassicEmulate)) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneMfClassicEmulate);
} else {
consumed = scene_manager_search_and_switch_to_another_scene(
nfc->scene_manager, NfcSceneFileSelect);
Expand Down
44 changes: 44 additions & 0 deletions lib/nfc/nfc_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,50 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_SHADOW_EXTENSION, true);
}

bool nfc_device_save_mf_classic_nonces(
NfcDevice* dev,
const char* name,
string_t nonces
) {
furi_assert(dev);
furi_assert(dev->format == NfcDeviceSaveFormatMifareClassic);

bool saved = false;
File* file = storage_file_alloc(dev->storage);
if(!file) {
return false;
}
string_t temp_str;
string_init(temp_str);

do {
if(!string_empty_p(dev->load_path)) {
// Get directory name
path_extract_dirname(string_get_cstr(dev->load_path), temp_str);
} else {
string_set_str(temp_str, NFC_APP_FOLDER);
}

// Create nfc directory if necessary
if(!storage_simply_mkdir(dev->storage, string_get_cstr(temp_str))) break;
// Make path to file to save
string_cat_printf(temp_str, "/%s%s", name, NFC_APP_LOG_EXTENSION);
// Open file
if(!storage_file_open(file, string_get_cstr(temp_str), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) break;
// Write nonces
uint32_t line_len = string_size(nonces);
if(storage_file_write(file, string_get_cstr(nonces), line_len) != line_len) break;
saved = true;
} while(0);

if(!saved) {
dialog_message_show_storage_error(dev->dialogs, "Can not save\nnonces file");
}
string_clear(temp_str);
storage_file_free(file);
return saved;
}

static bool nfc_device_load_data(NfcDevice* dev, string_t path, bool show_dialog) {
bool parsed = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
Expand Down
17 changes: 16 additions & 1 deletion lib/nfc/nfc_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@

#define NFC_DEV_NAME_MAX_LEN 22
#define NFC_READER_DATA_MAX_SIZE 64
#define NFC_MAX_NONCE_COUNT 64

#define NFC_APP_FOLDER ANY_PATH("nfc")
#define NFC_APP_EXTENSION ".nfc"
#define NFC_APP_SHADOW_EXTENSION ".shd"
#define NFC_APP_LOG_EXTENSION ".txt"

typedef void (*NfcLoadingCallback)(void* context, bool state);

Expand All @@ -41,10 +43,18 @@ typedef struct {
uint16_t size;
} NfcReaderRequestData;

typedef struct {
string_t nonce_log;
bool data_changed;
} NfcMfClassicEmulatorOutput;

typedef struct {
FuriHalNfcDevData nfc_data;
NfcProtocol protocol;
NfcReaderRequestData reader_data;
union {
NfcReaderRequestData reader_data;
NfcMfClassicEmulatorOutput mf_classic_emulator_output;
};
union {
EmvData emv_data;
MfUltralightData mf_ul_data;
Expand Down Expand Up @@ -77,6 +87,11 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name);

bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name);

bool nfc_device_save_mf_classic_nonces(
NfcDevice* dev,
const char* name,
string_t nonces);

bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog);

bool nfc_device_load_key_cache(NfcDevice* dev);
Expand Down
Loading