mirror of
https://github.com/RfidResearchGroup/ChameleonUltra.git
synced 2026-09-11 18:30:14 -07:00
Merge pull request #215 from turbocool3r/main
Add support for Ultralight emulation.
This commit is contained in:
@@ -30,6 +30,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||
- Added support for timestamped comments in CLI via `rem`, `;`, `%` or `#` (@doegox)
|
||||
- Fixed watchdog trigger during `hw factory_reset` (@doegox)
|
||||
- Added PyInstaller support for CLI client (@augustozanellato)
|
||||
- Added proper Mifare Ultralight (original, C, EV1) / NTAG (213, 215, 216) emulation (@turbocooler).
|
||||
|
||||
## [v2.0.0][2023-09-26]
|
||||
- Added `hw slot nick delete` and DELETE_SLOT_TAG_NICK (@doegox)
|
||||
|
||||
@@ -388,6 +388,50 @@ Notes:
|
||||
* Command: no data
|
||||
* Response: no data or N bytes: `uidlen|uid[uidlen]|atqa[2]|sak|atslen|ats[atslen]`. UID, ATQA, SAK and ATS as bytes.
|
||||
* CLI: cf `hw slot list`/`hf mf econfig`/`hf mfu econfig`
|
||||
### 4019: MF0_NTAG_GET_UID_MAGIC_MODE
|
||||
* Command: no data
|
||||
* Response: 1 byte where a non-zero value indicates that UID magic mode is enabled for the current slot.
|
||||
* CLI: cf `hf mfu econfig`
|
||||
### 4020: MF0_NTAG_SET_UID_MAGIC_MODE
|
||||
* Command: 1 byte where a non-zero value indicates that UID magic mode should be enabled for the current slot, otherwise disabled.
|
||||
* Response: no data
|
||||
* CLI: cf `hf mfu econfig --enable-uid-magic`/`hf mfu econfig --disable-uid-magic`
|
||||
### 4021: MF0_NTAG_READ_EMU_PAGE_DATA
|
||||
* Command: 2 bytes: one for first page index, one for count of pages to be read.
|
||||
* Response: `4 * n` bytes where `n` is the number if pages to be read
|
||||
* CLI: cf `hf mfu eview`
|
||||
### 4022: MF0_NTAG_WRITE_EMU_PAGE_DATA
|
||||
* Command: 2 + `n * 4` bytes: one for first page index, one for count of pages to be read, `n * 4` for `n` pages data.
|
||||
* Response: no data
|
||||
* CLI: unused
|
||||
### 4023: MF0_NTAG_GET_VERSION_DATA
|
||||
* Command: no data
|
||||
* Response: 8 version data bytes.
|
||||
* CLI: cf `hf mfu econfig`
|
||||
### 4024: MF0_NTAG_SET_VERSION_DATA
|
||||
* Command: 8 version data bytes.
|
||||
* Response: no data
|
||||
* CLI: cf `hf mfu econfig --set-version <hex>`
|
||||
### 4025: MF0_NTAG_GET_SIGNATURE_DATA
|
||||
* Command: no data
|
||||
* Response: 32 signature data bytes.
|
||||
* CLI: cf `hf mfu econfig`
|
||||
### 4026: MF0_NTAG_SET_SIGNATURE_DATA
|
||||
* Command: 32 signature data bytes.
|
||||
* Response: no data
|
||||
* CLI: cf `hf mfu econfig --set-signature <hex>`
|
||||
### 4027: MF0_NTAG_GET_COUNTER_DATA
|
||||
* Command: 1 byte for the counter index
|
||||
* Response: 3 bytes for the counter value (big-endian) + 1 byte for tearing where `0xBD` means tearing flag is not set.
|
||||
* CLI: cf `hf mfu ercnt`
|
||||
### 4028: MF0_NTAG_SET_COUNTER_DATA
|
||||
* Command: 1 byte where the lower 7 bits are the counter index and the top bit indicates whether tearing event flag should be reset + 3 bytes of the counter value (big-endian).
|
||||
* Response: no data
|
||||
* CLI: cf `hf mfu ewcnt`
|
||||
### 4029: MF0_NTAG_RESET_AUTH_CNT
|
||||
* Command: no data
|
||||
* Response: 1 byte for the old value of the unsuccessful auth counter.
|
||||
* CLI: cf `hf mfu econfig --reset-auth-cnt`
|
||||
### 5000: EM410X_SET_EMU_ID
|
||||
* Command: 5 bytes. `id[5]`. ID as 5 bytes.
|
||||
* Response: no data
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -688,13 +688,44 @@ static data_frame_tx_t *cmd_processor_em410x_get_emu_id(uint16_t cmd, uint16_t s
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, LF_EM410X_TAG_ID_SIZE, responseData);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_hf14a_get_anti_coll_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
static nfc_tag_14a_coll_res_reference_t *get_coll_res_data(bool write) {
|
||||
nfc_tag_14a_coll_res_reference_t *info;
|
||||
tag_slot_specific_type_t tag_types;
|
||||
|
||||
tag_emulation_get_specific_types_by_slot(tag_emulation_get_slot(), &tag_types);
|
||||
if (tag_types.tag_hf == TAG_TYPE_UNDEFINED) {
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL); // no data in slot, don't send garbage
|
||||
|
||||
switch (tag_types.tag_hf) {
|
||||
case TAG_TYPE_MIFARE_1024:
|
||||
case TAG_TYPE_MIFARE_2048:
|
||||
case TAG_TYPE_MIFARE_4096:
|
||||
case TAG_TYPE_MIFARE_Mini:
|
||||
info = write ? get_mifare_coll_res() : get_saved_mifare_coll_res();
|
||||
break;
|
||||
case TAG_TYPE_MF0ICU1:
|
||||
case TAG_TYPE_MF0ICU2:
|
||||
case TAG_TYPE_MF0UL11:
|
||||
case TAG_TYPE_MF0UL21:
|
||||
case TAG_TYPE_NTAG_210:
|
||||
case TAG_TYPE_NTAG_212:
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216:
|
||||
info = nfc_tag_mf0_ntag_get_coll_res();
|
||||
break;
|
||||
default:
|
||||
// no collision resolution data for slot
|
||||
info = NULL;
|
||||
break;
|
||||
}
|
||||
nfc_tag_14a_coll_res_reference_t *info = get_saved_mifare_coll_res();
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_hf14a_get_anti_coll_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
nfc_tag_14a_coll_res_reference_t *info = get_coll_res_data(false);
|
||||
|
||||
if (info == NULL) return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
|
||||
// uidlen[1]|uid[uidlen]|atqa[2]|sak[1]|atslen[1]|ats[atslen]
|
||||
// dynamic length, so no struct
|
||||
uint8_t payload[1 + *info->size + 2 + 1 + 1 + 254];
|
||||
@@ -790,6 +821,154 @@ static data_frame_tx_t *cmd_processor_mf1_read_emu_block_data(uint16_t cmd, uint
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, result_length, result_buffer);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf0_ntag_write_emu_page_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
uint8_t byte;
|
||||
uint8_t active_slot = tag_emulation_get_slot();
|
||||
|
||||
tag_slot_specific_type_t active_slot_tag_types;
|
||||
tag_emulation_get_specific_types_by_slot(active_slot, &active_slot_tag_types);
|
||||
|
||||
int nr_pages = nfc_tag_mf0_ntag_get_nr_pages_by_tag_type(active_slot_tag_types.tag_hf);
|
||||
// This means wrong slot type.
|
||||
if (nr_pages <= 0) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, data);
|
||||
|
||||
if (length < 2) {
|
||||
byte = nr_pages;
|
||||
return data_frame_make(cmd, STATUS_INVALID_PARAMS, 1, &byte);
|
||||
}
|
||||
|
||||
int page_index = data[0];
|
||||
int pages_count = data[1];
|
||||
int byte_length = (int)pages_count * NFC_TAG_MF0_NTAG_DATA_SIZE;
|
||||
|
||||
if (pages_count == 0) return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
else if (
|
||||
(page_index >= ((int)nr_pages))
|
||||
|| (pages_count > (((int)nr_pages) - page_index))
|
||||
|| (((int)length - 2) < byte_length)
|
||||
) {
|
||||
byte = nr_pages;
|
||||
return data_frame_make(cmd, STATUS_INVALID_PARAMS, 1, &byte);
|
||||
}
|
||||
|
||||
tag_data_buffer_t *buffer = get_buffer_by_tag_type(active_slot_tag_types.tag_hf);
|
||||
nfc_tag_mf0_ntag_information_t *info = (nfc_tag_mf0_ntag_information_t *)buffer->buffer;
|
||||
|
||||
memcpy(&info->memory[page_index][0], &data[2], byte_length);
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf0_ntag_read_emu_page_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
uint8_t byte;
|
||||
uint8_t active_slot = tag_emulation_get_slot();
|
||||
|
||||
tag_slot_specific_type_t active_slot_tag_types;
|
||||
tag_emulation_get_specific_types_by_slot(active_slot, &active_slot_tag_types);
|
||||
|
||||
int nr_pages = nfc_tag_mf0_ntag_get_nr_pages_by_tag_type(active_slot_tag_types.tag_hf);
|
||||
// This means wrong slot type.
|
||||
if (nr_pages <= 0) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, data);
|
||||
|
||||
if (length < 2) {
|
||||
byte = nr_pages;
|
||||
return data_frame_make(cmd, STATUS_INVALID_PARAMS, 1, &byte);
|
||||
}
|
||||
|
||||
int page_index = data[0];
|
||||
int pages_count = data[1];
|
||||
|
||||
if (pages_count == 0) return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
else if ((page_index >= ((int)nr_pages)) || (pages_count > (((int)nr_pages) - page_index))) {
|
||||
byte = nr_pages;
|
||||
return data_frame_make(cmd, STATUS_INVALID_PARAMS, 1, &byte);
|
||||
}
|
||||
|
||||
tag_data_buffer_t *buffer = get_buffer_by_tag_type(active_slot_tag_types.tag_hf);
|
||||
nfc_tag_mf0_ntag_information_t *info = (nfc_tag_mf0_ntag_information_t *)buffer->buffer;
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, pages_count * NFC_TAG_MF0_NTAG_DATA_SIZE, &info->memory[page_index][0]);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf0_ntag_get_version_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
uint8_t *version_data = nfc_tag_mf0_ntag_get_version_data();
|
||||
if (version_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, NFC_TAG_MF0_NTAG_VER_SIZE, version_data);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf0_ntag_set_version_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if (length != 8) return data_frame_make(cmd, STATUS_INVALID_PARAMS, 0, NULL);
|
||||
|
||||
uint8_t *version_data = nfc_tag_mf0_ntag_get_version_data();
|
||||
if (version_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);
|
||||
memcpy(version_data, data, NFC_TAG_MF0_NTAG_VER_SIZE);
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf0_ntag_get_signature_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
uint8_t *signature_data = nfc_tag_mf0_ntag_get_signature_data();
|
||||
if (signature_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, NFC_TAG_MF0_NTAG_SIG_SIZE, signature_data);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf0_ntag_set_signature_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if (length != NFC_TAG_MF0_NTAG_SIG_SIZE) return data_frame_make(cmd, STATUS_INVALID_PARAMS, 0, NULL);
|
||||
|
||||
uint8_t *signature_data = nfc_tag_mf0_ntag_get_signature_data();
|
||||
if (signature_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);
|
||||
memcpy(signature_data, data, NFC_TAG_MF0_NTAG_SIG_SIZE);
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf0_ntag_get_counter_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if (length != 1) return data_frame_make(cmd, STATUS_INVALID_PARAMS, 0, NULL);
|
||||
|
||||
uint8_t index = data[0] & 0x7F;
|
||||
uint8_t *counter_data = nfc_tag_mf0_ntag_get_counter_data_by_index(index);
|
||||
if (counter_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);
|
||||
|
||||
bool tearing = (counter_data[MF0_NTAG_AUTHLIM_OFF_IN_CTR] & MF0_NTAG_AUTHLIM_MASK_IN_CTR) != 0;
|
||||
|
||||
uint8_t response[4];
|
||||
memcpy(response, counter_data, 3);
|
||||
response[3] = tearing ? 0x00 : 0xBD;
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 4, response);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf0_ntag_set_counter_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if (length != 4) return data_frame_make(cmd, STATUS_INVALID_PARAMS, 0, NULL);
|
||||
|
||||
uint8_t index = data[0] & 0x7F;
|
||||
uint8_t *counter_data = nfc_tag_mf0_ntag_get_counter_data_by_index(index);
|
||||
if (counter_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);
|
||||
|
||||
// clear tearing event flag
|
||||
if ((data[0] & 0x80) == 0x80) {
|
||||
counter_data[MF0_NTAG_AUTHLIM_OFF_IN_CTR] &= ~MF0_NTAG_TEARING_MASK_IN_AUTHLIM;
|
||||
}
|
||||
|
||||
// copy the actual counter value
|
||||
memcpy(counter_data, &data[1], 3);
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf0_ntag_reset_auth_cnt(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
// all tags with counters support auth
|
||||
uint8_t *counter_data = nfc_tag_mf0_ntag_get_counter_data_by_index(0);
|
||||
if (counter_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);
|
||||
|
||||
uint8_t old_value = counter_data[MF0_NTAG_AUTHLIM_OFF_IN_CTR] & MF0_NTAG_AUTHLIM_MASK_IN_CTR;
|
||||
counter_data[MF0_NTAG_AUTHLIM_OFF_IN_CTR] &= ~MF0_NTAG_AUTHLIM_MASK_IN_CTR;
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 1, &old_value);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_hf14a_set_anti_coll_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
// uidlen[1]|uid[uidlen]|atqa[2]|sak[1]|atslen[1]|ats[atslen]
|
||||
// dynamic length, so no struct
|
||||
@@ -799,7 +978,8 @@ static data_frame_tx_t *cmd_processor_hf14a_set_anti_coll_data(uint16_t cmd, uin
|
||||
(length < 1 + data[0] + 2 + 1 + 1 + data[1 + data[0] + 2 + 1])) {
|
||||
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
|
||||
}
|
||||
nfc_tag_14a_coll_res_reference_t *info = get_mifare_coll_res();
|
||||
nfc_tag_14a_coll_res_reference_t *info = get_coll_res_data(true);
|
||||
|
||||
uint16_t offset = 0;
|
||||
*(info->size) = (nfc_tag_14a_uid_size)data[offset];
|
||||
offset++;
|
||||
@@ -1026,6 +1206,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 +1307,17 @@ 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_MF0_NTAG_READ_EMU_PAGE_DATA, NULL, cmd_processor_mf0_ntag_read_emu_page_data, NULL },
|
||||
{ DATA_CMD_MF0_NTAG_WRITE_EMU_PAGE_DATA, NULL, cmd_processor_mf0_ntag_write_emu_page_data, NULL },
|
||||
{ DATA_CMD_MF0_NTAG_GET_VERSION_DATA, NULL, cmd_processor_mf0_ntag_get_version_data, NULL },
|
||||
{ DATA_CMD_MF0_NTAG_SET_VERSION_DATA, NULL, cmd_processor_mf0_ntag_set_version_data, NULL },
|
||||
{ DATA_CMD_MF0_NTAG_GET_SIGNATURE_DATA, NULL, cmd_processor_mf0_ntag_get_signature_data, NULL },
|
||||
{ DATA_CMD_MF0_NTAG_SET_SIGNATURE_DATA, NULL, cmd_processor_mf0_ntag_set_signature_data, NULL },
|
||||
{ DATA_CMD_MF0_NTAG_GET_COUNTER_DATA, NULL, cmd_processor_mf0_ntag_get_counter_data, NULL },
|
||||
{ DATA_CMD_MF0_NTAG_SET_COUNTER_DATA, NULL, cmd_processor_mf0_ntag_set_counter_data, NULL },
|
||||
{ DATA_CMD_MF0_NTAG_RESET_AUTH_CNT, NULL, cmd_processor_mf0_ntag_reset_auth_cnt, 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 },
|
||||
|
||||
@@ -651,10 +651,16 @@ static void btn_fn_copy_ic_uid(void) {
|
||||
break;
|
||||
}
|
||||
|
||||
case TAG_TYPE_NTAG_210:
|
||||
case TAG_TYPE_NTAG_212:
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -32,4 +32,6 @@
|
||||
#define STATUS_NOT_IMPLEMENTED (0x69) // Calling some unrealized operations, which belongs to the missed error of the developer
|
||||
#define STATUS_FLASH_WRITE_FAIL (0x70) // Flash writing failed
|
||||
#define STATUS_FLASH_READ_FAIL (0x71) // Flash read failed
|
||||
#define STATUS_INVALID_SLOT_TYPE (0x72) // Invalid slot type
|
||||
#define STATUS_INVALID_PARAMS (0x73) // Invalid command parameters
|
||||
#endif
|
||||
|
||||
@@ -106,6 +106,17 @@
|
||||
#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)
|
||||
#define DATA_CMD_MF0_NTAG_READ_EMU_PAGE_DATA (4021)
|
||||
#define DATA_CMD_MF0_NTAG_WRITE_EMU_PAGE_DATA (4022)
|
||||
#define DATA_CMD_MF0_NTAG_GET_VERSION_DATA (4023)
|
||||
#define DATA_CMD_MF0_NTAG_SET_VERSION_DATA (4024)
|
||||
#define DATA_CMD_MF0_NTAG_GET_SIGNATURE_DATA (4025)
|
||||
#define DATA_CMD_MF0_NTAG_SET_SIGNATURE_DATA (4026)
|
||||
#define DATA_CMD_MF0_NTAG_GET_COUNTER_DATA (4027)
|
||||
#define DATA_CMD_MF0_NTAG_SET_COUNTER_DATA (4028)
|
||||
#define DATA_CMD_MF0_NTAG_RESET_AUTH_CNT (4029)
|
||||
//
|
||||
// ******************************************************************
|
||||
|
||||
|
||||
@@ -295,6 +295,7 @@ uint8_t nfc_tag_14a_unwrap_frame(const uint8_t *pbtFrame, const size_t szFrameBi
|
||||
* @param[in] appendCrc Whether to send the byte flow, automatically send the CRC16 verification automatically
|
||||
*/
|
||||
void nfc_tag_14a_tx_bytes(uint8_t *data, uint32_t bytes, bool appendCrc) {
|
||||
ASSERT(bytes <= MAX_NFC_TX_BUFFER_SIZE);
|
||||
NFC_14A_TX_BYTE_CORE(data, bytes, appendCrc, NRF_NFCT_FRAME_DELAY_MODE_WINDOWGRID);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "tag_emulation.h"
|
||||
|
||||
#define MAX_NFC_RX_BUFFER_SIZE 64
|
||||
#define MAX_NFC_RX_BUFFER_SIZE 257
|
||||
#define MAX_NFC_TX_BUFFER_SIZE 64
|
||||
|
||||
#define NFC_TAG_14A_CRC_LENGTH 2
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,83 @@
|
||||
#ifndef NFC_NTAG_H
|
||||
#define NFC_NTAG_H
|
||||
|
||||
#include "nfc_14a.h"
|
||||
|
||||
#define NFC_TAG_MF0_NTAG_DATA_SIZE 4
|
||||
#define NFC_TAG_MF0_NTAG_SIG_SIZE 32
|
||||
#define NFC_TAG_MF0_NTAG_VER_SIZE 8
|
||||
#define NFC_TAG_MF0_NTAG_SIG_PAGES (NFC_TAG_MF0_NTAG_SIG_SIZE / NFC_TAG_MF0_NTAG_DATA_SIZE)
|
||||
#define NFC_TAG_MF0_NTAG_VER_PAGES (NFC_TAG_MF0_NTAG_VER_SIZE / NFC_TAG_MF0_NTAG_DATA_SIZE)
|
||||
|
||||
#define NFC_TAG_MF0_FRAME_SIZE (16 + NFC_TAG_14A_CRC_LENGTH)
|
||||
#define NFC_TAG_MF0_BLOCK_MAX 41
|
||||
|
||||
#define MF0ULx1_NUM_CTRS 3 // number of Ultralight EV1 one-way counters
|
||||
#define NTAG_NUM_CTRS 1 // number of NTAG one-way counters
|
||||
|
||||
#define MF0ULx1_EXTRA_PAGES (MF0ULx1_NUM_CTRS + NFC_TAG_MF0_NTAG_VER_PAGES + NFC_TAG_MF0_NTAG_SIG_PAGES)
|
||||
#define NTAG_EXTRA_PAGES (NTAG_NUM_CTRS + NFC_TAG_MF0_NTAG_VER_PAGES + NFC_TAG_MF0_NTAG_SIG_PAGES)
|
||||
|
||||
#define NTAG210_PAGES 20 //20 pages total for ntag210, from 0 to 44
|
||||
#define NTAG210_TOTAL_PAGES (NTAG210_PAGES + NTAG_EXTRA_PAGES) // 1 more page for the counter
|
||||
#define NTAG212_PAGES 41 //41 pages total for ntag212, from 0 to 44
|
||||
#define NTAG212_TOTAL_PAGES (NTAG212_PAGES + NTAG_EXTRA_PAGES) // 1 more page for the counter
|
||||
#define NTAG213_PAGES 45 //45 pages total for ntag213, from 0 to 44
|
||||
#define NTAG213_TOTAL_PAGES (NTAG213_PAGES + NTAG_EXTRA_PAGES) // 1 more page for the counter
|
||||
#define NTAG215_PAGES 135 //135 pages total for ntag215, from 0 to 134
|
||||
#define NTAG215_TOTAL_PAGES (NTAG215_PAGES + NTAG_EXTRA_PAGES) // 1 more page for the counter
|
||||
#define NTAG216_PAGES 231 //231 pages total for ntag216, from 0 to 230
|
||||
#define NTAG216_TOTAL_PAGES (NTAG216_PAGES + NTAG_EXTRA_PAGES) // 1 more page for the counter
|
||||
|
||||
#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 MF0UL11_TOTAL_PAGES (MF0UL11_PAGES + MF0ULx1_EXTRA_PAGES) // 3 more pages for 3 one way counters
|
||||
#define MF0UL21_PAGES 41 //231 pages total for MF0UL21 (UL EV1), from 0 to 40
|
||||
#define MF0UL21_TOTAL_PAGES (MF0UL21_PAGES + MF0ULx1_EXTRA_PAGES) // 3 more pages for 3 one way counters
|
||||
|
||||
#define NFC_TAG_NTAG_FRAME_SIZE 64
|
||||
#define NFC_TAG_NTAG_BLOCK_MAX NTAG216_TOTAL_PAGES
|
||||
|
||||
// Since all counters are 24-bit and each currently supported tag that supports counters
|
||||
// has password authentication we store the auth attempts counter in the last bit of the
|
||||
// first counter. AUTHLIM is only 3 bits though so we reserve 4 bits just to be sure and
|
||||
// use the top bit for tearing event flag.
|
||||
#define MF0_NTAG_AUTHLIM_OFF_IN_CTR 3
|
||||
#define MF0_NTAG_AUTHLIM_MASK_IN_CTR 0xF
|
||||
#define MF0_NTAG_TEARING_MASK_IN_AUTHLIM 0x80
|
||||
|
||||
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 {
|
||||
// TX buffer must fit the largest possible frame size.
|
||||
// TODO: This size should be decreased as the maximum allowed frame size is 257 (see 6.14.13.36 in datasheet).
|
||||
uint8_t tx_buffer[NFC_TAG_NTAG_BLOCK_MAX * NFC_TAG_MF0_NTAG_DATA_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_nr_pages_by_tag_type(tag_specific_type_t tag_type);
|
||||
uint8_t *nfc_tag_mf0_ntag_get_counter_data_by_index(uint8_t index);
|
||||
uint8_t *nfc_tag_mf0_ntag_get_version_data(void);
|
||||
uint8_t *nfc_tag_mf0_ntag_get_signature_data(void);
|
||||
nfc_tag_14a_coll_res_reference_t *nfc_tag_mf0_ntag_get_coll_res(void);
|
||||
|
||||
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,12 @@ 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,
|
||||
TAG_TYPE_NTAG_210,
|
||||
TAG_TYPE_NTAG_212,
|
||||
// MIFARE Plus series 1200
|
||||
// DESFire series 1300
|
||||
|
||||
@@ -106,7 +112,13 @@ 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,\
|
||||
TAG_TYPE_NTAG_210,\
|
||||
TAG_TYPE_NTAG_212
|
||||
|
||||
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"
|
||||
@@ -100,9 +100,16 @@ 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_210, 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_212, 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_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 },
|
||||
{ TAG_SENSE_HF, TAG_TYPE_MF0ICU2, 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_MF0UL11, 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_MF0UL21, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf },
|
||||
};
|
||||
|
||||
|
||||
@@ -701,7 +708,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"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -573,6 +573,71 @@ class ChameleonCMD:
|
||||
resp.parsed = resp.data
|
||||
return resp
|
||||
|
||||
@expect_response(Status.INVALID_PARAMS)
|
||||
def mfu_get_emu_pages_count(self):
|
||||
"""
|
||||
Gets the number of pages available in the current MF0 / NTAG slot
|
||||
"""
|
||||
data = struct.pack('!BB', 255, 255)
|
||||
resp = self.device.send_cmd_sync(Command.MF0_NTAG_READ_EMU_PAGE_DATA, data)
|
||||
if len(resp.data) > 0:
|
||||
resp.parsed = resp.data[0]
|
||||
return resp
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def mfu_read_emu_page_data(self, page_start: int, page_count: int):
|
||||
"""
|
||||
Gets data for selected block range
|
||||
"""
|
||||
data = struct.pack('!BB', page_start, page_count)
|
||||
resp = self.device.send_cmd_sync(Command.MF0_NTAG_READ_EMU_PAGE_DATA, data)
|
||||
resp.parsed = resp.data
|
||||
return resp
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def mfu_write_emu_page_data(self, page_start: int, data: bytes):
|
||||
"""
|
||||
Gets data for selected block range
|
||||
"""
|
||||
count = len(data) >> 2
|
||||
|
||||
assert (len(data) % 4) == 0
|
||||
assert (page_start >= 0) and (count + page_start) <= 256
|
||||
|
||||
data = struct.pack('!BB', page_start, count) + data
|
||||
resp = self.device.send_cmd_sync(Command.MF0_NTAG_WRITE_EMU_PAGE_DATA, data)
|
||||
return resp
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def mfu_read_emu_counter_data(self, index: int) -> (int, bool):
|
||||
"""
|
||||
Gets data for selected counter
|
||||
"""
|
||||
data = struct.pack('!B', index)
|
||||
resp = self.device.send_cmd_sync(Command.MF0_NTAG_GET_COUNTER_DATA, data)
|
||||
if resp.status == Status.SUCCESS:
|
||||
resp.parsed = (((resp.data[0] << 16) | (resp.data[1] << 8) | resp.data[2]), resp.data[3] == 0xBD)
|
||||
return resp
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def mfu_write_emu_counter_data(self, index: int, value: int, reset_tearing: bool):
|
||||
"""
|
||||
Sets data for selected counter
|
||||
"""
|
||||
data = struct.pack('!BBBB', index | (int(reset_tearing) << 7), (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF)
|
||||
resp = self.device.send_cmd_sync(Command.MF0_NTAG_SET_COUNTER_DATA, data)
|
||||
return resp
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def mfu_reset_auth_cnt(self):
|
||||
"""
|
||||
Resets authentication counter
|
||||
"""
|
||||
resp = self.device.send_cmd_sync(Command.MF0_NTAG_RESET_AUTH_CNT, bytes())
|
||||
if resp.status == Status.SUCCESS:
|
||||
resp.parsed = resp.data[0]
|
||||
return resp
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def hf14a_set_anti_coll_data(self, uid: bytes, atqa: bytes, sak: bytes, ats: bytes = b''):
|
||||
"""
|
||||
@@ -919,6 +984,41 @@ 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 mf0_ntag_get_version_data(self):
|
||||
resp = self.device.send_cmd_sync(Command.MF0_NTAG_GET_VERSION_DATA)
|
||||
if resp.status == Status.SUCCESS:
|
||||
resp.parsed = resp.data[:8]
|
||||
return resp
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def mf0_ntag_set_version_data(self, data: bytes):
|
||||
assert len(data) == 8
|
||||
return self.device.send_cmd_sync(Command.MF0_NTAG_SET_VERSION_DATA, data)
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def mf0_ntag_get_signature_data(self):
|
||||
resp = self.device.send_cmd_sync(Command.MF0_NTAG_GET_SIGNATURE_DATA)
|
||||
if resp.status == Status.SUCCESS:
|
||||
resp.parsed = resp.data[:32]
|
||||
return resp
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def mf0_ntag_set_signature_data(self, data: bytes):
|
||||
assert len(data) == 32
|
||||
return self.device.send_cmd_sync(Command.MF0_NTAG_SET_SIGNATURE_DATA, data)
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def get_ble_pairing_enable(self):
|
||||
"""
|
||||
|
||||
@@ -95,6 +95,17 @@ 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
|
||||
MF0_NTAG_READ_EMU_PAGE_DATA = 4021
|
||||
MF0_NTAG_WRITE_EMU_PAGE_DATA = 4022
|
||||
MF0_NTAG_GET_VERSION_DATA = 4023
|
||||
MF0_NTAG_SET_VERSION_DATA = 4024
|
||||
MF0_NTAG_GET_SIGNATURE_DATA = 4025
|
||||
MF0_NTAG_SET_SIGNATURE_DATA = 4026
|
||||
MF0_NTAG_GET_COUNTER_DATA = 4027
|
||||
MF0_NTAG_SET_COUNTER_DATA = 4028
|
||||
MF0_NTAG_RESET_AUTH_CNT = 4029
|
||||
|
||||
EM410X_SET_EMU_ID = 5000
|
||||
EM410X_GET_EMU_ID = 5001
|
||||
@@ -127,6 +138,8 @@ class Status(enum.IntEnum):
|
||||
NOT_IMPLEMENTED = 0x69
|
||||
FLASH_WRITE_FAIL = 0x70
|
||||
FLASH_READ_FAIL = 0x71
|
||||
INVALID_SLOT_TYPE = 0x72
|
||||
INVALID_PARAMS = 0x73
|
||||
|
||||
def __str__(self):
|
||||
if self == Status.HF_TAG_OK:
|
||||
@@ -165,6 +178,10 @@ class Status(enum.IntEnum):
|
||||
return "Flash write failed"
|
||||
elif self == Status.FLASH_READ_FAIL:
|
||||
return "Flash read failed"
|
||||
elif self == Status.INVALID_SLOT_TYPE:
|
||||
return "Invalid card type in slot"
|
||||
elif self == Status.INVALID_PARAMS:
|
||||
return "Invalid command parameters"
|
||||
return "Invalid status"
|
||||
|
||||
|
||||
@@ -260,6 +277,12 @@ class TagSpecificType(enum.IntEnum):
|
||||
NTAG_213 = 1100
|
||||
NTAG_215 = 1101
|
||||
NTAG_216 = 1102
|
||||
MF0ICU1 = 1103
|
||||
MF0ICU2 = 1104
|
||||
MF0UL11 = 1105
|
||||
MF0UL21 = 1106
|
||||
NTAG_210 = 1107
|
||||
NTAG_212 = 1108
|
||||
# MIFARE Plus series 1200
|
||||
# DESFire series 1300
|
||||
|
||||
@@ -303,6 +326,18 @@ 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.NTAG_210:
|
||||
return "NTAG 210"
|
||||
elif self == TagSpecificType.NTAG_212:
|
||||
return "NTAG 212"
|
||||
elif self < TagSpecificType.OLD_TAG_TYPES_END:
|
||||
return "Old tag type, must be migrated! Upgrade fw!"
|
||||
return "Invalid"
|
||||
@@ -438,4 +473,4 @@ class ButtonPressFunction(enum.IntEnum):
|
||||
class MfcValueBlockOperator(enum.IntEnum):
|
||||
DECREMENT = 0xC0
|
||||
INCREMENT = 0xC1
|
||||
RESTORE = 0xC2
|
||||
RESTORE = 0xC2
|
||||
|
||||
Reference in New Issue
Block a user