nfc: NTAG203 support (#1383)
* nfc: Fix original MFUL feature flags * nfc: Add NTAG203 read support * nfc: Update emulation lock byte handling for NTAG203 * nfc: Add NTAG203 counter emulation support * nfc: Add NTAG203 tag generator * nfc: Fix NTAG203 emulating GET_VERSION * nfc: Fix MFUL version reading * nfc: Complete NTAG203 counter emulation behavior * nfc: Complete NTAG203 emulation * nfc: Remove unnecessary init in MFUL emulation * nfc: Add notes about MFUL type enum Co-authored-by: gornekich <n.gorbadey@gmail.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									30820b83b5
								
							
						
					
					
						commit
						f8e0ec42c5
					
				| @ -6,6 +6,8 @@ | |||||||
| static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03}; | static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03}; | ||||||
| static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03}; | static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03}; | ||||||
| static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03}; | static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03}; | ||||||
|  | static const uint8_t default_data_ntag203[] = | ||||||
|  |     {0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE}; | ||||||
| static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE}; | static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE}; | ||||||
| static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE}; | static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE}; | ||||||
| static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE}; | static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE}; | ||||||
| @ -58,6 +60,18 @@ static void nfc_generate_mf_ul_orig(NfcDeviceData* data) { | |||||||
|     memset(&mful->data[4 * 4], 0xFF, 4); |     memset(&mful->data[4 * 4], 0xFF, 4); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) { | ||||||
|  |     nfc_generate_common_start(data); | ||||||
|  |     nfc_generate_mf_ul_common(data); | ||||||
|  | 
 | ||||||
|  |     MfUltralightData* mful = &data->mf_ul_data; | ||||||
|  |     mful->type = MfUltralightTypeNTAG203; | ||||||
|  |     mful->data_size = 42 * 4; | ||||||
|  |     nfc_generate_mf_ul_copy_uid_with_bcc(data); | ||||||
|  |     mful->data[9] = 0x48; // Internal byte
 | ||||||
|  |     memcpy(&mful->data[3 * 4], default_data_ntag203, sizeof(default_data_ntag203)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t num_pages) { | static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t num_pages) { | ||||||
|     nfc_generate_common_start(data); |     nfc_generate_common_start(data); | ||||||
|     nfc_generate_mf_ul_common(data); |     nfc_generate_mf_ul_common(data); | ||||||
| @ -275,6 +289,11 @@ static const NfcGenerator mf_ul_h21_generator = { | |||||||
|     .generator_func = nfc_generate_mf_ul_h21, |     .generator_func = nfc_generate_mf_ul_h21, | ||||||
|     .next_scene = NfcSceneMifareUlMenu}; |     .next_scene = NfcSceneMifareUlMenu}; | ||||||
| 
 | 
 | ||||||
|  | static const NfcGenerator ntag203_generator = { | ||||||
|  |     .name = "NTAG203", | ||||||
|  |     .generator_func = nfc_generate_mf_ul_ntag203, | ||||||
|  |     .next_scene = NfcSceneMifareUlMenu}; | ||||||
|  | 
 | ||||||
| static const NfcGenerator ntag213_generator = { | static const NfcGenerator ntag213_generator = { | ||||||
|     .name = "NTAG213", |     .name = "NTAG213", | ||||||
|     .generator_func = nfc_generate_ntag213, |     .generator_func = nfc_generate_ntag213, | ||||||
| @ -316,6 +335,7 @@ const NfcGenerator* const nfc_generators[] = { | |||||||
|     &mf_ul_h11_generator, |     &mf_ul_h11_generator, | ||||||
|     &mf_ul_21_generator, |     &mf_ul_21_generator, | ||||||
|     &mf_ul_h21_generator, |     &mf_ul_h21_generator, | ||||||
|  |     &ntag203_generator, | ||||||
|     &ntag213_generator, |     &ntag213_generator, | ||||||
|     &ntag215_generator, |     &ntag215_generator, | ||||||
|     &ntag216_generator, |     &ntag216_generator, | ||||||
|  | |||||||
| @ -43,6 +43,8 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { | |||||||
|         return "NTAG I2C Plus 1K"; |         return "NTAG I2C Plus 1K"; | ||||||
|     } else if(type == MfUltralightTypeNTAGI2CPlus2K) { |     } else if(type == MfUltralightTypeNTAGI2CPlus2K) { | ||||||
|         return "NTAG I2C Plus 2K"; |         return "NTAG I2C Plus 2K"; | ||||||
|  |     } else if(type == MfUltralightTypeNTAG203) { | ||||||
|  |         return "NTAG203"; | ||||||
|     } 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) { | ||||||
|  | |||||||
| @ -35,9 +35,11 @@ static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) { | |||||||
|         return MfUltralightSupportFastRead | MfUltralightSupportAuth | |         return MfUltralightSupportFastRead | MfUltralightSupportAuth | | ||||||
|                MfUltralightSupportFastWrite | MfUltralightSupportSignature | |                MfUltralightSupportFastWrite | MfUltralightSupportSignature | | ||||||
|                MfUltralightSupportSectorSelect; |                MfUltralightSupportSectorSelect; | ||||||
|  |     case MfUltralightTypeNTAG203: | ||||||
|  |         return MfUltralightSupportCompatWrite | MfUltralightSupportCounterInMemory; | ||||||
|     default: |     default: | ||||||
|         // Assumed original MFUL 512-bit
 |         // Assumed original MFUL 512-bit
 | ||||||
|         return MfUltralightSupportNone; |         return MfUltralightSupportCompatWrite; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -46,6 +48,11 @@ static void mf_ul_set_default_version(MfUltralightReader* reader, MfUltralightDa | |||||||
|     reader->pages_to_read = 16; |     reader->pages_to_read = 16; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void mf_ul_set_version_ntag203(MfUltralightReader* reader, MfUltralightData* data) { | ||||||
|  |     data->type = MfUltralightTypeNTAG203; | ||||||
|  |     reader->pages_to_read = 42; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool mf_ultralight_read_version( | bool mf_ultralight_read_version( | ||||||
|     FuriHalNfcTxRxContext* tx_rx, |     FuriHalNfcTxRxContext* tx_rx, | ||||||
|     MfUltralightReader* reader, |     MfUltralightReader* reader, | ||||||
| @ -57,7 +64,7 @@ bool mf_ultralight_read_version( | |||||||
|         tx_rx->tx_data[0] = MF_UL_GET_VERSION_CMD; |         tx_rx->tx_data[0] = MF_UL_GET_VERSION_CMD; | ||||||
|         tx_rx->tx_bits = 8; |         tx_rx->tx_bits = 8; | ||||||
|         tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; |         tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; | ||||||
|         if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { |         if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits != 64) { | ||||||
|             FURI_LOG_D(TAG, "Failed reading version"); |             FURI_LOG_D(TAG, "Failed reading version"); | ||||||
|             mf_ul_set_default_version(reader, data); |             mf_ul_set_default_version(reader, data); | ||||||
|             furi_hal_nfc_sleep(); |             furi_hal_nfc_sleep(); | ||||||
| @ -468,6 +475,23 @@ static bool mf_ultralight_sector_select(FuriHalNfcTxRxContext* tx_rx, uint8_t se | |||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool mf_ultralight_read_pages_direct( | ||||||
|  |     FuriHalNfcTxRxContext* tx_rx, | ||||||
|  |     uint8_t start_index, | ||||||
|  |     uint8_t* data) { | ||||||
|  |     FURI_LOG_D(TAG, "Reading pages %d - %d", start_index, start_index + 3); | ||||||
|  |     tx_rx->tx_data[0] = MF_UL_READ_CMD; | ||||||
|  |     tx_rx->tx_data[1] = start_index; | ||||||
|  |     tx_rx->tx_bits = 16; | ||||||
|  |     tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; | ||||||
|  |     if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits < 16 * 8) { | ||||||
|  |         FURI_LOG_D(TAG, "Failed to read pages %d - %d", start_index, start_index + 3); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     memcpy(data, tx_rx->rx_data, 16); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool mf_ultralight_read_pages( | bool mf_ultralight_read_pages( | ||||||
|     FuriHalNfcTxRxContext* tx_rx, |     FuriHalNfcTxRxContext* tx_rx, | ||||||
|     MfUltralightReader* reader, |     MfUltralightReader* reader, | ||||||
| @ -632,6 +656,17 @@ bool mf_ul_read_card( | |||||||
|             // Read Signature
 |             // Read Signature
 | ||||||
|             mf_ultralight_read_signature(tx_rx, data); |             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)) { | ||||||
|  |             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); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     card_read = mf_ultralight_read_pages(tx_rx, reader, data); |     card_read = mf_ultralight_read_pages(tx_rx, reader, data); | ||||||
| @ -772,6 +807,8 @@ static bool mf_ul_ntag_i2c_plus_check_auth( | |||||||
| 
 | 
 | ||||||
| static int16_t mf_ul_get_dynamic_lock_page_addr(MfUltralightData* data) { | static int16_t mf_ul_get_dynamic_lock_page_addr(MfUltralightData* data) { | ||||||
|     switch(data->type) { |     switch(data->type) { | ||||||
|  |     case MfUltralightTypeNTAG203: | ||||||
|  |         return 0x28; | ||||||
|     case MfUltralightTypeUL21: |     case MfUltralightTypeUL21: | ||||||
|     case MfUltralightTypeNTAG213: |     case MfUltralightTypeNTAG213: | ||||||
|     case MfUltralightTypeNTAG215: |     case MfUltralightTypeNTAG215: | ||||||
| @ -804,6 +841,10 @@ static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) | |||||||
| 
 | 
 | ||||||
|     // Check max page
 |     // Check max page
 | ||||||
|     switch(emulator->data.type) { |     switch(emulator->data.type) { | ||||||
|  |     case MfUltralightTypeNTAG203: | ||||||
|  |         // Counter page can be locked and is after dynamic locks
 | ||||||
|  |         if(write_page == 40) return true; | ||||||
|  |         break; | ||||||
|     case MfUltralightTypeUL21: |     case MfUltralightTypeUL21: | ||||||
|     case MfUltralightTypeNTAG213: |     case MfUltralightTypeNTAG213: | ||||||
|     case MfUltralightTypeNTAG215: |     case MfUltralightTypeNTAG215: | ||||||
| @ -841,6 +882,19 @@ static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) | |||||||
| 
 | 
 | ||||||
|     switch(emulator->data.type) { |     switch(emulator->data.type) { | ||||||
|     // low byte LSB range, MSB range
 |     // low byte LSB range, MSB range
 | ||||||
|  |     case MfUltralightTypeNTAG203: | ||||||
|  |         if(write_page >= 16 && write_page <= 27) | ||||||
|  |             shift = (write_page - 16) / 4 + 1; | ||||||
|  |         else if(write_page >= 28 && write_page <= 39) | ||||||
|  |             shift = (write_page - 28) / 4 + 5; | ||||||
|  |         else if(write_page == 41) | ||||||
|  |             shift = 12; | ||||||
|  |         else { | ||||||
|  |             furi_assert(false); | ||||||
|  |             shift = 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         break; | ||||||
|     case MfUltralightTypeUL21: |     case MfUltralightTypeUL21: | ||||||
|     case MfUltralightTypeNTAG213: |     case MfUltralightTypeNTAG213: | ||||||
|         // 16-17, 30-31
 |         // 16-17, 30-31
 | ||||||
| @ -937,6 +991,42 @@ static void mf_ul_increment_single_counter(MfUltralightEmulator* emulator) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool | ||||||
|  |     mf_ul_emulate_ntag203_counter_write(MfUltralightEmulator* emulator, uint8_t* page_buff) { | ||||||
|  |     // We'll reuse the existing counters for other NTAGs as staging
 | ||||||
|  |     // Counter 0 stores original value, data is new value
 | ||||||
|  |     uint32_t counter_value; | ||||||
|  |     if(emulator->data.tearing[0] == MF_UL_TEARING_FLAG_DEFAULT) { | ||||||
|  |         counter_value = emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] | | ||||||
|  |                         (emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] << 8); | ||||||
|  |     } else { | ||||||
|  |         // We've had a reset here, so load from original value
 | ||||||
|  |         counter_value = emulator->data.counter[0]; | ||||||
|  |     } | ||||||
|  |     // Although the datasheet says increment by 0 is always possible, this is not the case on
 | ||||||
|  |     // an actual tag. If the counter is at 0xFFFF, any writes are locked out.
 | ||||||
|  |     if(counter_value == 0xFFFF) return false; | ||||||
|  |     uint32_t increment = page_buff[0] | (page_buff[1] << 8); | ||||||
|  |     if(counter_value == 0) { | ||||||
|  |         counter_value = increment; | ||||||
|  |     } else { | ||||||
|  |         // Per datasheet specifying > 0x000F is supposed to NAK, but actual tag doesn't
 | ||||||
|  |         increment &= 0x000F; | ||||||
|  |         if(counter_value + increment > 0xFFFF) return false; | ||||||
|  |         counter_value += increment; | ||||||
|  |     } | ||||||
|  |     // Commit to new value counter
 | ||||||
|  |     emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] = (uint8_t)counter_value; | ||||||
|  |     emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] = (uint8_t)(counter_value >> 8); | ||||||
|  |     emulator->data.tearing[0] = MF_UL_TEARING_FLAG_DEFAULT; | ||||||
|  |     if(counter_value == 0xFFFF) { | ||||||
|  |         // Tag will lock out counter if final number is 0xFFFF, even if you try to roll it back
 | ||||||
|  |         emulator->data.counter[1] = 0xFFFF; | ||||||
|  |     } | ||||||
|  |     emulator->data_changed = true; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void mf_ul_emulate_write( | static void mf_ul_emulate_write( | ||||||
|     MfUltralightEmulator* emulator, |     MfUltralightEmulator* emulator, | ||||||
|     int16_t tag_addr, |     int16_t tag_addr, | ||||||
| @ -962,53 +1052,75 @@ static void mf_ul_emulate_write( | |||||||
|         *(uint32_t*)page_buff |= *(uint32_t*)&emulator->data.data[write_page * 4]; |         *(uint32_t*)page_buff |= *(uint32_t*)&emulator->data.data[write_page * 4]; | ||||||
|     } else if(tag_addr == mf_ul_get_dynamic_lock_page_addr(&emulator->data)) { |     } else if(tag_addr == mf_ul_get_dynamic_lock_page_addr(&emulator->data)) { | ||||||
|         // Handle dynamic locks
 |         // Handle dynamic locks
 | ||||||
|         uint16_t orig_locks = emulator->data.data[write_page * 4] | |         if(emulator->data.type == MfUltralightTypeNTAG203) { | ||||||
|                               (emulator->data.data[write_page * 4 + 1] << 8); |             // NTAG203 lock bytes are a bit different from the others
 | ||||||
|         uint8_t orig_block_locks = emulator->data.data[write_page * 4 + 2]; |             uint8_t orig_page_lock_byte = emulator->data.data[write_page * 4]; | ||||||
|         uint16_t new_locks = page_buff[0] | (page_buff[1] << 8); |             uint8_t orig_cnt_lock_byte = emulator->data.data[write_page * 4 + 1]; | ||||||
|         uint8_t new_block_locks = page_buff[2]; |             uint8_t new_page_lock_byte = page_buff[0]; | ||||||
|  |             uint8_t new_cnt_lock_byte = page_buff[1]; | ||||||
| 
 | 
 | ||||||
|         int block_lock_count; |             if(orig_page_lock_byte & 0x01) // Block lock bits 1-3
 | ||||||
|         switch(emulator->data.type) { |                 new_page_lock_byte &= ~0x0E; | ||||||
|         case MfUltralightTypeUL21: |             if(orig_page_lock_byte & 0x10) // Block lock bits 5-7
 | ||||||
|             block_lock_count = 5; |                 new_page_lock_byte &= ~0xE0; | ||||||
|             break; |             for(uint8_t i = 0; i < 4; ++i) { | ||||||
|         case MfUltralightTypeNTAG213: |                 if(orig_cnt_lock_byte & (1 << i)) // Block lock counter bit
 | ||||||
|             block_lock_count = 6; |                     new_cnt_lock_byte &= ~(1 << (4 + i)); | ||||||
|             break; |             } | ||||||
|         case MfUltralightTypeNTAG215: | 
 | ||||||
|             block_lock_count = 4; |             new_page_lock_byte |= orig_page_lock_byte; | ||||||
|             break; |             new_cnt_lock_byte |= orig_cnt_lock_byte; | ||||||
|         case MfUltralightTypeNTAG216: |             page_buff[0] = new_page_lock_byte; | ||||||
|         case MfUltralightTypeNTAGI2C1K: |             page_buff[1] = new_cnt_lock_byte; | ||||||
|         case MfUltralightTypeNTAGI2CPlus1K: |         } else { | ||||||
|             block_lock_count = 7; |             uint16_t orig_locks = emulator->data.data[write_page * 4] | | ||||||
|             break; |                                   (emulator->data.data[write_page * 4 + 1] << 8); | ||||||
|         case MfUltralightTypeNTAGI2C2K: |             uint8_t orig_block_locks = emulator->data.data[write_page * 4 + 2]; | ||||||
|         case MfUltralightTypeNTAGI2CPlus2K: |             uint16_t new_locks = page_buff[0] | (page_buff[1] << 8); | ||||||
|             block_lock_count = 8; |             uint8_t new_block_locks = page_buff[2]; | ||||||
|             break; | 
 | ||||||
|         default: |             int block_lock_count; | ||||||
|             furi_assert(false); |             switch(emulator->data.type) { | ||||||
|             block_lock_count = 0; |             case MfUltralightTypeUL21: | ||||||
|             break; |                 block_lock_count = 5; | ||||||
|  |                 break; | ||||||
|  |             case MfUltralightTypeNTAG213: | ||||||
|  |                 block_lock_count = 6; | ||||||
|  |                 break; | ||||||
|  |             case MfUltralightTypeNTAG215: | ||||||
|  |                 block_lock_count = 4; | ||||||
|  |                 break; | ||||||
|  |             case MfUltralightTypeNTAG216: | ||||||
|  |             case MfUltralightTypeNTAGI2C1K: | ||||||
|  |             case MfUltralightTypeNTAGI2CPlus1K: | ||||||
|  |                 block_lock_count = 7; | ||||||
|  |                 break; | ||||||
|  |             case MfUltralightTypeNTAGI2C2K: | ||||||
|  |             case MfUltralightTypeNTAGI2CPlus2K: | ||||||
|  |                 block_lock_count = 8; | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 furi_assert(false); | ||||||
|  |                 block_lock_count = 0; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             for(int i = 0; i < block_lock_count; ++i) { | ||||||
|  |                 if(orig_block_locks & (1 << i)) new_locks &= ~(3 << (2 * i)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             new_locks |= orig_locks; | ||||||
|  |             new_block_locks |= orig_block_locks; | ||||||
|  | 
 | ||||||
|  |             page_buff[0] = new_locks & 0xff; | ||||||
|  |             page_buff[1] = new_locks >> 8; | ||||||
|  |             page_buff[2] = new_block_locks; | ||||||
|  |             if(emulator->data.type >= MfUltralightTypeUL21 && | ||||||
|  |                emulator->data.type <= MfUltralightTypeNTAG216) | ||||||
|  |                 page_buff[3] = MF_UL_TEARING_FLAG_DEFAULT; | ||||||
|  |             else | ||||||
|  |                 page_buff[3] = 0; | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         for(int i = 0; i < block_lock_count; ++i) { |  | ||||||
|             if(orig_block_locks & (1 << i)) new_locks &= ~(3 << (2 * i)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         new_locks |= orig_locks; |  | ||||||
|         new_block_locks |= orig_block_locks; |  | ||||||
| 
 |  | ||||||
|         page_buff[0] = new_locks & 0xff; |  | ||||||
|         page_buff[1] = new_locks >> 8; |  | ||||||
|         page_buff[2] = new_block_locks; |  | ||||||
|         if(emulator->data.type >= MfUltralightTypeUL21 && |  | ||||||
|            emulator->data.type <= MfUltralightTypeNTAG216) |  | ||||||
|             page_buff[3] = MF_UL_TEARING_FLAG_DEFAULT; |  | ||||||
|         else |  | ||||||
|             page_buff[3] = 0; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     memcpy(&emulator->data.data[write_page * 4], page_buff, 4); |     memcpy(&emulator->data.data[write_page * 4], page_buff, 4); | ||||||
| @ -1025,6 +1137,18 @@ void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) | |||||||
|         if(emulator->supported_features & MfUltralightSupportSingleCounter) { |         if(emulator->supported_features & MfUltralightSupportSingleCounter) { | ||||||
|             emulator->read_counter_incremented = false; |             emulator->read_counter_incremented = false; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         if(emulator->data.type == MfUltralightTypeNTAG203) { | ||||||
|  |             // Apply lockout if counter ever reached 0xFFFF
 | ||||||
|  |             if(emulator->data.counter[1] == 0xFFFF) { | ||||||
|  |                 emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] = 0xFF; | ||||||
|  |                 emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] = 0xFF; | ||||||
|  |             } | ||||||
|  |             // Copy original counter value from data
 | ||||||
|  |             emulator->data.counter[0] = | ||||||
|  |                 emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] | | ||||||
|  |                 (emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] << 8); | ||||||
|  |         } | ||||||
|     } else { |     } else { | ||||||
|         if(emulator->config != NULL) { |         if(emulator->config != NULL) { | ||||||
|             // ACCESS (less CFGLCK) and AUTH0 are updated when reactivated
 |             // ACCESS (less CFGLCK) and AUTH0 are updated when reactivated
 | ||||||
| @ -1034,6 +1158,10 @@ void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) | |||||||
|             emulator->config_cache.auth0 = emulator->config->auth0; |             emulator->config_cache.auth0 = emulator->config->auth0; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     if(emulator->data.type == MfUltralightTypeNTAG203) { | ||||||
|  |         // Mark counter as dirty
 | ||||||
|  |         emulator->data.tearing[0] = 0; | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data) { | void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data) { | ||||||
| @ -1077,12 +1205,20 @@ bool mf_ul_prepare_emulation_response( | |||||||
| 
 | 
 | ||||||
|     // Check composite commands
 |     // Check composite commands
 | ||||||
|     if(emulator->comp_write_cmd_started) { |     if(emulator->comp_write_cmd_started) { | ||||||
|         // Compatibility write is the only one composit command
 |  | ||||||
|         if(buff_rx_len == 16 * 8) { |         if(buff_rx_len == 16 * 8) { | ||||||
|             mf_ul_emulate_write( |             if(emulator->data.type == MfUltralightTypeNTAG203 && | ||||||
|                 emulator, emulator->comp_write_page_addr, emulator->comp_write_page_addr, buff_rx); |                emulator->comp_write_page_addr == MF_UL_NTAG203_COUNTER_PAGE) { | ||||||
|             send_ack = true; |                 send_ack = mf_ul_emulate_ntag203_counter_write(emulator, buff_rx); | ||||||
|             command_parsed = true; |                 command_parsed = send_ack; | ||||||
|  |             } else { | ||||||
|  |                 mf_ul_emulate_write( | ||||||
|  |                     emulator, | ||||||
|  |                     emulator->comp_write_page_addr, | ||||||
|  |                     emulator->comp_write_page_addr, | ||||||
|  |                     buff_rx); | ||||||
|  |                 send_ack = true; | ||||||
|  |                 command_parsed = true; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         emulator->comp_write_cmd_started = false; |         emulator->comp_write_cmd_started = false; | ||||||
|     } else if(emulator->sector_select_cmd_started) { |     } else if(emulator->sector_select_cmd_started) { | ||||||
| @ -1099,7 +1235,7 @@ bool mf_ul_prepare_emulation_response( | |||||||
|     } else if(buff_rx_len >= 8) { |     } else if(buff_rx_len >= 8) { | ||||||
|         uint8_t cmd = buff_rx[0]; |         uint8_t cmd = buff_rx[0]; | ||||||
|         if(cmd == MF_UL_GET_VERSION_CMD) { |         if(cmd == MF_UL_GET_VERSION_CMD) { | ||||||
|             if(emulator->data.type != MfUltralightTypeUnknown) { |             if(emulator->data.type >= MfUltralightTypeUL11) { | ||||||
|                 if(buff_rx_len == 1 * 8) { |                 if(buff_rx_len == 1 * 8) { | ||||||
|                     tx_bytes = sizeof(emulator->data.version); |                     tx_bytes = sizeof(emulator->data.version); | ||||||
|                     memcpy(buff_tx, &emulator->data.version, tx_bytes); |                     memcpy(buff_tx, &emulator->data.version, tx_bytes); | ||||||
| @ -1409,9 +1545,15 @@ bool mf_ul_prepare_emulation_response( | |||||||
|                     int16_t tag_addr = mf_ultralight_page_addr_to_tag_addr( |                     int16_t tag_addr = mf_ultralight_page_addr_to_tag_addr( | ||||||
|                         emulator->curr_sector, orig_write_page); |                         emulator->curr_sector, orig_write_page); | ||||||
|                     if(!mf_ul_check_lock(emulator, tag_addr)) break; |                     if(!mf_ul_check_lock(emulator, tag_addr)) break; | ||||||
|                     mf_ul_emulate_write(emulator, tag_addr, write_page, &buff_rx[2]); |                     if(emulator->data.type == MfUltralightTypeNTAG203 && | ||||||
|                     send_ack = true; |                        orig_write_page == MF_UL_NTAG203_COUNTER_PAGE) { | ||||||
|                     command_parsed = true; |                         send_ack = mf_ul_emulate_ntag203_counter_write(emulator, &buff_rx[2]); | ||||||
|  |                         command_parsed = send_ack; | ||||||
|  |                     } else { | ||||||
|  |                         mf_ul_emulate_write(emulator, tag_addr, write_page, &buff_rx[2]); | ||||||
|  |                         send_ack = true; | ||||||
|  |                         command_parsed = true; | ||||||
|  |                     } | ||||||
|                 } while(false); |                 } while(false); | ||||||
|             } |             } | ||||||
|         } else if(cmd == MF_UL_FAST_WRITE) { |         } else if(cmd == MF_UL_FAST_WRITE) { | ||||||
| @ -1590,7 +1732,8 @@ bool mf_ul_prepare_emulation_response( | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             reset_idle = true; |             // NTAG203 appears to NAK instead of just falling off on invalid commands
 | ||||||
|  |             if(emulator->data.type != MfUltralightTypeNTAG203) reset_idle = true; | ||||||
|             FURI_LOG_D(TAG, "Received invalid command"); |             FURI_LOG_D(TAG, "Received invalid command"); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|  | |||||||
| @ -26,15 +26,23 @@ | |||||||
| #define MF_UL_NAK_INVALID_ARGUMENT (0x0) | #define MF_UL_NAK_INVALID_ARGUMENT (0x0) | ||||||
| #define MF_UL_NAK_AUTHLIM_REACHED (0x4) | #define MF_UL_NAK_AUTHLIM_REACHED (0x4) | ||||||
| 
 | 
 | ||||||
|  | #define MF_UL_NTAG203_COUNTER_PAGE (41) | ||||||
|  | 
 | ||||||
|  | // Important: order matters; some features are based on positioning in this enum
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     MfUltralightTypeUnknown, |     MfUltralightTypeUnknown, | ||||||
|  |     MfUltralightTypeNTAG203, | ||||||
|  |     // Below have config pages and GET_VERSION support
 | ||||||
|     MfUltralightTypeUL11, |     MfUltralightTypeUL11, | ||||||
|     MfUltralightTypeUL21, |     MfUltralightTypeUL21, | ||||||
|     MfUltralightTypeNTAG213, |     MfUltralightTypeNTAG213, | ||||||
|     MfUltralightTypeNTAG215, |     MfUltralightTypeNTAG215, | ||||||
|     MfUltralightTypeNTAG216, |     MfUltralightTypeNTAG216, | ||||||
|  |     // Below also have sector select
 | ||||||
|  |     // NTAG I2C's *does not* have regular config pages, so it's a bit of an odd duck
 | ||||||
|     MfUltralightTypeNTAGI2C1K, |     MfUltralightTypeNTAGI2C1K, | ||||||
|     MfUltralightTypeNTAGI2C2K, |     MfUltralightTypeNTAGI2C2K, | ||||||
|  |     // NTAG I2C Plus has stucture expected from NTAG21x
 | ||||||
|     MfUltralightTypeNTAGI2CPlus1K, |     MfUltralightTypeNTAGI2CPlus1K, | ||||||
|     MfUltralightTypeNTAGI2CPlus2K, |     MfUltralightTypeNTAGI2CPlus2K, | ||||||
| 
 | 
 | ||||||
| @ -58,6 +66,8 @@ typedef enum { | |||||||
|     MfUltralightSupportSingleCounter = 1 << 10, |     MfUltralightSupportSingleCounter = 1 << 10, | ||||||
|     // ASCII mirror is not a command, but handy to have as a flag
 |     // ASCII mirror is not a command, but handy to have as a flag
 | ||||||
|     MfUltralightSupportAsciiMirror = 1 << 11, |     MfUltralightSupportAsciiMirror = 1 << 11, | ||||||
|  |     // NTAG203 counter that's in memory rather than through a command
 | ||||||
|  |     MfUltralightSupportCounterInMemory = 1 << 12, | ||||||
| } MfUltralightFeatures; | } MfUltralightFeatures; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -173,6 +183,11 @@ bool mf_ultralight_read_version( | |||||||
|     MfUltralightReader* reader, |     MfUltralightReader* reader, | ||||||
|     MfUltralightData* data); |     MfUltralightData* data); | ||||||
| 
 | 
 | ||||||
|  | bool mf_ultralight_read_pages_direct( | ||||||
|  |     FuriHalNfcTxRxContext* tx_rx, | ||||||
|  |     uint8_t start_index, | ||||||
|  |     uint8_t* data); | ||||||
|  | 
 | ||||||
| bool mf_ultralight_read_pages( | bool mf_ultralight_read_pages( | ||||||
|     FuriHalNfcTxRxContext* tx_rx, |     FuriHalNfcTxRxContext* tx_rx, | ||||||
|     MfUltralightReader* reader, |     MfUltralightReader* reader, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Yukai Li
						Yukai Li