diff --git a/firmware/application/Makefile b/firmware/application/Makefile index 632b3e2..b6596af 100644 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -28,7 +28,7 @@ SRC_FILES += \ $(PROJ_DIR)/rfid/nfctag/hf/crypto1_helper.c \ $(PROJ_DIR)/rfid/nfctag/hf/nfc_14a.c \ $(PROJ_DIR)/rfid/nfctag/hf/nfc_mf1.c \ - $(PROJ_DIR)/rfid/nfctag/hf/nfc_ntag.c \ + $(PROJ_DIR)/rfid/nfctag/hf/nfc_mf0_ntag.c \ $(PROJ_DIR)/rfid/nfctag/lf/lf_tag_em.c \ $(PROJ_DIR)/utils/dataframe.c \ $(PROJ_DIR)/utils/delayed_reset.c \ diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index 8a7e9ab..d4fc9e8 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -1026,6 +1026,24 @@ static data_frame_tx_t *after_hf_reader_run(uint16_t cmd, uint16_t status, uint1 // fct will be defined after m_data_cmd_map because we need to know its size data_frame_tx_t *cmd_processor_get_device_capabilities(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data); +static data_frame_tx_t *cmd_processor_mf0_ntag_get_uid_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + int rc = nfc_tag_mf0_ntag_get_uid_mode(); + + if (rc < 0) return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL); + else { + uint8_t res = rc; + return data_frame_make(cmd, STATUS_SUCCESS, 1, &res); + } +} + +static data_frame_tx_t *cmd_processor_mf0_ntag_set_uid_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + if (length != 1 || !nfc_tag_mf0_ntag_set_uid_mode(data[0] != 0)) { + return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL); + } + + return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL); +} + /** * (cmd -> processor) function map, the map struct is: * cmd code before process cmd processor after process @@ -1109,6 +1127,8 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_MF1_GET_WRITE_MODE, NULL, cmd_processor_mf1_get_write_mode, NULL }, { DATA_CMD_MF1_SET_WRITE_MODE, NULL, cmd_processor_mf1_set_write_mode, NULL }, { DATA_CMD_HF14A_GET_ANTI_COLL_DATA, NULL, cmd_processor_hf14a_get_anti_coll_data, NULL }, + { DATA_CMD_MF0_NTAG_GET_UID_MAGIC_MODE, NULL, cmd_processor_mf0_ntag_get_uid_mode, NULL }, + { DATA_CMD_MF0_NTAG_SET_UID_MAGIC_MODE, NULL, cmd_processor_mf0_ntag_set_uid_mode, NULL }, { DATA_CMD_EM410X_SET_EMU_ID, NULL, cmd_processor_em410x_set_emu_id, NULL }, { DATA_CMD_EM410X_GET_EMU_ID, NULL, cmd_processor_em410x_get_emu_id, NULL }, diff --git a/firmware/application/src/app_main.c b/firmware/application/src/app_main.c index 011f4ba..5a6d322 100644 --- a/firmware/application/src/app_main.c +++ b/firmware/application/src/app_main.c @@ -653,8 +653,12 @@ static void btn_fn_copy_ic_uid(void) { case TAG_TYPE_NTAG_213: case TAG_TYPE_NTAG_215: - case TAG_TYPE_NTAG_216: { - nfc_tag_ntag_information_t *p_info = (nfc_tag_ntag_information_t *)buffer->buffer; + case TAG_TYPE_NTAG_216: + case TAG_TYPE_MF0ICU1: + case TAG_TYPE_MF0ICU2: + case TAG_TYPE_MF0UL11: + case TAG_TYPE_MF0UL21: { + nfc_tag_mf0_ntag_information_t *p_info = (nfc_tag_mf0_ntag_information_t *)buffer->buffer; antres = &(p_info->res_coll); break; } diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index 10313b1..7ede255 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -106,6 +106,8 @@ #define DATA_CMD_MF1_GET_WRITE_MODE (4016) #define DATA_CMD_MF1_SET_WRITE_MODE (4017) #define DATA_CMD_HF14A_GET_ANTI_COLL_DATA (4018) +#define DATA_CMD_MF0_NTAG_GET_UID_MAGIC_MODE (4019) +#define DATA_CMD_MF0_NTAG_SET_UID_MAGIC_MODE (4020) // // ****************************************************************** diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c b/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c new file mode 100644 index 0000000..665fa27 --- /dev/null +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c @@ -0,0 +1,492 @@ +#include + +#include "nfc_mf0_ntag.h" +#include "nfc_14a.h" +#include "fds_util.h" +#include "tag_persistence.h" + +#define NRF_LOG_MODULE_NAME tag_mf0_ntag +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_log_default_backends.h" +NRF_LOG_MODULE_REGISTER(); + + +#define VERSION_FIXED_HEADER 0x00 +#define VERSION_VENDOR_ID 0x04 +#define MF0ULx1_VERSION_PRODUCT_TYPE 0x03 +#define NTAG_VERSION_PRODUCT_TYPE 0x04 +#define VERSION_PRODUCT_SUBTYPE_17pF 0x01 +#define VERSION_PRODUCT_SUBTYPE_50pF 0x02 +#define VERSION_MAJOR_PRODUCT 0x01 +#define VERSION_MINOR_PRODUCT 0x00 +#define MF0UL11_VERSION_STORAGE_SIZE 0x0B +#define MF0UL21_VERSION_STORAGE_SIZE 0x0E +#define NTAG213_VERSION_STORAGE_SIZE 0x0F +#define NTAG215_VERSION_STORAGE_SIZE 0x11 +#define NTAG216_VERSION_STORAGE_SIZE 0x13 +#define VERSION_PROTOCOL_TYPE 0x03 + +// MF0 and NTAG COMMANDS +#define CMD_GET_VERSION 0x60 +#define CMD_READ 0x30 +#define CMD_FAST_READ 0x3A +#define CMD_WRITE 0xA2 +#define CMD_COMPAT_WRITE 0xA0 +#define CMD_READ_CNT 0x39 +#define CMD_INCR_CNT 0x3A +#define CMD_PWD_AUTH 0x1B +#define CMD_READ_SIG 0x3C +#define CMD_CHECK_TEARING_EVENT 0x3E +#define CMD_VCSL 0x4B + +// MEMORY LAYOUT STUFF, addresses and sizes in bytes +// UID stuff +#define UID_CL1_ADDRESS 0x00 +#define UID_CL1_SIZE 3 +#define UID_BCC1_ADDRESS 0x03 +#define UID_CL2_ADDRESS 0x04 +#define UID_CL2_SIZE 4 +#define UID_BCC2_ADDRESS 0x08 +// LockBytes stuff +#define STATIC_LOCKBYTE_0_ADDRESS 0x0A +#define STATIC_LOCKBYTE_1_ADDRESS 0x0B +// CONFIG stuff +#define MF0UL11_FIRST_CFG_PAGE 0x10 +#define MF0UL21_FIRST_CFG_PAGE 0x25 +#define NTAG213_FIRST_CFG_PAGE 0x29 +#define NTAG215_FIRST_CFG_PAGE 0x83 +#define NTAG216_FIRST_CFG_PAGE 0xE3 +#define CONFIG_AREA_SIZE 8 + +// CONFIG offsets, relative to config start address +#define CONF_AUTH0_BYTE 0x03 +#define CONF_ACCESS_OFFSET 0x04 +#define CONF_PWD_PAGE_OFFSET 2 +#define CONF_PACK_PAGE_OFFSET 3 + +// WRITE STUFF +#define BYTES_PER_WRITE 4 +#define PAGE_WRITE_MIN 0x02 + +// CONFIG masks to check individual needed bits +#define CONF_ACCESS_PROT 0x80 + +#define VERSION_INFO_LENGTH 8 //8 bytes info length + crc + +#define BYTES_PER_READ 16 + +// SIGNATURE Length +#define SIGNATURE_LENGTH 32 + +// NTAG215_Version[7] mean: +// 0x0F ntag213 +// 0x11 ntag215 +// 0x13 ntag216 +const uint8_t ntagVersion[8] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x11, 0x03}; +/* pwd auth for amiibo */ +uint8_t ntagPwdOK[2] = {0x80, 0x80}; + +// Data structure pointer to the label information +static nfc_tag_mf0_ntag_information_t *m_tag_information = NULL; +// Define and use shadow anti -collision resources +static nfc_tag_14a_coll_res_reference_t m_shadow_coll_res; +//Define and use MF0/NTAG special communication buffer +static nfc_tag_mf0_ntag_tx_buffer_t m_tag_tx_buffer; +// Save the specific type of MF0/NTAG currently being simulated +static tag_specific_type_t m_tag_type; +static bool m_tag_authenticated = false; + +static uint8_t get_nr_pages_by_tag_type(tag_specific_type_t tag_type) { + uint8_t nr_pages; + + switch (tag_type) { + case TAG_TYPE_MF0ICU1: + nr_pages = MF0ICU1_PAGES; + break; + case TAG_TYPE_MF0ICU2: + nr_pages = MF0ICU2_PAGES; + break; + case TAG_TYPE_MF0UL11: + nr_pages = MF0UL11_PAGES; + break; + case TAG_TYPE_MF0UL21: + nr_pages = MF0UL21_PAGES; + break; + case TAG_TYPE_NTAG_213: + nr_pages = NTAG213_PAGES; + break; + case TAG_TYPE_NTAG_215: + nr_pages = NTAG215_PAGES; + break; + case TAG_TYPE_NTAG_216: + nr_pages = NTAG216_PAGES; + break; + default: + nr_pages = 0; + break; + } + + return nr_pages; +} + +static uint8_t get_first_cfg_page_by_tag_type(tag_specific_type_t tag_type) { + uint8_t page; + + switch (tag_type) { + case TAG_TYPE_MF0UL11: + page = MF0UL11_FIRST_CFG_PAGE; + break; + case TAG_TYPE_MF0UL21: + page = MF0UL21_FIRST_CFG_PAGE; + break; + case TAG_TYPE_NTAG_213: + page = NTAG213_FIRST_CFG_PAGE; + break; + case TAG_TYPE_NTAG_215: + page = NTAG215_FIRST_CFG_PAGE; + break; + case TAG_TYPE_NTAG_216: + page = NTAG216_FIRST_CFG_PAGE; + break; + default: + page = 0; + break; + } + + return page; +} + +static uint8_t get_block_max_by_tag_type(tag_specific_type_t tag_type) { + uint8_t max_pages = get_nr_pages_by_tag_type(tag_type); + uint8_t first_cfg_page = get_first_cfg_page_by_tag_type(tag_type); + + if (first_cfg_page == 0 || m_tag_authenticated || m_tag_information->config.mode_uid_magic) return max_pages; + + uint8_t auth0 = m_tag_information->memory[first_cfg_page][CONF_AUTH0_BYTE]; + return (max_pages > auth0) ? auth0 : max_pages; +} + +static bool is_ntag() { + switch (m_tag_type) { + case TAG_TYPE_NTAG_213: + case TAG_TYPE_NTAG_215: + case TAG_TYPE_NTAG_216: + return true; + default: + return false; + } +} + +static void handle_get_version_command() { + switch (m_tag_type) { + case TAG_TYPE_MF0UL11: + m_tag_tx_buffer.tx_buffer[6] = MF0UL11_VERSION_STORAGE_SIZE; + m_tag_tx_buffer.tx_buffer[2] = MF0ULx1_VERSION_PRODUCT_TYPE; + break; + case TAG_TYPE_MF0UL21: + m_tag_tx_buffer.tx_buffer[6] = MF0UL21_VERSION_STORAGE_SIZE; + m_tag_tx_buffer.tx_buffer[2] = MF0ULx1_VERSION_PRODUCT_TYPE; + break; + case TAG_TYPE_NTAG_213: + m_tag_tx_buffer.tx_buffer[6] = NTAG213_VERSION_STORAGE_SIZE; + m_tag_tx_buffer.tx_buffer[2] = NTAG_VERSION_PRODUCT_TYPE; + break; + case TAG_TYPE_NTAG_215: + m_tag_tx_buffer.tx_buffer[6] = NTAG215_VERSION_STORAGE_SIZE; + m_tag_tx_buffer.tx_buffer[2] = NTAG_VERSION_PRODUCT_TYPE; + break; + case TAG_TYPE_NTAG_216: + m_tag_tx_buffer.tx_buffer[6] = NTAG216_VERSION_STORAGE_SIZE; + m_tag_tx_buffer.tx_buffer[2] = NTAG_VERSION_PRODUCT_TYPE; + break; + default: + // MF0ICU1 and MF0ICU2 do not support GET_VERSION + nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV, 4); + return; + } + + m_tag_tx_buffer.tx_buffer[0] = VERSION_FIXED_HEADER; + m_tag_tx_buffer.tx_buffer[1] = VERSION_VENDOR_ID; + m_tag_tx_buffer.tx_buffer[3] = VERSION_PRODUCT_SUBTYPE_50pF; // TODO: make configurable for MF0ULx1 + m_tag_tx_buffer.tx_buffer[4] = VERSION_MAJOR_PRODUCT; + m_tag_tx_buffer.tx_buffer[5] = VERSION_MINOR_PRODUCT; + m_tag_tx_buffer.tx_buffer[7] = VERSION_PROTOCOL_TYPE; + + nfc_tag_14a_tx_bytes(m_tag_tx_buffer.tx_buffer, 8, true); +} + +static void handle_read_command(uint8_t block_num) { + int block_max = get_block_max_by_tag_type(m_tag_type); + + if (block_num >= block_max) { + nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV, 4); + return; + } + + uint8_t pwd_page = get_first_cfg_page_by_tag_type(m_tag_type); + if (pwd_page != 0) pwd_page += CONF_PWD_PAGE_OFFSET; + + for (int block = 0; block < 4; block++) { + // In case PWD or PACK pages are read we need to write zero to the output buffer. In UID magic mode we don't care. + if (m_tag_information->config.mode_uid_magic || (pwd_page == 0) || ((block - pwd_page) >= 2)) { + memcpy(m_tag_tx_buffer.tx_buffer + block * 4, m_tag_information->memory[(block_num + block) % block_max], NFC_TAG_MF0_NTAG_DATA_SIZE); + } else { + memset(m_tag_tx_buffer.tx_buffer + block * 4, 0, NFC_TAG_MF0_NTAG_DATA_SIZE); + } + } + nfc_tag_14a_tx_bytes(m_tag_tx_buffer.tx_buffer, BYTES_PER_READ, true); +} + +static bool check_ro_lock_on_page(int block_num) { + if (block_num < 3) return true; + else if (block_num == 3) return (m_tag_information->memory[2][2] & 1) == 1; + else if (block_num <= MF0ICU1_PAGES) { + bool locked = false; + + // check block locking bits + if (block_num <= 9) locked |= (m_tag_information->memory[2][2] & 2) == 2; + else locked |= (m_tag_information->memory[2][2] & 4) == 4; + + locked |= (((*(uint16_t *)&m_tag_information->memory[2][2]) >> block_num) & 1) == 1; + + return locked; + } else { + // too large block number + return true; + } +} + +static int handle_write_command(uint8_t block_num, uint8_t *p_data) { + int block_max = get_block_max_by_tag_type(m_tag_type); + + if (block_num >= block_max) { + return NAK_INVALID_OPERATION_TBIV; + } + + if (m_tag_information->config.mode_uid_magic) { + // anything can be written in this mode + memcpy(m_tag_information->memory[block_num], p_data, NFC_TAG_MF0_NTAG_DATA_SIZE); + return ACK_VALUE; + } + + switch (block_num) { + case 0: + case 1: + return NAK_INVALID_OPERATION_TBIV; + case 2: + // Page 2 contains lock bytes for pages 3-15. These are OR'ed when not in the UID + // magic mode. First two bytes are ignored. + m_tag_information->memory[2][2] |= p_data[2]; + m_tag_information->memory[2][3] |= p_data[3]; + break; + case 3: + // Page 3 contains what's called OTP bits for Ultralight tags and CC bits for NTAG + // cards, these work in the same way. + if (!check_ro_lock_on_page(block_num)) { + // lock bit for OTP page is not set + for (int i = 0; i < NFC_TAG_MF0_NTAG_DATA_SIZE; i++) { + m_tag_information->memory[3][i] |= p_data[i]; + } + } + break; + default: + if (!check_ro_lock_on_page(block_num)) { + memcpy(m_tag_information->memory[block_num], p_data, NFC_TAG_MF0_NTAG_DATA_SIZE); + } + break; + } + + return ACK_VALUE; +} + +static void nfc_tag_mf0_ntag_state_handler(uint8_t *p_data, uint16_t szDataBits) { + uint8_t command = p_data[0]; + uint8_t block_num = p_data[1]; + + switch (command) { + case CMD_GET_VERSION: + handle_get_version_command(); + break; + case CMD_READ: { + handle_read_command(block_num); + break; + } + case CMD_FAST_READ: { + uint8_t end_block_num = p_data[2]; + // TODO: support ultralight + if (!is_ntag() || (block_num > end_block_num) || (block_num >= get_block_max_by_tag_type(m_tag_type)) || (end_block_num >= get_block_max_by_tag_type(m_tag_type))) { + nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBV, 4); + break; + } + for (int block = block_num; block <= end_block_num; block++) { + memcpy(m_tag_tx_buffer.tx_buffer + (block - block_num) * 4, m_tag_information->memory[block], NFC_TAG_MF0_NTAG_DATA_SIZE); + } + nfc_tag_14a_tx_bytes(m_tag_tx_buffer.tx_buffer, (end_block_num - block_num + 1) * NFC_TAG_MF0_NTAG_DATA_SIZE, true); + break; + } + case CMD_WRITE: + case CMD_COMPAT_WRITE: { + int resp = handle_write_command(block_num, &p_data[2]); + nfc_tag_14a_tx_nbit(resp, 4); + break; + } + /*case CMD_PWD_AUTH: { + // TODO: IMPLEMENT COUNTER AUTHLIM + uint8_t Password[4]; + memcpy(Password, m_tag_information->memory[get_block_cfg_by_tag_type(m_tag_type) + CONF_PASSWORD_OFFSET], 4); + if (Password[0] != p_data[1] || Password[1] != p_data[2] || Password[2] != p_data[3] || Password[3] != p_data[4]) { + nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV, 4); + break; + } + // Authenticate the user + //RESET AUTHLIM COUNTER, CURRENTLY NOT IMPLEMENTED + // TODO + // Send the PACK value back + if (m_tag_information->config.mode_uid_magic) { + nfc_tag_14a_tx_bytes(ntagPwdOK, 2, true); + } else { + nfc_tag_14a_tx_bytes(m_tag_information->memory[get_block_cfg_by_tag_type(m_tag_type) + CONF_PASSWORD_OFFSET], 2, true); + } + break; + }*/ + case CMD_READ_SIG: + memset(m_tag_tx_buffer.tx_buffer, 0xCA, SIGNATURE_LENGTH); + nfc_tag_14a_tx_bytes(m_tag_tx_buffer.tx_buffer, SIGNATURE_LENGTH, true); + break; + } + return; +} + +static nfc_tag_14a_coll_res_reference_t *get_coll_res() { + // Use a separate anti -conflict information instead of using the information in the sector + m_shadow_coll_res.sak = m_tag_information->res_coll.sak; + m_shadow_coll_res.atqa = m_tag_information->res_coll.atqa; + m_shadow_coll_res.uid = m_tag_information->res_coll.uid; + m_shadow_coll_res.size = &(m_tag_information->res_coll.size); + m_shadow_coll_res.ats = &(m_tag_information->res_coll.ats); + // Finally, a shadow data structure pointer with only reference, no physical shadow, + return &m_shadow_coll_res; +} + +static void nfc_tag_mf0_ntag_reset_handler() { + +} + +static int get_information_size_by_tag_type(tag_specific_type_t type) { + return sizeof(nfc_tag_14a_coll_res_entity_t) + sizeof(nfc_tag_mf0_ntag_configure_t) + (get_nr_pages_by_tag_type(type) * NFC_TAG_MF0_NTAG_DATA_SIZE); +} + +/** @brief MF0/NTAG callback before saving data + * @param type detailed label type + * @param buffer data buffer + * @return to be saved, the length of the data that needs to be saved, it means not saved when 0 + */ +int nfc_tag_mf0_ntag_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) { + if (m_tag_type != TAG_TYPE_UNDEFINED && m_tag_information != NULL) { + // Save the corresponding size data according to the current label type + return get_information_size_by_tag_type(type); + } else { + return 0; + } +} + +int nfc_tag_mf0_ntag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) { + int info_size = get_information_size_by_tag_type(type); + if (buffer->length >= info_size) { + // Convert the data buffer to MF0/NTAG structure type + m_tag_information = (nfc_tag_mf0_ntag_information_t *)buffer->buffer; + // The specific type of MF0/NTAG tag that is simulated by the cache + m_tag_type = type; + // Register 14A communication management interface + nfc_tag_14a_handler_t handler_for_14a = { + .get_coll_res = get_coll_res, + .cb_state = nfc_tag_mf0_ntag_state_handler, + .cb_reset = nfc_tag_mf0_ntag_reset_handler, + }; + nfc_tag_14a_set_handler(&handler_for_14a); + NRF_LOG_INFO("HF ntag data load finish."); + } else { + NRF_LOG_ERROR("nfc_tag_mf0_ntag_information_t too big."); + } + return info_size; +} + +// Initialized NTAG factory data +bool nfc_tag_mf0_ntag_data_factory(uint8_t slot, tag_specific_type_t tag_type) { + // default ntag data + uint8_t default_p0[] = { 0x04, 0x68, 0x95, 0x71 }; + uint8_t default_p1[] = { 0xFA, 0x5C, 0x64, 0x80 }; + uint8_t default_p2[] = { 0x42, 0x48, 0x0F, 0xE0 }; + + if (!is_ntag()) { + default_p2[2] = 0; + default_p2[3] = 0; + } + + // default ntag info + nfc_tag_mf0_ntag_information_t ntag_tmp_information; + nfc_tag_mf0_ntag_information_t *p_ntag_information; + p_ntag_information = &ntag_tmp_information; + int block_max = get_nr_pages_by_tag_type(tag_type); + for (int block = 0; block < block_max; block++) { + switch (block) { + case 0: + memcpy(p_ntag_information->memory[block], default_p0, NFC_TAG_MF0_NTAG_DATA_SIZE); + break; + case 1: + memcpy(p_ntag_information->memory[block], default_p1, NFC_TAG_MF0_NTAG_DATA_SIZE); + break; + case 2: + memcpy(p_ntag_information->memory[block], default_p2, NFC_TAG_MF0_NTAG_DATA_SIZE); + break; + default: + memset(p_ntag_information->memory[block], 0, NFC_TAG_MF0_NTAG_DATA_SIZE); + break; + } + } + + // default ntag auto ant-collision res + p_ntag_information->res_coll.atqa[0] = 0x44; + p_ntag_information->res_coll.atqa[1] = 0x00; + p_ntag_information->res_coll.sak[0] = 0x00; + p_ntag_information->res_coll.uid[0] = 0x04; + p_ntag_information->res_coll.uid[1] = 0x68; + p_ntag_information->res_coll.uid[2] = 0x95; + p_ntag_information->res_coll.uid[3] = 0x71; + p_ntag_information->res_coll.uid[4] = 0xFA; + p_ntag_information->res_coll.uid[5] = 0x5C; + p_ntag_information->res_coll.uid[6] = 0x64; + p_ntag_information->res_coll.size = NFC_TAG_14A_UID_DOUBLE_SIZE; + p_ntag_information->res_coll.ats.length = 0; + + // default ntag config + p_ntag_information->config.mode_uid_magic = false; + + // save data to flash + tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); + fds_slot_record_map_t map_info; + get_fds_map_by_slot_sense_type_for_dump(slot, sense_type, &map_info); + int info_size = get_information_size_by_tag_type(tag_type); + NRF_LOG_INFO("MF0/NTAG info size: %d", info_size); + bool ret = fds_write_sync(map_info.id, map_info.key, info_size, p_ntag_information); + if (ret) { + NRF_LOG_INFO("Factory slot data success."); + } else { + NRF_LOG_ERROR("Factory slot data error."); + } + return ret; +} + +int nfc_tag_mf0_ntag_get_uid_mode() { + if (m_tag_type == TAG_TYPE_UNDEFINED || m_tag_information == NULL) return -1; + + return (int)m_tag_information->config.mode_uid_magic; +} + +bool nfc_tag_mf0_ntag_set_uid_mode(bool enabled) { + if (m_tag_type == TAG_TYPE_UNDEFINED || m_tag_information == NULL) return false; + + m_tag_information->config.mode_uid_magic = enabled; + return true; +} \ No newline at end of file diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.h b/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.h new file mode 100644 index 0000000..cc97185 --- /dev/null +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.h @@ -0,0 +1,50 @@ +#ifndef NFC_NTAG_H +#define NFC_NTAG_H + +#include "nfc_14a.h" + +#define NFC_TAG_MF0_NTAG_DATA_SIZE 4 + +#define NFC_TAG_NTAG_FRAME_SIZE 64 +#define NFC_TAG_NTAG_BLOCK_MAX 231 + +#define NFC_TAG_MF0_FRAME_SIZE (16 + NFC_TAG_14A_CRC_LENGTH) +#define NFC_TAG_MF0_BLOCK_MAX 41 + +#define NTAG213_PAGES 45 //45 pages total for ntag213, from 0 to 44 +#define NTAG215_PAGES 135 //135 pages total for ntag215, from 0 to 134 +#define NTAG216_PAGES 231 //231 pages total for ntag216, from 0 to 230 + +#define MF0ICU1_PAGES 16 //16 pages total for MF0ICU1 (the original UL), from 0 to 15 +#define MF0ICU2_PAGES 36 //16 pages total for MF0ICU2 (UL C), from 0 to 35 +#define MF0UL11_PAGES 20 //20 pages total for MF0UL11 (UL EV1), from 0 to 19 +#define MF0UL21_PAGES 41 //231 pages total for MF0UL21 (UL EV1), from 0 to 40 + + +typedef struct { + uint8_t mode_uid_magic: 1; + // reserve + uint8_t reserved1: 7; + uint8_t reserved2; + uint8_t reserved3; +} nfc_tag_mf0_ntag_configure_t; + +typedef struct __attribute__((aligned(4))) { + nfc_tag_14a_coll_res_entity_t res_coll; + nfc_tag_mf0_ntag_configure_t config; + uint8_t memory[][NFC_TAG_MF0_NTAG_DATA_SIZE]; +} +nfc_tag_mf0_ntag_information_t; + +typedef struct { + uint8_t tx_buffer[NFC_TAG_NTAG_FRAME_SIZE]; +} nfc_tag_mf0_ntag_tx_buffer_t; + +int nfc_tag_mf0_ntag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer); +int nfc_tag_mf0_ntag_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer); +bool nfc_tag_mf0_ntag_data_factory(uint8_t slot, tag_specific_type_t tag_type); + +int nfc_tag_mf0_ntag_get_uid_mode(void); +bool nfc_tag_mf0_ntag_set_uid_mode(bool enabled); + +#endif diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c b/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c deleted file mode 100644 index a90f3c7..0000000 --- a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c +++ /dev/null @@ -1,301 +0,0 @@ -#include - -#include "nfc_ntag.h" -#include "nfc_14a.h" -#include "fds_util.h" -#include "tag_persistence.h" - -#define NRF_LOG_MODULE_NAME tag_ntag -#include "nrf_log.h" -#include "nrf_log_ctrl.h" -#include "nrf_log_default_backends.h" -NRF_LOG_MODULE_REGISTER(); - -#define NTAG213_VERSION 0x0F -#define NTAG215_VERSION 0x11 -#define NTAG216_VERSION 0x13 - -// NTAG COMMANDS -#define CMD_GET_VERSION 0x60 -#define CMD_READ 0x30 -#define CMD_FAST_READ 0x3A -#define CMD_WRITE 0xA2 -#define CMD_COMPAT_WRITE 0xA0 -#define CMD_READ_CNT 0x39 -#define CMD_PWD_AUTH 0x1B -#define CMD_READ_SIG 0x3C - -// MEMORY LAYOUT STUFF, addresses and sizes in bytes -// UID stuff -#define UID_CL1_ADDRESS 0x00 -#define UID_CL1_SIZE 3 -#define UID_BCC1_ADDRESS 0x03 -#define UID_CL2_ADDRESS 0x04 -#define UID_CL2_SIZE 4 -#define UID_BCC2_ADDRESS 0x08 -// LockBytes stuff -#define STATIC_LOCKBYTE_0_ADDRESS 0x0A -#define STATIC_LOCKBYTE_1_ADDRESS 0x0B -// CONFIG stuff -#define NTAG213_CONFIG_AREA_START_ADDRESS 0xA4 // 4 * 0x29 -#define NTAG215_CONFIG_AREA_START_ADDRESS 0x20C // 4 * 0x83 -#define NTAG216_CONFIG_AREA_START_ADDRESS 0x38C // 4 * 0xE3 -#define CONFIG_AREA_SIZE 8 -// CONFIG offsets, relative to config start address -#define CONF_AUTH0_OFFSET 0x03 -#define CONF_ACCESS_OFFSET 0x04 -#define CONF_PASSWORD_OFFSET 0x08 -#define CONF_PACK_OFFSET 0x0C - -// WRITE STUFF -#define BYTES_PER_WRITE 4 -#define PAGE_WRITE_MIN 0x02 - -// CONFIG masks to check individual needed bits -#define CONF_ACCESS_PROT 0x80 - -#define VERSION_INFO_LENGTH 8 //8 bytes info length + crc - -#define BYTES_PER_READ 16 - -// SIGNATURE Length -#define SIGNATURE_LENGTH 32 - -// NTAG215_Version[7] mean: -// 0x0F ntag213 -// 0x11 ntag215 -// 0x13 ntag216 -const uint8_t ntagVersion[8] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x11, 0x03}; -/* pwd auth for amiibo */ -uint8_t ntagPwdOK[2] = {0x80, 0x80}; - -// Data structure pointer to the label information -static nfc_tag_ntag_information_t *m_tag_information = NULL; -// Define and use shadow anti -collision resources -static nfc_tag_14a_coll_res_reference_t m_shadow_coll_res; -//Define and use NTAG special communication buffer -static nfc_tag_ntag_tx_buffer_t m_tag_tx_buffer; -// Save the specific type of NTAG currently being simulated -static tag_specific_type_t m_tag_type; - -static int get_block_max_by_tag_type(tag_specific_type_t tag_type) { - int block_max; - switch (tag_type) { - case TAG_TYPE_NTAG_213: - block_max = NTAG213_PAGES; - break; - default: - case TAG_TYPE_NTAG_215: - block_max = NTAG215_PAGES; - break; - case TAG_TYPE_NTAG_216: - block_max = NTAG216_PAGES; - break; - } - return block_max; -} - -static int get_block_cfg_by_tag_type(tag_specific_type_t tag_type) { - int block_max; - switch (tag_type) { - case TAG_TYPE_NTAG_213: - block_max = NTAG213_CONFIG_AREA_START_ADDRESS; - break; - default: - case TAG_TYPE_NTAG_215: - block_max = NTAG215_CONFIG_AREA_START_ADDRESS; - break; - case TAG_TYPE_NTAG_216: - block_max = NTAG216_CONFIG_AREA_START_ADDRESS; - break; - } - return block_max; -} - -void nfc_tag_ntag_state_handler(uint8_t *p_data, uint16_t szDataBits) { - uint8_t command = p_data[0]; - uint8_t block_num = p_data[1]; - - switch (command) { - case CMD_GET_VERSION: - memcpy(m_tag_tx_buffer.tx_buffer, ntagVersion, 8); - switch (m_tag_type) { - case TAG_TYPE_NTAG_213: - m_tag_tx_buffer.tx_buffer[6] = NTAG213_VERSION; - break; - default: - case TAG_TYPE_NTAG_215: - m_tag_tx_buffer.tx_buffer[6] = NTAG215_VERSION; - break; - case TAG_TYPE_NTAG_216: - m_tag_tx_buffer.tx_buffer[6] = NTAG216_VERSION; - break; - } - nfc_tag_14a_tx_bytes(m_tag_tx_buffer.tx_buffer, 8, true); - break; - case CMD_READ: - if (block_num < get_block_max_by_tag_type(m_tag_type)) { - for (int block = 0; block < 4; block++) { - memcpy(m_tag_tx_buffer.tx_buffer + block * 4, m_tag_information->memory[block_num + block], NFC_TAG_NTAG_DATA_SIZE); - } - nfc_tag_14a_tx_bytes(m_tag_tx_buffer.tx_buffer, BYTES_PER_READ, true); - } else { - nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV, 4); - } - break; - case CMD_FAST_READ: { - uint8_t end_block_num = p_data[2]; - if ((block_num > end_block_num) || (block_num >= get_block_max_by_tag_type(m_tag_type)) || (end_block_num >= get_block_max_by_tag_type(m_tag_type))) { - nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBV, 4); - break; - } - for (int block = block_num; block <= end_block_num; block++) { - memcpy(m_tag_tx_buffer.tx_buffer + (block - block_num) * 4, m_tag_information->memory[block], NFC_TAG_NTAG_DATA_SIZE); - } - nfc_tag_14a_tx_bytes(m_tag_tx_buffer.tx_buffer, (end_block_num - block_num + 1) * NFC_TAG_NTAG_DATA_SIZE, true); - break; - } - case CMD_WRITE: - // TODO - nfc_tag_14a_tx_nbit(ACK_VALUE, 4); - break; - case CMD_COMPAT_WRITE: - // TODO - break; - case CMD_PWD_AUTH: { - /* TODO: IMPLEMENT COUNTER AUTHLIM */ - uint8_t Password[4]; - memcpy(Password, m_tag_information->memory[get_block_cfg_by_tag_type(m_tag_type) + CONF_PASSWORD_OFFSET], 4); - if (Password[0] != p_data[1] || Password[1] != p_data[2] || Password[2] != p_data[3] || Password[3] != p_data[4]) { - nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV, 4); - break; - } - /* Authenticate the user */ - //RESET AUTHLIM COUNTER, CURRENTLY NOT IMPLEMENTED - // TODO - /* Send the PACK value back */ - if (m_tag_information->config.mode_uid_magic) { - nfc_tag_14a_tx_bytes(ntagPwdOK, 2, true); - } else { - nfc_tag_14a_tx_bytes(m_tag_information->memory[get_block_cfg_by_tag_type(m_tag_type) + CONF_PASSWORD_OFFSET], 2, true); - } - break; - } - case CMD_READ_SIG: - memset(m_tag_tx_buffer.tx_buffer, 0xCA, SIGNATURE_LENGTH); - nfc_tag_14a_tx_bytes(m_tag_tx_buffer.tx_buffer, SIGNATURE_LENGTH, true); - break; - } - return; -} - -nfc_tag_14a_coll_res_reference_t *get_ntag_coll_res() { - // Use a separate anti -conflict information instead of using the information in the sector - m_shadow_coll_res.sak = m_tag_information->res_coll.sak; - m_shadow_coll_res.atqa = m_tag_information->res_coll.atqa; - m_shadow_coll_res.uid = m_tag_information->res_coll.uid; - m_shadow_coll_res.size = &(m_tag_information->res_coll.size); - m_shadow_coll_res.ats = &(m_tag_information->res_coll.ats); - // Finally, a shadow data structure pointer with only reference, no physical shadow, - return &m_shadow_coll_res; -} - -void nfc_tag_ntag_reset_handler() { - // TODO -} - -static int get_information_size_by_tag_type(tag_specific_type_t type) { - return sizeof(nfc_tag_14a_coll_res_entity_t) + sizeof(nfc_tag_ntag_configure_t) + (get_block_max_by_tag_type(type) * NFC_TAG_NTAG_DATA_SIZE); -} - -/** @brief ntag's callback before saving data - * @param type detailed label type - * @param buffer data buffer - * @return to be saved, the length of the data that needs to be saved, it means not saved when 0 - */ -int nfc_tag_ntag_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) { - if (m_tag_type != TAG_TYPE_UNDEFINED) { - // Save the corresponding size data according to the current label type - return get_information_size_by_tag_type(type); - } else { - return 0; - } -} - -int nfc_tag_ntag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) { - int info_size = get_information_size_by_tag_type(type); - if (buffer->length >= info_size) { - // Convert the data buffer to NTAG structure type - m_tag_information = (nfc_tag_ntag_information_t *)buffer->buffer; - // The specific type of NTAG that is simulated by the cache - m_tag_type = type; - // Register 14A communication management interface - nfc_tag_14a_handler_t handler_for_14a = { - .get_coll_res = get_ntag_coll_res, - .cb_state = nfc_tag_ntag_state_handler, - .cb_reset = nfc_tag_ntag_reset_handler, - }; - nfc_tag_14a_set_handler(&handler_for_14a); - NRF_LOG_INFO("HF ntag data load finish."); - } else { - NRF_LOG_ERROR("nfc_tag_ntag_information_t too big."); - } - return info_size; -} - -// Initialized NTAG factory data -bool nfc_tag_ntag_data_factory(uint8_t slot, tag_specific_type_t tag_type) { - // default ntag data - uint8_t default_p0[] = { 0x04, 0x68, 0x95, 0x71 }; - uint8_t default_p1[] = { 0xFA, 0x5C, 0x64, 0x80 }; - uint8_t default_p2[] = { 0x42, 0x48, 0x0F, 0xE0 }; - - // default ntag info - nfc_tag_ntag_information_t ntag_tmp_information; - nfc_tag_ntag_information_t *p_ntag_information; - p_ntag_information = &ntag_tmp_information; - int block_max = get_block_max_by_tag_type(tag_type); - for (int block = 0; block < block_max; block++) { - if (block == 0) { - memcpy(p_ntag_information->memory[block], default_p0, NFC_TAG_NTAG_DATA_SIZE); - } - if (block == 1) { - memcpy(p_ntag_information->memory[block], default_p1, NFC_TAG_NTAG_DATA_SIZE); - } - if (block == 2) { - memcpy(p_ntag_information->memory[block], default_p2, NFC_TAG_NTAG_DATA_SIZE); - } - } - - // default ntag auto ant-collision res - p_ntag_information->res_coll.atqa[0] = 0x44; - p_ntag_information->res_coll.atqa[1] = 0x00; - p_ntag_information->res_coll.sak[0] = 0x00; - p_ntag_information->res_coll.uid[0] = 0x04; - p_ntag_information->res_coll.uid[1] = 0x68; - p_ntag_information->res_coll.uid[2] = 0x95; - p_ntag_information->res_coll.uid[3] = 0x71; - p_ntag_information->res_coll.uid[4] = 0xFA; - p_ntag_information->res_coll.uid[5] = 0x5C; - p_ntag_information->res_coll.uid[6] = 0x64; - p_ntag_information->res_coll.size = NFC_TAG_14A_UID_DOUBLE_SIZE; - p_ntag_information->res_coll.ats.length = 0; - - // default ntag config - p_ntag_information->config.mode_uid_magic = true; - p_ntag_information->config.detection_enable = false; - - // save data to flash - tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); - fds_slot_record_map_t map_info; - get_fds_map_by_slot_sense_type_for_dump(slot, sense_type, &map_info); - int info_size = get_information_size_by_tag_type(tag_type); - NRF_LOG_INFO("NTAG info size: %d", info_size); - bool ret = fds_write_sync(map_info.id, map_info.key, info_size, p_ntag_information); - if (ret) { - NRF_LOG_INFO("Factory slot data success."); - } else { - NRF_LOG_ERROR("Factory slot data error."); - } - return ret; -} diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.h b/firmware/application/src/rfid/nfctag/hf/nfc_ntag.h deleted file mode 100644 index fcbd430..0000000 --- a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef NFC_NTAG_H -#define NFC_NTAG_H - -#include "nfc_14a.h" - -#define NFC_TAG_NTAG_DATA_SIZE 4 -#define NFC_TAG_NTAG_FRAME_SIZE 64 -#define NFC_TAG_NTAG_BLOCK_MAX 231 - -#define NTAG213_PAGES 45 //45 pages total for ntag213, from 0 to 44 -#define NTAG215_PAGES 135 //135 pages total for ntag215, from 0 to 134 -#define NTAG216_PAGES 231 //231 pages total for ntag216, from 0 to 230 - - -typedef struct { - uint8_t mode_uid_magic: 1; - uint8_t detection_enable: 1; - // reserve - uint8_t reserved1: 5; - uint8_t reserved2; - uint8_t reserved3; -} nfc_tag_ntag_configure_t; - -typedef struct __attribute__((aligned(4))) { - nfc_tag_14a_coll_res_entity_t res_coll; - nfc_tag_ntag_configure_t config; - uint8_t memory[NFC_TAG_NTAG_BLOCK_MAX][NFC_TAG_NTAG_DATA_SIZE]; -} -nfc_tag_ntag_information_t; - -typedef struct { - uint8_t tx_buffer[NFC_TAG_NTAG_FRAME_SIZE]; -} nfc_tag_ntag_tx_buffer_t; - -int nfc_tag_ntag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer); -int nfc_tag_ntag_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer); -bool nfc_tag_ntag_data_factory(uint8_t slot, tag_specific_type_t tag_type); - -#endif diff --git a/firmware/application/src/rfid/nfctag/tag_base_type.h b/firmware/application/src/rfid/nfctag/tag_base_type.h index 9f6b202..c4d3dac 100644 --- a/firmware/application/src/rfid/nfctag/tag_base_type.h +++ b/firmware/application/src/rfid/nfctag/tag_base_type.h @@ -75,6 +75,10 @@ typedef enum { TAG_TYPE_NTAG_213 = 1100, TAG_TYPE_NTAG_215, TAG_TYPE_NTAG_216, + TAG_TYPE_MF0ICU1, + TAG_TYPE_MF0ICU2, + TAG_TYPE_MF0UL11, + TAG_TYPE_MF0UL21, // MIFARE Plus series 1200 // DESFire series 1300 @@ -106,7 +110,11 @@ typedef enum { TAG_TYPE_MIFARE_4096,\ TAG_TYPE_NTAG_213,\ TAG_TYPE_NTAG_215,\ - TAG_TYPE_NTAG_216 + TAG_TYPE_NTAG_216,\ + TAG_TYPE_MF0ICU1,\ + TAG_TYPE_MF0ICU2,\ + TAG_TYPE_MF0UL11,\ + TAG_TYPE_MF0UL21 typedef struct { tag_specific_type_t tag_hf; diff --git a/firmware/application/src/rfid/nfctag/tag_emulation.c b/firmware/application/src/rfid/nfctag/tag_emulation.c index 65a05e4..85d77be 100644 --- a/firmware/application/src/rfid/nfctag/tag_emulation.c +++ b/firmware/application/src/rfid/nfctag/tag_emulation.c @@ -2,7 +2,7 @@ #include "nfc_14a.h" #include "lf_tag_em.h" #include "nfc_mf1.h" -#include "nfc_ntag.h" +#include "nfc_mf0_ntag.h" #include "fds_ids.h" #include "fds_util.h" #include "tag_emulation.h" @@ -71,7 +71,7 @@ static tag_slot_config_t slotConfig ALIGN_U32 = { // See tag_emulation_factory_init for actual tag content .slots = { { .enabled_hf = true, .enabled_lf = true, .tag_hf = TAG_TYPE_MIFARE_1024, .tag_lf = TAG_TYPE_EM410X, }, // 1 - { .enabled_hf = true, .enabled_lf = false, .tag_hf = TAG_TYPE_MIFARE_1024, .tag_lf = TAG_TYPE_UNDEFINED, }, // 2 + { .enabled_hf = true, .enabled_lf = false, .tag_hf = TAG_TYPE_MF0ICU1, .tag_lf = TAG_TYPE_UNDEFINED, }, // 2 { .enabled_hf = false, .enabled_lf = true, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_EM410X, }, // 3 { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 4 { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 5 @@ -100,9 +100,11 @@ static tag_base_handler_map_t tag_base_map[] = { { TAG_SENSE_HF, TAG_TYPE_MIFARE_2048, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf }, { TAG_SENSE_HF, TAG_TYPE_MIFARE_4096, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf }, // NTAG tag simulation - { TAG_SENSE_HF, TAG_TYPE_NTAG_213, nfc_tag_ntag_data_loadcb, nfc_tag_ntag_data_savecb, nfc_tag_ntag_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_NTAG_215, nfc_tag_ntag_data_loadcb, nfc_tag_ntag_data_savecb, nfc_tag_ntag_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_NTAG_216, nfc_tag_ntag_data_loadcb, nfc_tag_ntag_data_savecb, nfc_tag_ntag_data_factory, &m_tag_data_hf }, + { TAG_SENSE_HF, TAG_TYPE_NTAG_213, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, + { TAG_SENSE_HF, TAG_TYPE_NTAG_215, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, + { TAG_SENSE_HF, TAG_TYPE_NTAG_216, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, + // MF0 tag simulation + { TAG_SENSE_HF, TAG_TYPE_MF0ICU1, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, }; @@ -701,7 +703,7 @@ void tag_emulation_factory_init(void) { } } - if (slotConfig.slots[1].enabled_hf && slotConfig.slots[1].tag_hf == TAG_TYPE_MIFARE_1024) { + if (slotConfig.slots[1].enabled_hf && slotConfig.slots[1].tag_hf == TAG_TYPE_MF0ICU1) { // Initialize a high -frequency M1 card in the card slot 2, if it does not exist. get_fds_map_by_slot_sense_type_for_dump(1, TAG_SENSE_HF, &map_info); if (!fds_is_exists(map_info.id, map_info.key)) { diff --git a/firmware/application/src/rfid_main.h b/firmware/application/src/rfid_main.h index fd6279b..dadf6a3 100644 --- a/firmware/application/src/rfid_main.h +++ b/firmware/application/src/rfid_main.h @@ -8,7 +8,7 @@ #include "hw_connect.h" #include "nfc_14a.h" #include "nfc_mf1.h" -#include "nfc_ntag.h" +#include "nfc_mf0_ntag.h" #include "lf_tag_em.h" #include "tag_emulation.h" diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index bc36994..0b1bf01 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -1744,9 +1744,12 @@ class HFMFUDUMP(MFUAuthArgsUnit): class HFMFUEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequiredUnit): def args_parser(self) -> ArgumentParserNoExit: parser = ArgumentParserNoExit() - parser.description = 'Settings of Mifare Classic emulator' + parser.description = 'Settings of Mifare Ultralight / NTAG emulator' self.add_slot_args(parser) self.add_hf14a_anticoll_args(parser) + uid_magic_group = parser.add_mutually_exclusive_group() + uid_magic_group.add_argument('--enable-uid-magic', action='store_true', help="Enable UID magic mode") + uid_magic_group.add_argument('--disable-uid-magic', action='store_true', help="Disable UID magic mode") return parser def on_exec(self, args: argparse.Namespace): @@ -1763,6 +1766,10 @@ class HFMFUEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequired fwslot = SlotNumber.to_fw(self.slot_num) hf_tag_type = TagSpecificType(slotinfo[fwslot]['hf']) if hf_tag_type not in [ + TagSpecificType.MF0ICU1, + TagSpecificType.MF0ICU2, + TagSpecificType.MF0UL11, + TagSpecificType.MF0UL21, TagSpecificType.NTAG_213, TagSpecificType.NTAG_215, TagSpecificType.NTAG_216, @@ -1770,6 +1777,18 @@ class HFMFUEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequired print(f"{CR}Slot {self.slot_num} not configured as MIFARE Ultralight / NTAG{C0}") return change_requested, change_done, uid, atqa, sak, ats = self.update_hf14a_anticoll(args, uid, atqa, sak, ats) + + if args.enable_uid_magic: + change_requested = True + self.cmd.mf0_ntag_set_uid_magic_mode(True) + magic_mode = True + elif args.disable_uid_magic: + change_requested = True + self.cmd.mf0_ntag_set_uid_magic_mode(False) + magic_mode = False + else: + magic_mode = self.cmd.mf0_ntag_get_uid_magic_mode() + if change_done: print(' - MFU/NTAG Emulator settings updated') if not change_requested: @@ -1780,6 +1799,10 @@ class HFMFUEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequired print(f'- {"SAK:":40}{CY}{sak.hex().upper()}{C0}') if len(ats) > 0: print(f'- {"ATS:":40}{CY}{ats.hex().upper()}{C0}') + if magic_mode: + print(f'- {"UID Magic:":40}{CY}enabled{C0}') + else: + print(f'- {"UID Magic:":40}{CY}disabled{C0}') @lf_em_410x.command('read') diff --git a/software/script/chameleon_cmd.py b/software/script/chameleon_cmd.py index 2ef363d..5ed16a6 100644 --- a/software/script/chameleon_cmd.py +++ b/software/script/chameleon_cmd.py @@ -919,6 +919,17 @@ class ChameleonCMD: resp.parsed = {'uid': uid, 'atqa': atqa, 'sak': sak, 'ats': ats} return resp + @expect_response(Status.SUCCESS) + def mf0_ntag_get_uid_magic_mode(self): + resp = self.device.send_cmd_sync(Command.MF0_NTAG_GET_UID_MAGIC_MODE) + if resp.status == Status.SUCCESS: + resp.parsed, = struct.unpack('!?', resp.data) + return resp + + @expect_response(Status.SUCCESS) + def mf0_ntag_set_uid_magic_mode(self, enabled: bool): + return self.device.send_cmd_sync(Command.MF0_NTAG_SET_UID_MAGIC_MODE, struct.pack('?', enabled)) + @expect_response(Status.SUCCESS) def get_ble_pairing_enable(self): """ diff --git a/software/script/chameleon_enum.py b/software/script/chameleon_enum.py index 2c13b8f..2bd4d07 100644 --- a/software/script/chameleon_enum.py +++ b/software/script/chameleon_enum.py @@ -95,6 +95,8 @@ class Command(enum.IntEnum): MF1_GET_WRITE_MODE = 4016 MF1_SET_WRITE_MODE = 4017 HF14A_GET_ANTI_COLL_DATA = 4018 + MF0_NTAG_GET_UID_MAGIC_MODE = 4019 + MF0_NTAG_SET_UID_MAGIC_MODE = 4020 EM410X_SET_EMU_ID = 5000 EM410X_GET_EMU_ID = 5001 @@ -260,6 +262,10 @@ class TagSpecificType(enum.IntEnum): NTAG_213 = 1100 NTAG_215 = 1101 NTAG_216 = 1102 + MF0ICU1 = 1103 + MF0ICU2 = 1104 + MF0UL11 = 1105 + MF0UL21 = 1106 # MIFARE Plus series 1200 # DESFire series 1300 @@ -303,6 +309,14 @@ class TagSpecificType(enum.IntEnum): return "NTAG 215" elif self == TagSpecificType.NTAG_216: return "NTAG 216" + elif self == TagSpecificType.MF0ICU1: + return "Mifare Ultralight" + elif self == TagSpecificType.MF0ICU2: + return "Mifare Ultralight C" + elif self == TagSpecificType.MF0UL11: + return "Mifare Ultralight EV1 (640 bit)" + elif self == TagSpecificType.MF0UL21: + return "Mifare Ultralight EV1 (1312 bit)" elif self < TagSpecificType.OLD_TAG_TYPES_END: return "Old tag type, must be migrated! Upgrade fw!" return "Invalid" @@ -438,4 +452,4 @@ class ButtonPressFunction(enum.IntEnum): class MfcValueBlockOperator(enum.IntEnum): DECREMENT = 0xC0 INCREMENT = 0xC1 - RESTORE = 0xC2 \ No newline at end of file + RESTORE = 0xC2