From e9454b629b7853b0ca374871c2fa3015c5774f4e Mon Sep 17 00:00:00 2001 From: Methodius Date: Thu, 11 Jan 2024 18:11:54 +0900 Subject: [PATCH] NFC fap: EMV protocol added --- .../nfc/helpers/protocol_support/emv/emv.c | 115 ++++++++++++++++++ .../nfc/helpers/protocol_support/emv/emv.h | 5 + .../helpers/protocol_support/emv/emv_render.c | 35 ++++++ .../helpers/protocol_support/emv/emv_render.h | 16 +++ .../nfc_protocol_support_defs.c | 2 + .../main/nfc/scenes/nfc_scene_config.h | 2 + .../main/nfc/scenes/nfc_scene_emv_more_info.c | 75 ++++++++++++ lib/nfc/SConscript | 2 + lib/nfc/protocols/emv/emv.h | 4 +- lib/nfc/protocols/emv/emv_poller_i.c | 8 +- targets/f7/api_symbols.csv | 24 +++- 11 files changed, 281 insertions(+), 7 deletions(-) create mode 100644 applications/main/nfc/helpers/protocol_support/emv/emv.c create mode 100644 applications/main/nfc/helpers/protocol_support/emv/emv.h create mode 100644 applications/main/nfc/helpers/protocol_support/emv/emv_render.c create mode 100644 applications/main/nfc/helpers/protocol_support/emv/emv_render.h create mode 100644 applications/main/nfc/scenes/nfc_scene_emv_more_info.c diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv.c b/applications/main/nfc/helpers/protocol_support/emv/emv.c new file mode 100644 index 000000000..035f8d220 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/emv/emv.c @@ -0,0 +1,115 @@ +#include "emv.h" +#include "emv_render.h" + +#include + +#include "nfc/nfc_app_i.h" + +#include "../nfc_protocol_support_common.h" +#include "../nfc_protocol_support_gui_common.h" +#include "../iso14443_4a/iso14443_4a_i.h" + +static void nfc_scene_info_on_enter_emv(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_emv_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static void nfc_scene_more_info_on_enter_emv(NfcApp* instance) { + // Jump to advanced scene right away + scene_manager_next_scene(instance->scene_manager, NfcSceneEmvMoreInfo); +} + +static NfcCommand nfc_scene_read_poller_callback_emv(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolEmv); + + NfcApp* instance = context; + const EmvPollerEvent* emv_event = event.event_data; + + if(emv_event->type == EmvPollerEventTypeReadSuccess) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolEmv, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + return NfcCommandStop; + } + + return NfcCommandContinue; +} + +static void nfc_scene_read_on_enter_emv(NfcApp* instance) { + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_emv, instance); +} + +static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_emv_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +// static void nfc_scene_emulate_on_enter_emv(NfcApp* instance) { +// const Iso14443_4aData* iso14443_4a_data = +// nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_4a); + +// instance->listener = +// nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_4a, iso14443_4a_data); +// nfc_listener_start( +// instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance); +// } + +const NfcProtocolSupportBase nfc_protocol_support_emv = { + .features = NfcProtocolFeatureNone, + + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_emv, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_more_info = + { + .on_enter = nfc_scene_more_info_on_enter_emv, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_emv, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_read_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_emv, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_saved_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_save_name = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, +}; diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv.h b/applications/main/nfc/helpers/protocol_support/emv/emv.h new file mode 100644 index 000000000..c68564f36 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/emv/emv.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_emv; diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c new file mode 100644 index 000000000..46cdc974f --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -0,0 +1,35 @@ +#include "emv_render.h" + +#include "../iso14443_4a/iso14443_4a_render.h" + +void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) { + nfc_render_iso14443_4a_brief(emv_get_base_data(data), str); + + nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); + nfc_render_emv_name(data->emv_application.name, str); + + if(format_type != NfcProtocolFormatTypeFull) return; + + furi_string_cat(str, "\n\e#ISO14443-4 data"); + nfc_render_iso14443_4a_extra(emv_get_base_data(data), str); +} + +void nfc_render_emv_data(const EmvData* data, FuriString* str) { + nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); + nfc_render_emv_name(data->emv_application.name, str); +} + +void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) { + for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%u", data[i]); + furi_string_cat_printf(str, "\n"); +} + +void nfc_render_emv_name(const char* data, FuriString* str) { + UNUSED(data); + furi_string_cat_printf(str, "\n"); +} + +void nfc_render_emv_application(const EmvApplication* data, FuriString* str) { + UNUSED(data); + furi_string_cat_printf(str, "\n"); +} \ No newline at end of file diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h new file mode 100644 index 000000000..16fc2e172 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" +#include + +void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str); + +void nfc_render_emv_data(const EmvData* data, FuriString* str); + +void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str); + +void nfc_render_emv_name(const char* data, FuriString* str); + +void nfc_render_emv_application(const EmvApplication* data, FuriString* str); \ No newline at end of file diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c index 215ffc455..9e61585c9 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c @@ -18,6 +18,7 @@ #include "mf_ultralight/mf_ultralight.h" #include "mf_classic/mf_classic.h" #include "mf_desfire/mf_desfire.h" +#include "emv/emv.h" #include "slix/slix.h" #include "st25tb/st25tb.h" @@ -39,6 +40,7 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight, [NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic, [NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire, + [NfcProtocolEmv] = &nfc_protocol_support_emv, [NfcProtocolSlix] = &nfc_protocol_support_slix, [NfcProtocolSt25tb] = &nfc_protocol_support_st25tb, /* Add new protocol support implementations here */ diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a9887996d..c0e28f480 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -36,6 +36,8 @@ ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) ADD_SCENE(nfc, mf_desfire_more_info, MfDesfireMoreInfo) ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) +ADD_SCENE(nfc, emv_more_info, EmvMoreInfo) + ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, mf_classic_detect_reader, MfClassicDetectReader) ADD_SCENE(nfc, mf_classic_mfkey_nonces_info, MfClassicMfkeyNoncesInfo) diff --git a/applications/main/nfc/scenes/nfc_scene_emv_more_info.c b/applications/main/nfc/scenes/nfc_scene_emv_more_info.c new file mode 100644 index 000000000..5825190d1 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_emv_more_info.c @@ -0,0 +1,75 @@ +#include "../nfc_app_i.h" + +#include "../helpers/protocol_support/nfc_protocol_support_gui_common.h" +#include "../helpers/protocol_support/emv/emv_render.h" + +enum { + EmvMoreInfoStateMenu, + EmvMoreInfoStateItem, // MUST be last, states >= this correspond with submenu index +}; + +enum SubmenuIndex { + SubmenuIndexCardInfo, + SubmenuIndexDynamic, // dynamic indices start here +}; + +void nfc_scene_emv_more_info_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + text_box_set_font(nfc->text_box, TextBoxFontHex); + + submenu_add_item( + submenu, + "Card info", + SubmenuIndexCardInfo, + nfc_protocol_support_common_submenu_callback, + nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_emv_more_info_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + const uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmvMoreInfo); + const EmvData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolEmv); + + if(event.type == SceneManagerEventTypeCustom) { + TextBox* text_box = nfc->text_box; + furi_string_reset(nfc->text_box_store); + + if(event.event == SubmenuIndexCardInfo) { + nfc_render_emv_data(data, nfc->text_box_store); + text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + scene_manager_set_scene_state( + nfc->scene_manager, + NfcSceneEmvMoreInfo, + EmvMoreInfoStateItem + SubmenuIndexCardInfo); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state >= EmvMoreInfoStateItem) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmvMoreInfo, EmvMoreInfoStateMenu); + } else { + // Return directly to the Info scene + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneInfo); + } + consumed = true; + } + + return consumed; +} + +void nfc_scene_emv_more_info_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear views + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + submenu_reset(nfc->submenu); +} diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 41332362c..3ad62f322 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -22,6 +22,7 @@ env.Append( File("protocols/mf_ultralight/mf_ultralight.h"), File("protocols/mf_classic/mf_classic.h"), File("protocols/mf_desfire/mf_desfire.h"), + File("protocols/emv/emv.h"), File("protocols/slix/slix.h"), File("protocols/st25tb/st25tb.h"), # Pollers @@ -32,6 +33,7 @@ env.Append( File("protocols/mf_ultralight/mf_ultralight_poller.h"), File("protocols/mf_classic/mf_classic_poller.h"), File("protocols/mf_desfire/mf_desfire_poller.h"), + File("protocols/emv/emv_poller.h"), File("protocols/st25tb/st25tb_poller.h"), # Listeners File("protocols/iso14443_3a/iso14443_3a_listener.h"), diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index feb390c7d..253101df7 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -41,8 +41,8 @@ typedef struct { bool app_started; char name[32]; bool name_found; - uint8_t card_number[10]; - uint8_t card_number_len; + uint8_t pan[10]; + uint8_t pan_len; uint8_t exp_month; uint8_t exp_year; uint16_t country_code; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 22c862661..4bb85eab7 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -186,8 +186,8 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio // 0xD0 delimits PAN from expiry (YYMM) for(int x = 1; x < tlen; x++) { if(buff[i + x + 1] > 0xD0) { - memcpy(app->card_number, &buff[i], x + 1); - app->card_number_len = x + 1; + memcpy(app->pan, &buff[i], x + 1); + app->pan_len = x + 1; app->exp_year = (buff[i + x + 1] << 4) | (buff[i + x + 2] >> 4); app->exp_month = (buff[i + x + 2] << 4) | (buff[i + x + 3] >> 4); break; @@ -213,8 +213,8 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio break; } case EMV_TAG_PAN: - memcpy(app->card_number, &buff[i], tlen); - app->card_number_len = tlen; + memcpy(app->pan, &buff[i], tlen); + app->pan_len = tlen; success = true; break; case EMV_TAG_EXP_DATE: diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 0ce105b05..1857a77ca 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,50.1,, +Version,v,50.2,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -120,6 +120,8 @@ Header,+,lib/nfc/nfc_device.h,, Header,+,lib/nfc/nfc_listener.h,, Header,+,lib/nfc/nfc_poller.h,, Header,+,lib/nfc/nfc_scanner.h,, +Header,?,lib/nfc/protocols/emv/emv.h,, +Header,?,lib/nfc/protocols/emv/emv_poller.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h,, @@ -877,6 +879,25 @@ Function,+,elf_symbolname_hash,uint32_t,const char* Function,+,empty_screen_alloc,EmptyScreen*, Function,+,empty_screen_free,void,EmptyScreen* Function,+,empty_screen_get_view,View*,EmptyScreen* +Function,?,emv_alloc,EmvData*, +Function,?,emv_copy,void,"EmvData*, const EmvData*" +Function,?,emv_free,void,EmvData* +Function,?,emv_get_application,const EmvApplication*,const EmvData* +Function,?,emv_get_base_data,Iso14443_4aData*,const EmvData* +Function,?,emv_get_device_name,const char*,"const EmvData*, NfcDeviceNameType" +Function,?,emv_get_uid,const uint8_t*,"const EmvData*, size_t*" +Function,?,emv_is_equal,_Bool,"const EmvData*, const EmvData*" +Function,?,emv_load,_Bool,"EmvData*, FlipperFormat*, uint32_t" +Function,?,emv_poller_get_processing_options,EmvError,EmvPoller* +Function,?,emv_poller_read,EmvError,EmvPoller* +Function,?,emv_poller_read_files,EmvError,EmvPoller* +Function,?,emv_poller_read_sfi_record,EmvError,"EmvPoller*, uint8_t, uint8_t" +Function,?,emv_poller_select_application,EmvError,EmvPoller* +Function,?,emv_poller_select_ppse,EmvError,EmvPoller* +Function,?,emv_reset,void,EmvData* +Function,?,emv_save,_Bool,"const EmvData*, FlipperFormat*" +Function,?,emv_set_uid,_Bool,"EmvData*, const uint8_t*, size_t" +Function,?,emv_verify,_Bool,"EmvData*, const FuriString*" Function,-,erand48,double,unsigned short[3] Function,-,erf,double,double Function,-,erfc,double,double @@ -3619,6 +3640,7 @@ Variable,+,message_red_255,const NotificationMessage, Variable,+,message_sound_off,const NotificationMessage, Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, +Variable,?,nfc_device_emv,const NfcDeviceBase, Variable,-,nfc_device_mf_classic,const NfcDeviceBase, Variable,-,nfc_device_mf_desfire,const NfcDeviceBase, Variable,-,nfc_device_mf_ultralight,const NfcDeviceBase,