mirror of
https://github.com/RfidResearchGroup/ChameleonUltra.git
synced 2026-05-12 11:22:59 -07:00
Add support for Ultralight emulation.
This version only emulates MF0ICU1 properly.
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
//
|
||||
// ******************************************************************
|
||||
|
||||
|
||||
@@ -0,0 +1,492 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -1,301 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
RESTORE = 0xC2
|
||||
|
||||
Reference in New Issue
Block a user