diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index c511e9dcbfe..e7a494d273a 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -19,7 +19,7 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { Submenu* submenu = nfc->submenu; MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; - if(!mf_ul_is_full_capture(data)) { + if(!mf_ul_is_full_capture(data) && data->type != MfUltralightTypeULC) { submenu_add_item( submenu, "Unlock", @@ -29,12 +29,14 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { } submenu_add_item( submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); - submenu_add_item( - submenu, - "Emulate", - SubmenuIndexEmulate, - nfc_scene_mf_ultralight_menu_submenu_callback, - nfc); + if(mf_ul_emulation_supported(data)) { + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexEmulate, + nfc_scene_mf_ultralight_menu_submenu_callback, + nfc); + } submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index ba1f9653984..e45dc4eb7dd 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -42,7 +42,8 @@ void nfc_scene_saved_menu_on_enter(void* context) { nfc); } } else if( - nfc->dev->format == NfcDeviceSaveFormatMifareUl || + (nfc->dev->format == NfcDeviceSaveFormatMifareUl && + mf_ul_emulation_supported(&nfc->dev->dev_data.mf_ul_data)) || nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); @@ -72,6 +73,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); if(nfc->dev->format == NfcDeviceSaveFormatMifareUl && + nfc->dev->dev_data.mf_ul_data.type != MfUltralightTypeULC && !mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) { submenu_add_item( submenu, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index aebfc9072be..ccbaa531765 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2013,6 +2013,7 @@ Function,-,mf_df_prepare_read_records,uint16_t,"uint8_t*, uint8_t, uint32_t, uin Function,-,mf_df_prepare_select_application,uint16_t,"uint8_t*, uint8_t[3]" Function,-,mf_df_read_card,_Bool,"FuriHalNfcTxRxContext*, MifareDesfireData*" Function,-,mf_ul_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" +Function,-,mf_ul_emulation_supported,_Bool,MfUltralightData* Function,-,mf_ul_is_full_capture,_Bool,MfUltralightData* Function,-,mf_ul_prepare_emulation,void,"MfUltralightEmulator*, MfUltralightData*" Function,-,mf_ul_prepare_emulation_response,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*, uint32_t*, void*" diff --git a/lib/nfc/nfc_types.c b/lib/nfc/nfc_types.c index 02ca85580db..96b92640f0e 100644 --- a/lib/nfc/nfc_types.c +++ b/lib/nfc/nfc_types.c @@ -45,6 +45,8 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { return "NTAG I2C Plus 2K"; } else if(type == MfUltralightTypeNTAG203) { return "NTAG203"; + } else if(type == MfUltralightTypeULC) { + return "Mifare Ultralight C"; } else if(type == MfUltralightTypeUL11 && full_name) { return "Mifare Ultralight 11"; } else if(type == MfUltralightTypeUL21 && full_name) { diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index 6960bd2a180..266b6e2e2e4 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -79,6 +79,8 @@ static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) { MfUltralightSupportSectorSelect; case MfUltralightTypeNTAG203: return MfUltralightSupportCompatWrite | MfUltralightSupportCounterInMemory; + case MfUltralightTypeULC: + return MfUltralightSupportCompatWrite | MfUltralightSupport3DesAuth; default: // Assumed original MFUL 512-bit return MfUltralightSupportCompatWrite; @@ -95,6 +97,11 @@ static void mf_ul_set_version_ntag203(MfUltralightReader* reader, MfUltralightDa reader->pages_to_read = 42; } +static void mf_ul_set_version_ulc(MfUltralightReader* reader, MfUltralightData* data) { + data->type = MfUltralightTypeULC; + reader->pages_to_read = 48; +} + bool mf_ultralight_read_version( FuriHalNfcTxRxContext* tx_rx, MfUltralightReader* reader, @@ -175,7 +182,7 @@ bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint do { FURI_LOG_D(TAG, "Authenticating"); - tx_rx->tx_data[0] = MF_UL_AUTH; + tx_rx->tx_data[0] = MF_UL_PWD_AUTH; nfc_util_num2bytes(key, 4, &tx_rx->tx_data[1]); tx_rx->tx_bits = 40; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; @@ -716,6 +723,21 @@ bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralight return flag_read == 2; } +static bool mf_ul_probe_3des_auth(FuriHalNfcTxRxContext* tx_rx) { + tx_rx->tx_data[0] = MF_UL_AUTHENTICATE_1; + tx_rx->tx_data[1] = 0; + tx_rx->tx_bits = 16; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + bool rc = furi_hal_nfc_tx_rx(tx_rx, 50) && tx_rx->rx_bits == 9 * 8 && + tx_rx->rx_data[0] == 0xAF; + + // Reset just in case, we're not going to finish authenticating and need to if tag doesn't support auth + furi_hal_nfc_sleep(); + furi_hal_nfc_activate_nfca(300, NULL); + + return rc; +} + bool mf_ul_read_card( FuriHalNfcTxRxContext* tx_rx, MfUltralightReader* reader, @@ -733,16 +755,20 @@ bool mf_ul_read_card( mf_ultralight_read_signature(tx_rx, data); } } else { - // No GET_VERSION command, check for NTAG203 by reading last page (41) uint8_t dummy[16]; - if(mf_ultralight_read_pages_direct(tx_rx, 41, dummy)) { + // No GET_VERSION command, check if AUTHENTICATE command available (detect UL C). + if(mf_ul_probe_3des_auth(tx_rx)) { + mf_ul_set_version_ulc(reader, data); + } else if(mf_ultralight_read_pages_direct(tx_rx, 41, dummy)) { + // No AUTHENTICATE, check for NTAG203 by reading last page (41) mf_ul_set_version_ntag203(reader, data); - reader->supported_features = mf_ul_get_features(data->type); } else { // We're really an original Mifare Ultralight, reset tag for safety furi_hal_nfc_sleep(); furi_hal_nfc_activate_nfca(300, NULL); } + + reader->supported_features = mf_ul_get_features(data->type); } card_read = mf_ultralight_read_pages(tx_rx, reader, data); @@ -1228,6 +1254,10 @@ static void mf_ul_emulate_write( emulator->data_changed = true; } +bool mf_ul_emulation_supported(MfUltralightData* data) { + return data->type != MfUltralightTypeULC; +} + void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) { emulator->comp_write_cmd_started = false; emulator->sector_select_cmd_started = false; @@ -1732,7 +1762,7 @@ bool mf_ul_prepare_emulation_response( } } } - } else if(cmd == MF_UL_AUTH) { + } else if(cmd == MF_UL_PWD_AUTH) { if(emulator->supported_features & MfUltralightSupportAuth) { if(buff_rx_len == (1 + 4) * 8) { // Record password sent by PCD diff --git a/lib/nfc/protocols/mifare_ultralight.h b/lib/nfc/protocols/mifare_ultralight.h index 4ab22e89cb8..d444fa7983e 100644 --- a/lib/nfc/protocols/mifare_ultralight.h +++ b/lib/nfc/protocols/mifare_ultralight.h @@ -16,7 +16,8 @@ #define MF_UL_COMP_WRITE (0xA0) #define MF_UL_READ_CNT (0x39) #define MF_UL_INC_CNT (0xA5) -#define MF_UL_AUTH (0x1B) +#define MF_UL_AUTHENTICATE_1 (0x1A) +#define MF_UL_PWD_AUTH (0x1B) #define MF_UL_READ_SIG (0x3C) #define MF_UL_CHECK_TEARING (0x3E) #define MF_UL_READ_VCSL (0x4B) @@ -41,6 +42,7 @@ typedef enum { typedef enum { MfUltralightTypeUnknown, MfUltralightTypeNTAG203, + MfUltralightTypeULC, // Below have config pages and GET_VERSION support MfUltralightTypeUL11, MfUltralightTypeUL21, @@ -77,6 +79,7 @@ typedef enum { MfUltralightSupportAsciiMirror = 1 << 11, // NTAG203 counter that's in memory rather than through a command MfUltralightSupportCounterInMemory = 1 << 12, + MfUltralightSupport3DesAuth = 1 << 13, } MfUltralightFeatures; typedef enum { @@ -237,6 +240,8 @@ bool mf_ul_read_card( MfUltralightReader* reader, MfUltralightData* data); +bool mf_ul_emulation_supported(MfUltralightData* data); + void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle); void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data);