diff --git a/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag_render.c b/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag_render.c index 8fdeecb14..ac1f5bdbc 100644 --- a/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag_render.c +++ b/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag_render.c @@ -2,8 +2,6 @@ #include "../iso14443_4a/iso14443_4a_render.h" -#define TYPE_4_TAG_RENDER_MAX_RECORD_SIZE (256U) - void nfc_render_type_4_tag_info( const Type4TagData* data, NfcProtocolFormatType format_type, @@ -11,26 +9,27 @@ void nfc_render_type_4_tag_info( nfc_render_iso14443_4a_brief(type_4_tag_get_base_data(data), str); furi_string_cat(str, "\n:::::::::::::::[Stored NDEF]:::::::::::::::\n"); - furi_string_cat_printf( - str, "Current NDEF Size: %lu\n", simple_array_get_count(data->ndef_data)); + furi_string_cat_printf(str, "Current NDEF Size: %lu", simple_array_get_count(data->ndef_data)); - furi_string_cat(str, "::::::::::::::::::[Tag Specs]::::::::::::::::::\n"); - furi_string_cat_printf( - str, "T4T Mapping Version: %u.%u\n", data->t4t_version.major, data->t4t_version.minor); - furi_string_cat_printf(str, "NDEF File ID: 0x%04X\n", data->ndef_file_id); - furi_string_cat_printf(str, "Max NDEF Size: %u\n", data->ndef_max_len); - furi_string_cat_printf( - str, "APDU Sizes: R:%u W:%u\n", data->chunk_max_read, data->chunk_max_write); - furi_string_cat_printf( - str, - "Read Lock: 0x%02X%s\n", - data->ndef_read_lock, - data->ndef_read_lock == 0 ? " (unlocked)" : ""); - furi_string_cat_printf( - str, - "Write Lock: 0x%02X%s", - data->ndef_write_lock, - data->ndef_write_lock == 0 ? " (unlocked)" : ""); + if(data->is_tag_specific) { + furi_string_cat(str, "\n::::::::::::::::::[Tag Specs]::::::::::::::::::\n"); + furi_string_cat_printf( + str, "T4T Mapping Version: %u.%u\n", data->t4t_version.major, data->t4t_version.minor); + furi_string_cat_printf(str, "NDEF File ID: 0x%04X\n", data->ndef_file_id); + furi_string_cat_printf(str, "Max NDEF Size: %u\n", data->ndef_max_len); + furi_string_cat_printf( + str, "APDU Sizes: R:%u W:%u\n", data->chunk_max_read, data->chunk_max_write); + furi_string_cat_printf( + str, + "Read Lock: 0x%02X%s\n", + data->ndef_read_lock, + data->ndef_read_lock == 0 ? " (unlocked)" : ""); + furi_string_cat_printf( + str, + "Write Lock: 0x%02X%s", + data->ndef_write_lock, + data->ndef_write_lock == 0 ? " (unlocked)" : ""); + } if(format_type != NfcProtocolFormatTypeFull) return; diff --git a/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag_render.h b/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag_render.h index 91eaeb735..abb45317c 100644 --- a/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag_render.h +++ b/applications/main/nfc/helpers/protocol_support/type_4_tag/type_4_tag_render.h @@ -4,7 +4,7 @@ #include "../nfc_protocol_support_render_common.h" -#define TYPE_4_TAG_RENDER_BYTES_PER_LINE (4) +#define TYPE_4_TAG_RENDER_BYTES_PER_LINE (4U) void nfc_render_type_4_tag_info( const Type4TagData* data, diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag.c b/lib/nfc/protocols/type_4_tag/type_4_tag.c index ec268b618..47e8e7352 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag.c +++ b/lib/nfc/protocols/type_4_tag/type_4_tag.c @@ -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 && diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag.h b/lib/nfc/protocols/type_4_tag/type_4_tag.h index 99f58b7cc..ec7013c48 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag.h +++ b/lib/nfc/protocols/type_4_tag/type_4_tag.h @@ -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; diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag_i.c b/lib/nfc/protocols/type_4_tag/type_4_tag_i.c index c2cbfd1af..ef252f9a0 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag_i.c +++ b/lib/nfc/protocols/type_4_tag/type_4_tag_i.c @@ -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; +} diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag_i.h b/lib/nfc/protocols/type_4_tag/type_4_tag_i.h index 0dcece22b..2fdd478ac 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag_i.h +++ b/lib/nfc/protocols/type_4_tag/type_4_tag_i.h @@ -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); diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.c b/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.c index ab2f28285..496277bc9 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.c +++ b/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.c @@ -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 =