Merge pull request #215 from turbocool3r/main

Add support for Ultralight emulation.
This commit is contained in:
DXL
2024-07-16 09:52:05 +08:00
committed by GitHub
19 changed files with 2454 additions and 413 deletions
+1
View File
@@ -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)
+44
View File
@@ -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
+1 -1
View File
@@ -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 \
+214 -5
View File
@@ -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 },
+8 -2
View File
@@ -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;
}
+2
View File
@@ -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
+11
View File
@@ -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)) {
+1 -1
View File
@@ -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
+100
View File
@@ -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):
"""
+36 -1
View File
@@ -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