From 931a603ebbae8db6c96941a6773fccc9e2ed0e36 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Wed, 4 Jan 2023 23:41:51 -0700 Subject: [PATCH 01/11] nfc: Add option for whether EMVCo compliance is used in detect --- applications/external/nfc_magic/nfc_magic_worker.c | 2 +- applications/main/nfc/nfc_cli.c | 3 ++- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 6 +++--- firmware/targets/f7/furi_hal/furi_hal_nfc.h | 11 +++++------ lib/nfc/nfc_worker.c | 14 +++++++------- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/applications/external/nfc_magic/nfc_magic_worker.c b/applications/external/nfc_magic/nfc_magic_worker.c index 92eb793a71d8..6b46288a5bc9 100644 --- a/applications/external/nfc_magic/nfc_magic_worker.c +++ b/applications/external/nfc_magic/nfc_magic_worker.c @@ -78,7 +78,7 @@ void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) { MfClassicData* src_data = &nfc_magic_worker->dev_data->mf_classic_data; while(nfc_magic_worker->state == NfcMagicWorkerStateWrite) { - if(furi_hal_nfc_detect(&nfc_data, 200)) { + if(furi_hal_nfc_detect(&nfc_data, 200, false)) { if(!card_found_notified) { nfc_magic_worker->callback( NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 6e6e04ca928b..fb87ef0d1c96 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -33,7 +33,8 @@ static void nfc_cli_detect(Cli* cli, FuriString* args) { printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n"); while(!cmd_exit) { cmd_exit |= cli_cmd_interrupt_received(cli); - if(furi_hal_nfc_detect(&dev_data, 400)) { + if(furi_hal_nfc_detect(&dev_data, 400, true) || + furi_hal_nfc_detect(&dev_data, 400, false)) { printf("Found: %s ", nfc_get_dev_type(dev_data.type)); printf("UID length: %d, UID:", dev_data.uid_len); for(size_t i = 0; i < dev_data.uid_len; i++) { diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 8910d887bcb7..cd4569e3a9a3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -76,7 +76,7 @@ void furi_hal_nfc_exit_sleep() { rfalLowPowerModeStop(); } -bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) { +bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout, bool emv_compliance) { furi_assert(nfc_data); rfalNfcDevice* dev_list = NULL; @@ -90,7 +90,7 @@ bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) { rfalNfcInitialize(); } rfalNfcDiscoverParam params; - params.compMode = RFAL_COMPLIANCE_MODE_EMV; + params.compMode = emv_compliance ? RFAL_COMPLIANCE_MODE_EMV : RFAL_COMPLIANCE_MODE_NFC; params.techs2Find = RFAL_NFC_POLL_TECH_A | RFAL_NFC_POLL_TECH_B | RFAL_NFC_POLL_TECH_F | RFAL_NFC_POLL_TECH_V | RFAL_NFC_POLL_TECH_AP2P | RFAL_NFC_POLL_TECH_ST25TB; params.totalDuration = 1000; @@ -124,7 +124,7 @@ bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) { rfalNfcSelect(0); } if(DWT->CYCCNT - start > timeout * clocks_in_ms) { - rfalNfcDeactivate(true); + rfalNfcDeactivate(false); FURI_LOG_T(TAG, "Timeout"); break; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.h b/firmware/targets/f7/furi_hal/furi_hal_nfc.h index dc3f873f3460..fb8df7f79a28 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.h +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.h @@ -135,16 +135,15 @@ void furi_hal_nfc_stop_cmd(); */ void furi_hal_nfc_exit_sleep(); -/** NFC poll +/** NFC detect * - * @param dev_list pointer to rfalNfcDevice buffer - * @param dev_cnt pointer device count - * @param timeout timeout in ms - * @param deactivate deactivate flag + * @param nfc_data pointer to FuriHalNfcDevData + * @param timeout timeout in ms + * @param emv_compliance whether to use EMVCo compliance mode * * @return true on success */ -bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout); +bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout, bool emv_compliance); /** Activate NFC-A tag * diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 28a1f6827977..945c3ca721f6 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -148,7 +148,7 @@ static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxC furi_hal_nfc_sleep(); // Otherwise, try to read as usual - if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break; + if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200, false)) break; if(!mf_ul_read_card(tx_rx, &reader, &data)) break; // Copy data nfc_worker->dev_data->mf_ul_data = data; @@ -217,7 +217,7 @@ static bool nfc_worker_read_mf_desfire(NfcWorker* nfc_worker, FuriHalNfcTxRxCont } do { - if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break; + if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300, false)) break; if(!mf_df_read_card(tx_rx, data)) break; read_success = true; } while(false); @@ -272,7 +272,7 @@ void nfc_worker_read(NfcWorker* nfc_worker) { bool card_not_detected_notified = false; while(nfc_worker->state == NfcWorkerStateRead) { - if(furi_hal_nfc_detect(nfc_data, 300)) { + if(furi_hal_nfc_detect(nfc_data, 300, true) || furi_hal_nfc_detect(nfc_data, 300, false)) { // Process first found device nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); card_not_detected_notified = false; @@ -335,7 +335,7 @@ void nfc_worker_read_type(NfcWorker* nfc_worker) { bool card_not_detected_notified = false; while(nfc_worker->state == NfcWorkerStateRead) { - if(furi_hal_nfc_detect(nfc_data, 300)) { + if(furi_hal_nfc_detect(nfc_data, 300, true) || furi_hal_nfc_detect(nfc_data, 300, false)) { FURI_LOG_D(TAG, "Card detected"); furi_hal_nfc_sleep(); // Process first found device @@ -772,7 +772,7 @@ void nfc_worker_write_mf_classic(NfcWorker* nfc_worker) { MfClassicData dest_data = *src_data; while(nfc_worker->state == NfcWorkerStateMfClassicWrite) { - if(furi_hal_nfc_detect(&nfc_data, 200)) { + if(furi_hal_nfc_detect(&nfc_data, 200, false)) { if(!card_found_notified) { nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); card_found_notified = true; @@ -845,7 +845,7 @@ void nfc_worker_update_mf_classic(NfcWorker* nfc_worker) { MfClassicData new_data = *old_data; while(nfc_worker->state == NfcWorkerStateMfClassicUpdate) { - if(furi_hal_nfc_detect(&nfc_data, 200)) { + if(furi_hal_nfc_detect(&nfc_data, 200, false)) { if(!card_found_notified) { nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); card_found_notified = true; @@ -923,7 +923,7 @@ void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) { uint16_t pack = 0; while(nfc_worker->state == NfcWorkerStateReadMfUltralightReadAuth) { furi_hal_nfc_sleep(); - if(furi_hal_nfc_detect(nfc_data, 300) && nfc_data->type == FuriHalNfcTypeA) { + if(furi_hal_nfc_detect(nfc_data, 300, false) && nfc_data->type == FuriHalNfcTypeA) { if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); if(data->auth_method == MfUltralightAuthMethodManual || From 72f5e790c9269385de58c9670985f811c81ddfe8 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Wed, 4 Jan 2023 23:42:16 -0700 Subject: [PATCH 02/11] rfal: Bind platformLog to FURI_LOG_D --- lib/ST25RFAL002/platform.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ST25RFAL002/platform.h b/lib/ST25RFAL002/platform.h index d86bba73e36e..a20e4b415255 100644 --- a/lib/ST25RFAL002/platform.h +++ b/lib/ST25RFAL002/platform.h @@ -124,7 +124,8 @@ void rfal_platform_spi_release(); #define platformI2CSlaveAddrWR(add) /*!< I2C Slave address for Write operation */ #define platformI2CSlaveAddrRD(add) /*!< I2C Slave address for Read operation */ -#define platformLog(...) /*!< Log method */ +#define platformLog(...) \ + FURI_LOG_D("ST25RFAL002", __VA_ARGS__) /*!< Log method */ /* ****************************************************************************** From fc0315b656760e03021324c159e4558797b956cf Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Thu, 5 Jan 2023 03:49:50 -0700 Subject: [PATCH 03/11] nfc: Add Topaz read, save, and load support --- .../main/nfc/scenes/nfc_scene_config.h | 3 + .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 13 ++- applications/main/nfc/scenes/nfc_scene_read.c | 5 + .../nfc/scenes/nfc_scene_read_card_type.c | 12 ++ .../main/nfc/scenes/nfc_scene_topaz_data.c | 34 ++++++ .../main/nfc/scenes/nfc_scene_topaz_menu.c | 71 ++++++++++++ .../nfc/scenes/nfc_scene_topaz_read_success.c | 74 ++++++++++++ lib/nfc/nfc_device.c | 67 +++++++++++ lib/nfc/nfc_device.h | 5 + lib/nfc/nfc_types.c | 12 ++ lib/nfc/nfc_types.h | 2 + lib/nfc/nfc_worker.c | 41 +++++++ lib/nfc/nfc_worker.h | 1 + lib/nfc/protocols/topaz.c | 109 ++++++++++++++++++ lib/nfc/protocols/topaz.h | 37 ++++++ 15 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_topaz_data.c create mode 100644 applications/main/nfc/scenes/nfc_scene_topaz_menu.c create mode 100644 applications/main/nfc/scenes/nfc_scene_topaz_read_success.c create mode 100644 lib/nfc/protocols/topaz.c create mode 100644 lib/nfc/protocols/topaz.h diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a9da07dfda00..8386345b4f1a 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -44,6 +44,9 @@ ADD_SCENE(nfc, mf_classic_write_fail, MfClassicWriteFail) ADD_SCENE(nfc, mf_classic_update, MfClassicUpdate) ADD_SCENE(nfc, mf_classic_update_success, MfClassicUpdateSuccess) ADD_SCENE(nfc, mf_classic_wrong_card, MfClassicWrongCard) +ADD_SCENE(nfc, topaz_read_success, TopazReadSuccess) +ADD_SCENE(nfc, topaz_menu, TopazMenu) +ADD_SCENE(nfc, topaz_data, TopazData) ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) ADD_SCENE(nfc, emv_menu, EmvMenu) ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index 92ad7b56ef41..aee483ddc5b5 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -15,7 +15,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { NfcProtocol protocol = dev_data->protocol; uint8_t text_scroll_height = 0; if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl) || - (protocol == NfcDeviceProtocolMifareClassic)) { + (protocol == NfcDeviceProtocolMifareClassic) || (protocol == NfcDeviceProtocolTopaz)) { widget_add_button_element( widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc); text_scroll_height = 52; @@ -41,6 +41,11 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n"); + } else if(protocol == NfcDeviceProtocolTopaz) { + furi_string_cat_printf( + temp_str, + "\e#%s\n", + nfc_topaz_type(topaz_get_type_from_hr0(dev_data->topaz_data.hr[0]))); } else { furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); } @@ -114,6 +119,9 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); furi_string_cat_printf(temp_str, "\nKeys Found %d/%d", keys_found, keys_total); furi_string_cat_printf(temp_str, "\nSectors Read %d/%d", sectors_read, sectors_total); + } else if(protocol == NfcDeviceProtocolTopaz) { + TopazData* data = &dev_data->topaz_data; + furi_string_cat_printf(temp_str, "\nHR0: %02X\nHR1: %02X", data->hr[0], data->hr[1]); } // Add text scroll widget @@ -140,6 +148,9 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { } else if(protocol == NfcDeviceProtocolMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData); consumed = true; + } else if(protocol == NfcDeviceProtocolTopaz) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneTopazData); + consumed = true; } } } diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 938f2da67546..09fe7d34a532 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -85,6 +85,11 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; + } else if(event.event == NfcWorkerEventReadTopaz) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneTopazReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c index 8023026c3da8..de3ff7517c27 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -5,6 +5,7 @@ enum SubmenuIndex { SubmenuIndexReadMifareClassic, SubmenuIndexReadMifareDesfire, SubmenuIndexReadMfUltralight, + SubmenuIndexReadTopaz, SubmenuIndexReadNFCA, }; @@ -36,6 +37,12 @@ void nfc_scene_read_card_type_on_enter(void* context) { SubmenuIndexReadMfUltralight, nfc_scene_read_card_type_submenu_callback, nfc); + submenu_add_item( + submenu, + "Read Topaz", + SubmenuIndexReadTopaz, + nfc_scene_read_card_type_submenu_callback, + nfc); submenu_add_item( submenu, "Read NFC-A data", @@ -68,6 +75,11 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); consumed = true; } + if(event.event == SubmenuIndexReadTopaz) { + nfc->dev->dev_data.read_mode = NfcReadModeTopaz; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } if(event.event == SubmenuIndexReadNFCA) { nfc->dev->dev_data.read_mode = NfcReadModeNFCA; scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); diff --git a/applications/main/nfc/scenes/nfc_scene_topaz_data.c b/applications/main/nfc/scenes/nfc_scene_topaz_data.c new file mode 100644 index 000000000000..d704454e8eb0 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_topaz_data.c @@ -0,0 +1,34 @@ +#include "../nfc_i.h" + +void nfc_scene_topaz_data_on_enter(void* context) { + Nfc* nfc = context; + TopazData* data = &nfc->dev->dev_data.topaz_data; + TextBox* text_box = nfc->text_box; + TopazType type = topaz_get_type_from_hr0(data->hr[0]); + size_t data_size = topaz_get_size_by_type(type); + + text_box_set_font(text_box, TextBoxFontHex); + for(uint16_t i = 0; i < data_size; i += 2) { + if(!(i % 8) && i) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data->data[i], data->data[i + 1]); + } + text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); +} + +bool nfc_scene_topaz_data_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_topaz_data_on_exit(void* context) { + Nfc* nfc = context; + + // Clean view + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); +} diff --git a/applications/main/nfc/scenes/nfc_scene_topaz_menu.c b/applications/main/nfc/scenes/nfc_scene_topaz_menu.c new file mode 100644 index 000000000000..7f3da14da359 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_topaz_menu.c @@ -0,0 +1,71 @@ +#include "../nfc_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexSave, + SubmenuIndexEmulate, + SubmenuIndexInfo, +}; + +void nfc_scene_topaz_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_topaz_menu_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, "Save", SubmenuIndexSave, nfc_scene_topaz_menu_submenu_callback, nfc); + // submenu_add_item( + // submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_topaz_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_topaz_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneTopazMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_topaz_menu_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSave) { + nfc->dev->format = NfcDeviceSaveFormatTopaz; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEmulate) { + // TODO + //scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneTopazMenu, event.event); + + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_topaz_menu_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_topaz_read_success.c b/applications/main/nfc/scenes/nfc_scene_topaz_read_success.c new file mode 100644 index 000000000000..172f0ab98f0f --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_topaz_read_success.c @@ -0,0 +1,74 @@ +#include "../nfc_i.h" + +void nfc_scene_topaz_read_success_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_topaz_read_success_on_enter(void* context) { + Nfc* nfc = context; + + // Setup widget view + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + TopazData* topaz_data = &nfc->dev->dev_data.topaz_data; + Widget* widget = nfc->widget; + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_topaz_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_topaz_read_success_widget_callback, nfc); + + FuriString* temp_str = NULL; + if(furi_string_size(nfc->dev->dev_data.parsed_data)) { + temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); + } else { + temp_str = furi_string_alloc_printf( + "\e#%s\n", nfc_topaz_type(topaz_get_type_from_hr0(topaz_data->hr[0]))); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", data->uid[i]); + } + furi_string_cat_printf( + temp_str, "\nHR0: %02X\nHR1: %02X", topaz_data->hr[0], topaz_data->hr[1]); + } + widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + notification_message_block(nfc->notifications, &sequence_set_green_255); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_topaz_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) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneTopazMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + + return consumed; +} + +void nfc_scene_topaz_read_success_on_exit(void* context) { + Nfc* nfc = context; + + notification_message_block(nfc->notifications, &sequence_reset_green); + + // Clean view + widget_reset(nfc->widget); +} diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 5179130702d8..fd35b3c2481c 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -58,6 +58,8 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, FuriString* format_ furi_string_set(format_string, "Mifare Classic"); } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { furi_string_set(format_string, "Mifare DESFire"); + } else if(dev->format == NfcDeviceSaveFormatTopaz) { + furi_string_set(format_string, "Topaz"); } else { furi_string_set(format_string, "Unknown"); } @@ -93,6 +95,11 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, FuriString* format_st dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire; return true; } + if(furi_string_start_with_str(format_string, "Topaz")) { + dev->format = NfcDeviceSaveFormatTopaz; + dev->dev_data.protocol = NfcDeviceProtocolTopaz; + return true; + } return false; } @@ -1012,6 +1019,62 @@ bool nfc_device_load_key_cache(NfcDevice* dev) { return load_success; } +static bool nfc_device_save_topaz_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + TopazData* data = &dev->dev_data.topaz_data; + FuriString* temp_str = furi_string_alloc(); + TopazType type = topaz_get_type_from_hr0(data->hr[0]); + size_t data_length = topaz_get_size_by_type(type); + + do { + if(!flipper_format_write_comment_cstr(file, "Topaz-specific data")) break; + if(!flipper_format_write_hex(file, "HR0", &data->hr[0], 1)) break; + if(!flipper_format_write_hex(file, "HR1", &data->hr[1], 1)) break; + + for(uint16_t i = 0; i < data_length; i += 8) { + furi_string_printf(temp_str, "Block %02X", i / 8); + if(!flipper_format_write_hex(file, furi_string_get_cstr(temp_str), &data->data[i], 8)) + break; + } + + saved = true; + } while(false); + + furi_string_free(temp_str); + return saved; +} + +static bool nfc_device_load_topaz_data(FlipperFormat* file, NfcDevice* dev) { + bool parsed = false; + TopazData* data = &dev->dev_data.topaz_data; + FuriString* temp_str = furi_string_alloc(); + TopazType type; + size_t data_length; + + do { + if(!flipper_format_read_hex(file, "HR0", &data->hr[0], 1)) break; + if(!flipper_format_read_hex(file, "HR1", &data->hr[1], 1)) break; + + if((data->hr[0] & 0xf0) != 0x10) { + FURI_LOG_D(TAG, "Non-Topaz HR0 detected: %02X", data->hr[0]); + break; + } + + type = topaz_get_type_from_hr0(data->hr[0]); + data_length = topaz_get_size_by_type(type); + + for(uint16_t i = 0; i < data_length; i += 8) { + furi_string_printf(temp_str, "Block %02X", i / 8); + if(!flipper_format_read_hex(file, furi_string_get_cstr(temp_str), &data->data[i], 8)) + break; + } + + parsed = true; + } while(false); + + return parsed; +} + void nfc_device_set_name(NfcDevice* dev, const char* name) { furi_assert(dev); @@ -1091,6 +1154,8 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { if(!nfc_device_save_mifare_classic_data(file, dev)) break; // Save keys cache if(!nfc_device_save_mifare_classic_keys(dev)) break; + } else if(dev->format == NfcDeviceSaveFormatTopaz) { + if(!nfc_device_save_topaz_data(file, dev)) break; } saved = true; } while(0); @@ -1186,6 +1251,8 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia if(!nfc_device_load_mifare_classic_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { if(!nfc_device_load_mifare_df_data(file, dev)) break; + } else if(dev->format == NfcDeviceSaveFormatTopaz) { + if(!nfc_device_load_topaz_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatBankCard) { if(!nfc_device_load_bank_card_data(file, dev)) break; } diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index df37ec3df53b..29db9d45a276 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -31,6 +32,7 @@ typedef enum { NfcDeviceProtocolMifareUl, NfcDeviceProtocolMifareClassic, NfcDeviceProtocolMifareDesfire, + NfcDeviceProtocolTopaz, } NfcProtocol; typedef enum { @@ -39,6 +41,7 @@ typedef enum { NfcDeviceSaveFormatMifareUl, NfcDeviceSaveFormatMifareClassic, NfcDeviceSaveFormatMifareDesfire, + NfcDeviceSaveFormatTopaz, } NfcDeviceSaveFormat; typedef struct { @@ -56,6 +59,7 @@ typedef enum { NfcReadModeMfClassic, NfcReadModeMfUltralight, NfcReadModeMfDesfire, + NfcReadModeTopaz, NfcReadModeNFCA, } NfcReadMode; @@ -73,6 +77,7 @@ typedef struct { MfUltralightData mf_ul_data; MfClassicData mf_classic_data; MifareDesfireData mf_df_data; + TopazData topaz_data; }; FuriString* parsed_data; } NfcDeviceData; diff --git a/lib/nfc/nfc_types.c b/lib/nfc/nfc_types.c index 02ca85580dbc..e76bb6647811 100644 --- a/lib/nfc/nfc_types.c +++ b/lib/nfc/nfc_types.c @@ -23,6 +23,8 @@ const char* nfc_guess_protocol(NfcProtocol protocol) { return "Mifare Classic"; } else if(protocol == NfcDeviceProtocolMifareDesfire) { return "Mifare DESFire"; + } else if(protocol == NfcDeviceProtocolTopaz) { + return "Topaz"; } else { return "Unrecognized"; } @@ -65,3 +67,13 @@ const char* nfc_mf_classic_type(MfClassicType type) { return "Mifare Classic"; } } + +const char* nfc_topaz_type(TopazType type) { + if(type == TopazType96) { + return "Topaz 96"; + } else if(type == TopazType512) { + return "Topaz 512"; + } else { + return "Topaz"; + } +} diff --git a/lib/nfc/nfc_types.h b/lib/nfc/nfc_types.h index fb53ce7c25be..8f1d168f7168 100644 --- a/lib/nfc/nfc_types.h +++ b/lib/nfc/nfc_types.h @@ -9,3 +9,5 @@ const char* nfc_guess_protocol(NfcProtocol protocol); const char* nfc_mf_ul_type(MfUltralightType type, bool full_name); const char* nfc_mf_classic_type(MfClassicType type); + +const char* nfc_topaz_type(TopazType type); diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 945c3ca721f6..f39ff892b3b5 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -229,6 +229,34 @@ static bool nfc_worker_read_mf_desfire(NfcWorker* nfc_worker, FuriHalNfcTxRxCont return read_success; } +static bool nfc_worker_read_topaz(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + bool read_success = false; + TopazData* data = &nfc_worker->dev_data->topaz_data; + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + + do { + if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300, false)) break; + if(!topaz_read_card(tx_rx, data, nfc_worker->dev_data->nfc_data.uid)) break; + read_success = true; + } while(false); + + if(read_success) { + // Update full UID from data + memcpy(nfc_worker->dev_data->nfc_data.uid, data->data, TOPAZ_UID_FULL_LENGTH); + nfc_worker->dev_data->nfc_data.uid_len = TOPAZ_UID_FULL_LENGTH; + } + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } + + return read_success; +} + static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; @@ -252,6 +280,10 @@ static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* t nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown; } card_read = true; + } else if(topaz_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1])) { + FURI_LOG_I(TAG, "Topaz detected"); + nfc_worker->dev_data->protocol = NfcDeviceProtocolTopaz; + card_read = nfc_worker_read_topaz(nfc_worker, tx_rx); } else { nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown; card_read = true; @@ -287,6 +319,9 @@ void nfc_worker_read(NfcWorker* nfc_worker) { } else if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) { event = NfcWorkerEventReadMfDesfire; break; + } else if(dev_data->protocol == NfcDeviceProtocolTopaz) { + event = NfcWorkerEventReadTopaz; + break; } else if(dev_data->protocol == NfcDeviceProtocolUnknown) { event = NfcWorkerEventReadUidNfcA; break; @@ -370,6 +405,12 @@ void nfc_worker_read_type(NfcWorker* nfc_worker) { event = NfcWorkerEventReadMfDesfire; break; } + } else if(read_mode == NfcReadModeTopaz) { + nfc_worker->dev_data->protocol = NfcDeviceProtocolTopaz; + if(nfc_worker_read_topaz(nfc_worker, &tx_rx)) { + event = NfcWorkerEventReadTopaz; + break; + } } else if(read_mode == NfcReadModeNFCA) { nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown; event = NfcWorkerEventReadUidNfcA; diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h index 8e993fc6aa3c..5f94f05d5872 100644 --- a/lib/nfc/nfc_worker.h +++ b/lib/nfc/nfc_worker.h @@ -39,6 +39,7 @@ typedef enum { NfcWorkerEventReadMfClassicDone, NfcWorkerEventReadMfClassicLoadKeyCache, NfcWorkerEventReadMfClassicDictAttackRequired, + NfcWorkerEventReadTopaz, // Nfc worker common events NfcWorkerEventSuccess, diff --git a/lib/nfc/protocols/topaz.c b/lib/nfc/protocols/topaz.c new file mode 100644 index 000000000000..b3309d0d8c65 --- /dev/null +++ b/lib/nfc/protocols/topaz.c @@ -0,0 +1,109 @@ +#include +#include "topaz.h" + +#define TAG "Topaz" + +bool topaz_check_card_type(uint8_t ATQA0, uint8_t ATQA1) { + return ATQA0 == 0x00 && ATQA1 == 0x0C; +} + +TopazType topaz_get_type_from_hr0(uint8_t hr0) { + if(hr0 == TOPAZ_96_HR0) { + return TopazType96; + } else if(hr0 == TOPAZ_512_HR0) { + return TopazType512; + } else { + return TopazTypeUnknown; + } +} + +size_t topaz_get_size_by_type(TopazType type) { + if(type == TopazType96) { + return TOPAZ_96_SIZE; + } else if(type == TopazType512) { + return TOPAZ_512_SIZE; + } else { + return TOPAZ_96_SIZE; // Probably safe fallback size; What's the size of Jewel? + } +} + +bool topaz_read_card(FuriHalNfcTxRxContext* tx_rx, TopazData* data, uint8_t* uid) { + size_t data_size; + size_t data_read = 0; + TopazType type; + bool read_success = false; + + do { + if(rfalT1TPollerInitialize() != ERR_NONE) { + FURI_LOG_D(TAG, "Failed to initialize poller"); + break; + } + + // Perform RALL: HR0, HR1, and block 00-0E + tx_rx->tx_data[0] = TOPAZ_CMD_RALL; + tx_rx->tx_data[1] = 0; + tx_rx->tx_data[2] = 0; + memcpy(&tx_rx->tx_data[3], uid, 4); + tx_rx->tx_bits = 7 * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + + if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits != 122 * 8) { + FURI_LOG_D(TAG, "Failed to RALL"); + break; + } + + memcpy(data->hr, tx_rx->rx_data, sizeof(data->hr)); + + type = topaz_get_type_from_hr0(data->hr[0]); + if(type == TopazTypeUnknown) { + FURI_LOG_D(TAG, "Unknown type, HR0=%#04x", data->hr[0]); + break; + } + data_size = topaz_get_size_by_type(type); + + memcpy(data->data, &tx_rx->rx_data[2], 120); + data_read += 120; + + if(data_size > TOPAZ_96_SIZE) { + // Perform READ8 on block 0F + tx_rx->tx_data[0] = TOPAZ_CMD_READ8; + tx_rx->tx_data[1] = 0x0F; + memset(&tx_rx->tx_data[2], 0, 8); + memcpy(&tx_rx->tx_data[10], uid, 4); + tx_rx->tx_bits = 14 * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + + if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits != 9 * 8 || + tx_rx->rx_data[0] != tx_rx->tx_data[1]) { + FURI_LOG_D(TAG, "Failed to read block 0F"); + break; + } + + memcpy(&data->data[data_read], &tx_rx->rx_data[1], 8); + data_read += 8; + + // Perform RSEG for rest of tag + for(uint8_t i = 1; data_read < data_size; ++i) { + tx_rx->tx_data[0] = TOPAZ_CMD_RSEG; + tx_rx->tx_data[1] = i << 4; + memset(&tx_rx->tx_data[2], 0, 8); + memcpy(&tx_rx->tx_data[10], uid, 4); + tx_rx->tx_bits = 14 * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + + if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits != 129 * 8 || + tx_rx->rx_data[0] != tx_rx->tx_data[1]) { + FURI_LOG_D(TAG, "Failed to read segment %d", i); + break; + } + + memcpy(&data->data[data_read], &tx_rx->rx_data[1], 128); + data_read += 128; + } + } + + read_success = true; + } while(false); + + return read_success; +} diff --git a/lib/nfc/protocols/topaz.h b/lib/nfc/protocols/topaz.h new file mode 100644 index 000000000000..6019ec11f41f --- /dev/null +++ b/lib/nfc/protocols/topaz.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#define TOPAZ_MAX_SIZE (512) +#define TOPAZ_UID_FULL_LENGTH (7) + +#define TOPAZ_CMD_RID (0x78) +#define TOPAZ_CMD_RALL (0x00) +#define TOPAZ_CMD_READ (0x01) +#define TOPAZ_CMD_WRITE_E (0x53) +#define TOPAZ_CMD_WRITE_NE (0x1A) +#define TOPAZ_CMD_RSEG (0x10) +#define TOPAZ_CMD_READ8 (0x02) +#define TOPAZ_CMD_WRITE_E8 (0x54) +#define TOPAZ_CMD_WRITE_NE8 (0x1B) + +#define TOPAZ_96_HR0 (0x11) +#define TOPAZ_96_SIZE (96) +#define TOPAZ_512_HR0 (0x12) +#define TOPAZ_512_SIZE (512) + +typedef enum { + TopazTypeUnknown, + TopazType96, + TopazType512, +} TopazType; + +typedef struct { + uint8_t hr[2]; + uint8_t data[TOPAZ_MAX_SIZE]; +} TopazData; + +bool topaz_check_card_type(uint8_t ATQA0, uint8_t ATQA1); +TopazType topaz_get_type_from_hr0(uint8_t hr0); +size_t topaz_get_size_by_type(TopazType type); +bool topaz_read_card(FuriHalNfcTxRxContext* tx_rx, TopazData* data, uint8_t* uid); From d0f0870f1234445c755786727fce0a36e65492bd Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Thu, 5 Jan 2023 09:27:41 -0700 Subject: [PATCH 04/11] nfc: Cache Topaz type and size in TopazData --- .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 5 +---- applications/main/nfc/scenes/nfc_scene_topaz_data.c | 4 +--- .../main/nfc/scenes/nfc_scene_topaz_read_success.c | 3 +-- lib/nfc/nfc_device.c | 12 ++++-------- lib/nfc/protocols/topaz.c | 12 +++++------- lib/nfc/protocols/topaz.h | 2 ++ 6 files changed, 14 insertions(+), 24 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index aee483ddc5b5..3895d10aaa0f 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -42,10 +42,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } else if(protocol == NfcDeviceProtocolMifareDesfire) { furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n"); } else if(protocol == NfcDeviceProtocolTopaz) { - furi_string_cat_printf( - temp_str, - "\e#%s\n", - nfc_topaz_type(topaz_get_type_from_hr0(dev_data->topaz_data.hr[0]))); + furi_string_cat_printf(temp_str, "\e#%s\n", nfc_topaz_type(dev_data->topaz_data.type)); } else { furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); } diff --git a/applications/main/nfc/scenes/nfc_scene_topaz_data.c b/applications/main/nfc/scenes/nfc_scene_topaz_data.c index d704454e8eb0..20b85140577c 100644 --- a/applications/main/nfc/scenes/nfc_scene_topaz_data.c +++ b/applications/main/nfc/scenes/nfc_scene_topaz_data.c @@ -4,11 +4,9 @@ void nfc_scene_topaz_data_on_enter(void* context) { Nfc* nfc = context; TopazData* data = &nfc->dev->dev_data.topaz_data; TextBox* text_box = nfc->text_box; - TopazType type = topaz_get_type_from_hr0(data->hr[0]); - size_t data_size = topaz_get_size_by_type(type); text_box_set_font(text_box, TextBoxFontHex); - for(uint16_t i = 0; i < data_size; i += 2) { + for(uint16_t i = 0; i < data->size; i += 2) { if(!(i % 8) && i) { furi_string_push_back(nfc->text_box_store, '\n'); } diff --git a/applications/main/nfc/scenes/nfc_scene_topaz_read_success.c b/applications/main/nfc/scenes/nfc_scene_topaz_read_success.c index 172f0ab98f0f..dc2940ac62be 100644 --- a/applications/main/nfc/scenes/nfc_scene_topaz_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_topaz_read_success.c @@ -27,8 +27,7 @@ void nfc_scene_topaz_read_success_on_enter(void* context) { if(furi_string_size(nfc->dev->dev_data.parsed_data)) { temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); } else { - temp_str = furi_string_alloc_printf( - "\e#%s\n", nfc_topaz_type(topaz_get_type_from_hr0(topaz_data->hr[0]))); + temp_str = furi_string_alloc_printf("\e#%s\n", nfc_topaz_type(topaz_data->type)); furi_string_cat_printf(temp_str, "UID:"); for(size_t i = 0; i < data->uid_len; i++) { furi_string_cat_printf(temp_str, " %02X", data->uid[i]); diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index fd35b3c2481c..add2b826f9e5 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -1023,15 +1023,13 @@ static bool nfc_device_save_topaz_data(FlipperFormat* file, NfcDevice* dev) { bool saved = false; TopazData* data = &dev->dev_data.topaz_data; FuriString* temp_str = furi_string_alloc(); - TopazType type = topaz_get_type_from_hr0(data->hr[0]); - size_t data_length = topaz_get_size_by_type(type); do { if(!flipper_format_write_comment_cstr(file, "Topaz-specific data")) break; if(!flipper_format_write_hex(file, "HR0", &data->hr[0], 1)) break; if(!flipper_format_write_hex(file, "HR1", &data->hr[1], 1)) break; - for(uint16_t i = 0; i < data_length; i += 8) { + for(uint16_t i = 0; i < data->size; i += 8) { furi_string_printf(temp_str, "Block %02X", i / 8); if(!flipper_format_write_hex(file, furi_string_get_cstr(temp_str), &data->data[i], 8)) break; @@ -1048,8 +1046,6 @@ static bool nfc_device_load_topaz_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; TopazData* data = &dev->dev_data.topaz_data; FuriString* temp_str = furi_string_alloc(); - TopazType type; - size_t data_length; do { if(!flipper_format_read_hex(file, "HR0", &data->hr[0], 1)) break; @@ -1060,10 +1056,10 @@ static bool nfc_device_load_topaz_data(FlipperFormat* file, NfcDevice* dev) { break; } - type = topaz_get_type_from_hr0(data->hr[0]); - data_length = topaz_get_size_by_type(type); + data->type = topaz_get_type_from_hr0(data->hr[0]); + data->size = topaz_get_size_by_type(data->type); - for(uint16_t i = 0; i < data_length; i += 8) { + for(uint16_t i = 0; i < data->size; i += 8) { furi_string_printf(temp_str, "Block %02X", i / 8); if(!flipper_format_read_hex(file, furi_string_get_cstr(temp_str), &data->data[i], 8)) break; diff --git a/lib/nfc/protocols/topaz.c b/lib/nfc/protocols/topaz.c index b3309d0d8c65..94a9962e6ec7 100644 --- a/lib/nfc/protocols/topaz.c +++ b/lib/nfc/protocols/topaz.c @@ -28,9 +28,7 @@ size_t topaz_get_size_by_type(TopazType type) { } bool topaz_read_card(FuriHalNfcTxRxContext* tx_rx, TopazData* data, uint8_t* uid) { - size_t data_size; size_t data_read = 0; - TopazType type; bool read_success = false; do { @@ -54,17 +52,17 @@ bool topaz_read_card(FuriHalNfcTxRxContext* tx_rx, TopazData* data, uint8_t* uid memcpy(data->hr, tx_rx->rx_data, sizeof(data->hr)); - type = topaz_get_type_from_hr0(data->hr[0]); - if(type == TopazTypeUnknown) { + data->type = topaz_get_type_from_hr0(data->hr[0]); + if(data->type == TopazTypeUnknown) { FURI_LOG_D(TAG, "Unknown type, HR0=%#04x", data->hr[0]); break; } - data_size = topaz_get_size_by_type(type); + data->size = topaz_get_size_by_type(data->type); memcpy(data->data, &tx_rx->rx_data[2], 120); data_read += 120; - if(data_size > TOPAZ_96_SIZE) { + if(data->size > TOPAZ_96_SIZE) { // Perform READ8 on block 0F tx_rx->tx_data[0] = TOPAZ_CMD_READ8; tx_rx->tx_data[1] = 0x0F; @@ -83,7 +81,7 @@ bool topaz_read_card(FuriHalNfcTxRxContext* tx_rx, TopazData* data, uint8_t* uid data_read += 8; // Perform RSEG for rest of tag - for(uint8_t i = 1; data_read < data_size; ++i) { + for(uint8_t i = 1; data_read < data->size; ++i) { tx_rx->tx_data[0] = TOPAZ_CMD_RSEG; tx_rx->tx_data[1] = i << 4; memset(&tx_rx->tx_data[2], 0, 8); diff --git a/lib/nfc/protocols/topaz.h b/lib/nfc/protocols/topaz.h index 6019ec11f41f..2724a9c825bf 100644 --- a/lib/nfc/protocols/topaz.h +++ b/lib/nfc/protocols/topaz.h @@ -27,6 +27,8 @@ typedef enum { } TopazType; typedef struct { + TopazType type; + size_t size; uint8_t hr[2]; uint8_t data[TOPAZ_MAX_SIZE]; } TopazData; From cf9659e8fcb6528369f03959f298fb191224f779 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Sun, 21 May 2023 17:05:17 -0600 Subject: [PATCH 05/11] nfc: Clean up Topaz read implementation --- applications/main/nfc/nfc_cli.c | 3 ++- .../main/nfc/scenes/nfc_scene_topaz_menu.c | 11 ----------- lib/nfc/protocols/topaz.c | 16 ++++++++-------- lib/nfc/protocols/topaz.h | 5 ++++- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index fb87ef0d1c96..f400fb1eeb69 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -126,7 +126,8 @@ static void nfc_cli_apdu(Cli* cli, FuriString* args) { } printf("detecting tag\r\n"); - if(!furi_hal_nfc_detect(&dev_data, 300)) { + if(!furi_hal_nfc_detect(&dev_data, 300, true) && + !furi_hal_nfc_detect(&dev_data, 300, false)) { printf("Failed to detect tag\r\n"); break; } diff --git a/applications/main/nfc/scenes/nfc_scene_topaz_menu.c b/applications/main/nfc/scenes/nfc_scene_topaz_menu.c index 7f3da14da359..de2eda25db93 100644 --- a/applications/main/nfc/scenes/nfc_scene_topaz_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_topaz_menu.c @@ -19,8 +19,6 @@ void nfc_scene_topaz_menu_on_enter(void* context) { submenu_add_item( submenu, "Save", SubmenuIndexSave, nfc_scene_topaz_menu_submenu_callback, nfc); - // submenu_add_item( - // submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_topaz_menu_submenu_callback, nfc); submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_topaz_menu_submenu_callback, nfc); @@ -41,15 +39,6 @@ bool nfc_scene_topaz_menu_on_event(void* context, SceneManagerEvent event) { nfc_device_set_name(nfc->dev, ""); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; - } else if(event.event == SubmenuIndexEmulate) { - // TODO - //scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); - } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); - } - consumed = true; } else if(event.event == SubmenuIndexInfo) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); consumed = true; diff --git a/lib/nfc/protocols/topaz.c b/lib/nfc/protocols/topaz.c index 94a9962e6ec7..71cdf877be53 100644 --- a/lib/nfc/protocols/topaz.c +++ b/lib/nfc/protocols/topaz.c @@ -59,14 +59,14 @@ bool topaz_read_card(FuriHalNfcTxRxContext* tx_rx, TopazData* data, uint8_t* uid } data->size = topaz_get_size_by_type(data->type); - memcpy(data->data, &tx_rx->rx_data[2], 120); - data_read += 120; + memcpy(data->data, &tx_rx->rx_data[2], TOPAZ_BYTES_RALL); + data_read += TOPAZ_BYTES_RALL; if(data->size > TOPAZ_96_SIZE) { // Perform READ8 on block 0F tx_rx->tx_data[0] = TOPAZ_CMD_READ8; tx_rx->tx_data[1] = 0x0F; - memset(&tx_rx->tx_data[2], 0, 8); + memset(&tx_rx->tx_data[2], 0, TOPAZ_BYTES_PER_BLOCK); memcpy(&tx_rx->tx_data[10], uid, 4); tx_rx->tx_bits = 14 * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; @@ -77,14 +77,14 @@ bool topaz_read_card(FuriHalNfcTxRxContext* tx_rx, TopazData* data, uint8_t* uid break; } - memcpy(&data->data[data_read], &tx_rx->rx_data[1], 8); - data_read += 8; + memcpy(&data->data[data_read], &tx_rx->rx_data[1], TOPAZ_BYTES_PER_BLOCK); + data_read += TOPAZ_BYTES_PER_BLOCK; // Perform RSEG for rest of tag for(uint8_t i = 1; data_read < data->size; ++i) { tx_rx->tx_data[0] = TOPAZ_CMD_RSEG; tx_rx->tx_data[1] = i << 4; - memset(&tx_rx->tx_data[2], 0, 8); + memset(&tx_rx->tx_data[2], 0, TOPAZ_BYTES_PER_BLOCK); memcpy(&tx_rx->tx_data[10], uid, 4); tx_rx->tx_bits = 14 * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; @@ -95,8 +95,8 @@ bool topaz_read_card(FuriHalNfcTxRxContext* tx_rx, TopazData* data, uint8_t* uid break; } - memcpy(&data->data[data_read], &tx_rx->rx_data[1], 128); - data_read += 128; + memcpy(&data->data[data_read], &tx_rx->rx_data[1], TOPAZ_BYTES_PER_SECTOR); + data_read += TOPAZ_BYTES_PER_SECTOR; } } diff --git a/lib/nfc/protocols/topaz.h b/lib/nfc/protocols/topaz.h index 2724a9c825bf..7a074b7d9254 100644 --- a/lib/nfc/protocols/topaz.h +++ b/lib/nfc/protocols/topaz.h @@ -4,6 +4,9 @@ #define TOPAZ_MAX_SIZE (512) #define TOPAZ_UID_FULL_LENGTH (7) +#define TOPAZ_BYTES_PER_BLOCK (8) +#define TOPAZ_BYTES_PER_SECTOR (TOPAZ_BYTES_PER_BLOCK * 16) +#define TOPAZ_BYTES_RALL (120) #define TOPAZ_CMD_RID (0x78) #define TOPAZ_CMD_RALL (0x00) @@ -16,7 +19,7 @@ #define TOPAZ_CMD_WRITE_NE8 (0x1B) #define TOPAZ_96_HR0 (0x11) -#define TOPAZ_96_SIZE (96) +#define TOPAZ_96_SIZE (120) #define TOPAZ_512_HR0 (0x12) #define TOPAZ_512_SIZE (512) From 9a3caf5d3631c984eb7ce78cfdf1485f5bd7faf3 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Sun, 21 May 2023 20:28:46 -0600 Subject: [PATCH 06/11] nfc: Add Topaz to type on delete screen --- applications/main/nfc/scenes/nfc_scene_delete.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applications/main/nfc/scenes/nfc_scene_delete.c b/applications/main/nfc/scenes/nfc_scene_delete.c index cbb52bfd0f2b..c6326b928344 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete.c +++ b/applications/main/nfc/scenes/nfc_scene_delete.c @@ -39,6 +39,8 @@ void nfc_scene_delete_on_enter(void* context) { furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { furi_string_set(temp_str, "MIFARE DESFire"); + } else if(protocol == NfcDeviceProtocolTopaz) { + furi_string_set(temp_str, nfc_topaz_type(nfc->dev->dev_data.topaz_data.type)); } else { furi_string_set(temp_str, "Unknown ISO tag"); } From e5f9fe18b11308a943a99155d16550c15b8be52d Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Mon, 22 May 2023 09:19:16 -0600 Subject: [PATCH 07/11] Bump API symbols --- firmware/targets/f7/api_symbols.csv | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index e2bedffb7d25..36567c748857 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,26.3,, +Version,+,27.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1204,7 +1204,7 @@ Function,+,furi_hal_mpu_protect_no_access,void,"FuriHalMpuRegion, uint32_t, Furi Function,+,furi_hal_mpu_protect_read_only,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" Function,+,furi_hal_nfc_activate_nfca,_Bool,"uint32_t, uint32_t*" Function,-,furi_hal_nfc_deinit,void, -Function,+,furi_hal_nfc_detect,_Bool,"FuriHalNfcDevData*, uint32_t" +Function,+,furi_hal_nfc_detect,_Bool,"FuriHalNfcDevData*, uint32_t, _Bool" Function,+,furi_hal_nfc_emulate_nfca,_Bool,"uint8_t*, uint8_t, uint8_t*, uint8_t, FuriHalNfcEmulateCallback, void*, uint32_t" Function,+,furi_hal_nfc_exit_sleep,void, Function,+,furi_hal_nfc_field_off,void, @@ -2821,6 +2821,10 @@ Function,-,toascii,int,int Function,-,toascii_l,int,"int, locale_t" Function,-,tolower,int,int Function,-,tolower_l,int,"int, locale_t" +Function,-,topaz_check_card_type,_Bool,"uint8_t, uint8_t" +Function,-,topaz_get_size_by_type,size_t,TopazType +Function,-,topaz_get_type_from_hr0,TopazType,uint8_t +Function,-,topaz_read_card,_Bool,"FuriHalNfcTxRxContext*, TopazData*, uint8_t*" Function,-,toupper,int,int Function,-,toupper_l,int,"int, locale_t" Function,-,trunc,double,double From ac2a30d0890035b8aa330e55468d4d188fcf98a0 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Wed, 24 May 2023 14:29:04 -0600 Subject: [PATCH 08/11] Sync API version --- firmware/targets/f18/api_symbols.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index ee1ae115423e..b7abdfc05024 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,26.3,, +Version,+,27.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, From af7b14ceb293e32381639081b3a6e11415b16c04 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Thu, 25 May 2023 10:27:35 -0600 Subject: [PATCH 09/11] nfc: Remove currently unused enum item --- applications/main/nfc/scenes/nfc_scene_topaz_menu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/main/nfc/scenes/nfc_scene_topaz_menu.c b/applications/main/nfc/scenes/nfc_scene_topaz_menu.c index de2eda25db93..2f0c5f847774 100644 --- a/applications/main/nfc/scenes/nfc_scene_topaz_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_topaz_menu.c @@ -3,7 +3,6 @@ enum SubmenuIndex { SubmenuIndexSave, - SubmenuIndexEmulate, SubmenuIndexInfo, }; From 14740f0b9ab16e0a8972457cab7cfc719dda99c1 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Mon, 26 Jun 2023 10:42:25 -0600 Subject: [PATCH 10/11] Fix updated dolphin_deed --- applications/main/nfc/scenes/nfc_scene_read.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 8adfaf385e3f..b16f5eeb20e3 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -93,7 +93,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { } else if(event.event == NfcWorkerEventReadTopaz) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneTopazReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { From 128fb24ab6fdfdc4aadef545c8bddb7f66f65e05 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Mon, 26 Jun 2023 10:46:29 -0600 Subject: [PATCH 11/11] nfc: Fix nfcv call for furi_hal_nfc_detect --- lib/nfc/nfc_worker.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 1d48c9eddb47..8cde94fd3d5e 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -141,7 +141,9 @@ static bool nfc_worker_read_nfcv(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* t } do { - if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break; + if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200, true) && + !furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200, false)) + break; if(!nfcv_read_card(&reader, nfc_data, nfcv_data)) break; read_success = true;