nfc: Mifare Ultralight C detection (#2668)
* nfc: Add Mifare Ultralight C detection
* nfc: Add display name for MFUL C and hide menu items
    MFUL C unlock and emulation currently not supported, so hide from menu
    if current card is MFUL C
* nfc: Also check response when probing 3DES auth
* nfc: Hide emulate option in saved menu for MFUL if not supported
* nfc: Remove unlock options from saved menu if Ultralight C
Co-authored-by: gornekich <n.gorbadey@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
			
			
This commit is contained in:
		
							parent
							
								
									cce0485e75
								
							
						
					
					
						commit
						5f52382098
					
				| @ -19,7 +19,7 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { | |||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
|     MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; |     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_add_item( | ||||||
|             submenu, |             submenu, | ||||||
|             "Unlock", |             "Unlock", | ||||||
| @ -29,12 +29,14 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { | |||||||
|     } |     } | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); |         submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); | ||||||
|     submenu_add_item( |     if(mf_ul_emulation_supported(data)) { | ||||||
|         submenu, |         submenu_add_item( | ||||||
|         "Emulate", |             submenu, | ||||||
|         SubmenuIndexEmulate, |             "Emulate", | ||||||
|         nfc_scene_mf_ultralight_menu_submenu_callback, |             SubmenuIndexEmulate, | ||||||
|         nfc); |             nfc_scene_mf_ultralight_menu_submenu_callback, | ||||||
|  |             nfc); | ||||||
|  |     } | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); |         submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -42,7 +42,8 @@ void nfc_scene_saved_menu_on_enter(void* context) { | |||||||
|                 nfc); |                 nfc); | ||||||
|         } |         } | ||||||
|     } else if( |     } 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) { |         nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); |             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_add_item( | ||||||
|         submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); |         submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); | ||||||
|     if(nfc->dev->format == NfcDeviceSaveFormatMifareUl && |     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)) { |        !mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) { | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, |             submenu, | ||||||
|  | |||||||
| @ -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_prepare_select_application,uint16_t,"uint8_t*, uint8_t[3]" | ||||||
| Function,-,mf_df_read_card,_Bool,"FuriHalNfcTxRxContext*, MifareDesfireData*" | Function,-,mf_df_read_card,_Bool,"FuriHalNfcTxRxContext*, MifareDesfireData*" | ||||||
| Function,-,mf_ul_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" | 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_is_full_capture,_Bool,MfUltralightData* | ||||||
| Function,-,mf_ul_prepare_emulation,void,"MfUltralightEmulator*, 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*" | Function,-,mf_ul_prepare_emulation_response,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*, uint32_t*, void*" | ||||||
|  | |||||||
| 
 | 
| @ -45,6 +45,8 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { | |||||||
|         return "NTAG I2C Plus 2K"; |         return "NTAG I2C Plus 2K"; | ||||||
|     } else if(type == MfUltralightTypeNTAG203) { |     } else if(type == MfUltralightTypeNTAG203) { | ||||||
|         return "NTAG203"; |         return "NTAG203"; | ||||||
|  |     } else if(type == MfUltralightTypeULC) { | ||||||
|  |         return "Mifare Ultralight C"; | ||||||
|     } else if(type == MfUltralightTypeUL11 && full_name) { |     } else if(type == MfUltralightTypeUL11 && full_name) { | ||||||
|         return "Mifare Ultralight 11"; |         return "Mifare Ultralight 11"; | ||||||
|     } else if(type == MfUltralightTypeUL21 && full_name) { |     } else if(type == MfUltralightTypeUL21 && full_name) { | ||||||
|  | |||||||
| @ -79,6 +79,8 @@ static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) { | |||||||
|                MfUltralightSupportSectorSelect; |                MfUltralightSupportSectorSelect; | ||||||
|     case MfUltralightTypeNTAG203: |     case MfUltralightTypeNTAG203: | ||||||
|         return MfUltralightSupportCompatWrite | MfUltralightSupportCounterInMemory; |         return MfUltralightSupportCompatWrite | MfUltralightSupportCounterInMemory; | ||||||
|  |     case MfUltralightTypeULC: | ||||||
|  |         return MfUltralightSupportCompatWrite | MfUltralightSupport3DesAuth; | ||||||
|     default: |     default: | ||||||
|         // Assumed original MFUL 512-bit
 |         // Assumed original MFUL 512-bit
 | ||||||
|         return MfUltralightSupportCompatWrite; |         return MfUltralightSupportCompatWrite; | ||||||
| @ -95,6 +97,11 @@ static void mf_ul_set_version_ntag203(MfUltralightReader* reader, MfUltralightDa | |||||||
|     reader->pages_to_read = 42; |     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( | bool mf_ultralight_read_version( | ||||||
|     FuriHalNfcTxRxContext* tx_rx, |     FuriHalNfcTxRxContext* tx_rx, | ||||||
|     MfUltralightReader* reader, |     MfUltralightReader* reader, | ||||||
| @ -175,7 +182,7 @@ bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint | |||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         FURI_LOG_D(TAG, "Authenticating"); |         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]); |         nfc_util_num2bytes(key, 4, &tx_rx->tx_data[1]); | ||||||
|         tx_rx->tx_bits = 40; |         tx_rx->tx_bits = 40; | ||||||
|         tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; |         tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; | ||||||
| @ -716,6 +723,21 @@ bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralight | |||||||
|     return flag_read == 2; |     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( | bool mf_ul_read_card( | ||||||
|     FuriHalNfcTxRxContext* tx_rx, |     FuriHalNfcTxRxContext* tx_rx, | ||||||
|     MfUltralightReader* reader, |     MfUltralightReader* reader, | ||||||
| @ -733,16 +755,20 @@ bool mf_ul_read_card( | |||||||
|             mf_ultralight_read_signature(tx_rx, data); |             mf_ultralight_read_signature(tx_rx, data); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         // No GET_VERSION command, check for NTAG203 by reading last page (41)
 |  | ||||||
|         uint8_t dummy[16]; |         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); |             mf_ul_set_version_ntag203(reader, data); | ||||||
|             reader->supported_features = mf_ul_get_features(data->type); |  | ||||||
|         } else { |         } else { | ||||||
|             // We're really an original Mifare Ultralight, reset tag for safety
 |             // We're really an original Mifare Ultralight, reset tag for safety
 | ||||||
|             furi_hal_nfc_sleep(); |             furi_hal_nfc_sleep(); | ||||||
|             furi_hal_nfc_activate_nfca(300, NULL); |             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); |     card_read = mf_ultralight_read_pages(tx_rx, reader, data); | ||||||
| @ -1228,6 +1254,10 @@ static void mf_ul_emulate_write( | |||||||
|     emulator->data_changed = true; |     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) { | void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) { | ||||||
|     emulator->comp_write_cmd_started = false; |     emulator->comp_write_cmd_started = false; | ||||||
|     emulator->sector_select_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(emulator->supported_features & MfUltralightSupportAuth) { | ||||||
|                 if(buff_rx_len == (1 + 4) * 8) { |                 if(buff_rx_len == (1 + 4) * 8) { | ||||||
|                     // Record password sent by PCD
 |                     // Record password sent by PCD
 | ||||||
|  | |||||||
| @ -16,7 +16,8 @@ | |||||||
| #define MF_UL_COMP_WRITE (0xA0) | #define MF_UL_COMP_WRITE (0xA0) | ||||||
| #define MF_UL_READ_CNT (0x39) | #define MF_UL_READ_CNT (0x39) | ||||||
| #define MF_UL_INC_CNT (0xA5) | #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_READ_SIG (0x3C) | ||||||
| #define MF_UL_CHECK_TEARING (0x3E) | #define MF_UL_CHECK_TEARING (0x3E) | ||||||
| #define MF_UL_READ_VCSL (0x4B) | #define MF_UL_READ_VCSL (0x4B) | ||||||
| @ -41,6 +42,7 @@ typedef enum { | |||||||
| typedef enum { | typedef enum { | ||||||
|     MfUltralightTypeUnknown, |     MfUltralightTypeUnknown, | ||||||
|     MfUltralightTypeNTAG203, |     MfUltralightTypeNTAG203, | ||||||
|  |     MfUltralightTypeULC, | ||||||
|     // Below have config pages and GET_VERSION support
 |     // Below have config pages and GET_VERSION support
 | ||||||
|     MfUltralightTypeUL11, |     MfUltralightTypeUL11, | ||||||
|     MfUltralightTypeUL21, |     MfUltralightTypeUL21, | ||||||
| @ -77,6 +79,7 @@ typedef enum { | |||||||
|     MfUltralightSupportAsciiMirror = 1 << 11, |     MfUltralightSupportAsciiMirror = 1 << 11, | ||||||
|     // NTAG203 counter that's in memory rather than through a command
 |     // NTAG203 counter that's in memory rather than through a command
 | ||||||
|     MfUltralightSupportCounterInMemory = 1 << 12, |     MfUltralightSupportCounterInMemory = 1 << 12, | ||||||
|  |     MfUltralightSupport3DesAuth = 1 << 13, | ||||||
| } MfUltralightFeatures; | } MfUltralightFeatures; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -237,6 +240,8 @@ bool mf_ul_read_card( | |||||||
|     MfUltralightReader* reader, |     MfUltralightReader* reader, | ||||||
|     MfUltralightData* data); |     MfUltralightData* data); | ||||||
| 
 | 
 | ||||||
|  | bool mf_ul_emulation_supported(MfUltralightData* data); | ||||||
|  | 
 | ||||||
| void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle); | void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle); | ||||||
| 
 | 
 | ||||||
| void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data); | void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Yukai Li
						Yukai Li