NFC: Implement Type 4 Tag saving

This commit is contained in:
Willy-JL
2025-03-06 02:21:47 +00:00
parent d5161f0806
commit aa38025977
7 changed files with 107 additions and 28 deletions

View File

@@ -41,6 +41,7 @@ void type_4_tag_reset(Type4TagData* data) {
iso14443_4a_reset(data->iso14443_4a_data);
data->is_tag_specific = false;
data->t4t_version.value = 0;
data->chunk_max_read = 0;
data->chunk_max_write = 0;
@@ -60,6 +61,7 @@ void type_4_tag_copy(Type4TagData* data, const Type4TagData* other) {
iso14443_4a_copy(data->iso14443_4a_data, other->iso14443_4a_data);
data->is_tag_specific = other->is_tag_specific;
data->t4t_version.value = other->t4t_version.value;
data->chunk_max_read = other->chunk_max_read;
data->chunk_max_write = other->chunk_max_write;
@@ -89,6 +91,8 @@ bool type_4_tag_load(Type4TagData* data, FlipperFormat* ff, uint32_t version) {
do {
if(!iso14443_4a_load(data->iso14443_4a_data, ff, version)) break;
if(!type_4_tag_ndef_data_load(data, ff)) break;
success = true;
} while(false);
@@ -109,6 +113,7 @@ bool type_4_tag_save(const Type4TagData* data, FlipperFormat* ff) {
if(!flipper_format_write_comment_cstr(ff, TYPE_4_TAG_PROTOCOL_NAME " specific data"))
break;
if(!type_4_tag_ndef_data_save(data, ff)) break;
success = true;
} while(false);
@@ -122,6 +127,7 @@ bool type_4_tag_is_equal(const Type4TagData* data, const Type4TagData* other) {
furi_check(other);
return iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data) &&
data->is_tag_specific == other->is_tag_specific &&
data->t4t_version.value == other->t4t_version.value &&
data->chunk_max_read == other->chunk_max_read &&
data->chunk_max_write == other->chunk_max_write &&

View File

@@ -17,7 +17,8 @@ typedef enum {
typedef struct {
Iso14443_4aData* iso14443_4a_data;
// Tag specific
// Tag specific data
bool is_tag_specific;
union {
struct {
uint8_t minor : 4;

View File

@@ -1,3 +1,63 @@
#include "type_4_tag_i.h"
#define TAG "Type4Tag"
#define TYPE_4_TAG_FFF_NDEF_DATA_SIZE_KEY "NDEF Data Size"
#define TYPE_4_TAG_FFF_NDEF_DATA_KEY "NDEF Data"
#define TYPE_4_TAG_FFF_NDEF_DATA_PER_LINE (16U)
bool type_4_tag_ndef_data_load(Type4TagData* data, FlipperFormat* ff) {
uint32_t ndef_data_size;
if(!flipper_format_read_uint32(ff, TYPE_4_TAG_FFF_NDEF_DATA_SIZE_KEY, &ndef_data_size, 1)) {
return false;
}
if(ndef_data_size == 0) {
return true;
}
simple_array_init(data->ndef_data, ndef_data_size);
uint32_t ndef_data_pos = 0;
uint8_t* ndef_data = simple_array_get_data(data->ndef_data);
while(ndef_data_size > 0) {
uint8_t ndef_line_size = MIN(ndef_data_size, TYPE_4_TAG_FFF_NDEF_DATA_PER_LINE);
if(!flipper_format_read_hex(
ff, TYPE_4_TAG_FFF_NDEF_DATA_KEY, &ndef_data[ndef_data_pos], ndef_line_size)) {
simple_array_reset(data->ndef_data);
return false;
}
ndef_data_pos += ndef_line_size;
ndef_data_size -= ndef_line_size;
}
return true;
}
bool type_4_tag_ndef_data_save(const Type4TagData* data, FlipperFormat* ff) {
uint32_t ndef_data_size = simple_array_get_count(data->ndef_data);
if(!flipper_format_write_uint32(ff, TYPE_4_TAG_FFF_NDEF_DATA_SIZE_KEY, &ndef_data_size, 1)) {
return false;
}
if(ndef_data_size == 0) {
return true;
}
uint32_t ndef_data_pos = 0;
uint8_t* ndef_data = simple_array_get_data(data->ndef_data);
while(ndef_data_size > 0) {
uint8_t ndef_line_size = MIN(ndef_data_size, TYPE_4_TAG_FFF_NDEF_DATA_PER_LINE);
if(!flipper_format_write_hex(
ff, TYPE_4_TAG_FFF_NDEF_DATA_KEY, &ndef_data[ndef_data_pos], ndef_line_size)) {
return false;
}
ndef_data_pos += ndef_line_size;
ndef_data_size -= ndef_line_size;
}
return true;
}

View File

@@ -2,26 +2,30 @@
#include "type_4_tag.h"
// ISO SELECT FILE command and parameters
#define TYPE_4_TAG_ISO_SELECT_CMD 0x00, 0xA4
#define TYPE_4_TAG_ISO_SELECT_P1_BY_NAME (0x04)
#define TYPE_4_TAG_ISO_SELECT_P1_BY_ID (0x00)
#define TYPE_4_TAG_ISO_SELECT_P2_EMPTY (0x0C)
#define TYPE_4_TAG_ISO_SELECT_LE_EMPTY (0x00)
// ISO READ BINARY command and parameters
#define TYPE_4_TAG_ISO_READ_CMD 0x00, 0xB0
#define TYPE_4_TAG_ISO_READ_P1_EMPTY (0x00)
#define TYPE_4_TAG_ISO_READ_P2_BEGINNING (0x00)
#define TYPE_4_TAG_ISO_READ_LE_FULL (0x00)
#define TYPE_4_TAG_ISO_STATUS_LEN (2)
// Common APDU parameters and values
#define TYPE_4_TAG_ISO_STATUS_LEN (2U)
#define TYPE_4_TAG_ISO_STATUS_SUCCESS 0x90, 0x00
#define TYPE_4_TAG_ISO_RW_CHUNK_LEN (255)
#define TYPE_4_TAG_ISO_APP_NAME_LEN (7)
#define TYPE_4_TAG_ISO_RW_CHUNK_LEN (255U)
#define TYPE_4_TAG_ISO_APP_NAME_LEN (7U)
#define TYPE_4_TAG_ISO_APP_NAME 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01
#define TYPE_4_TAG_T4T_CC_FILE_ID_LEN (2)
#define TYPE_4_TAG_T4T_CC_FILE_ID_LEN (2U)
#define TYPE_4_TAG_T4T_CC_FILE_ID 0xE1, 0x03
#define TYPE_4_TAG_T4T_CC_VNO (0x20)
#define TYPE_4_TAG_T4T_CC_VNO 0x20
// Capability Container parsing structures
typedef enum FURI_PACKED {
Type4TagCcTlvTypeNdefFileCtrl = 0x04,
@@ -52,3 +56,11 @@ typedef struct FURI_PACKED {
uint16_t mlc;
Type4TagCcTlv tlv[];
} Type4TagCc;
// Load internal Type4Tag structures
bool type_4_tag_ndef_data_load(Type4TagData* data, FlipperFormat* ff);
// Save internal Type4Tag structures
bool type_4_tag_ndef_data_save(const Type4TagData* data, FlipperFormat* ff);

View File

@@ -137,6 +137,7 @@ Type4TagError type_4_tag_poller_read_cc(Type4TagPoller* instance) {
break;
}
instance->data->is_tag_specific = true;
instance->data->t4t_version.value = cc->t4t_vno;
instance->data->chunk_max_read = bit_lib_bytes_to_num_be((void*)&cc->mle, sizeof(cc->mle));
instance->data->chunk_max_write =