NFC: Mf Desfire fix reading big files (#3616)

* mf desfire: fix incorrect long files reading
* nfc app: trim record size for mf desfire render
* mf desfire: rework reading long record files
* mf desfire: more robust size check

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
gornekich 2024-05-14 13:34:27 +01:00 committed by GitHub
parent a7715704f8
commit 5f9b300ab2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 47 deletions

View file

@ -2,6 +2,8 @@
#include "../iso14443_4a/iso14443_4a_render.h"
#define MF_DESFIRE_RENDER_MAX_RECORD_SIZE (256U)
void nfc_render_mf_desfire_info(
const MfDesfireData* data,
NfcProtocolFormatType format_type,
@ -212,8 +214,6 @@ void nfc_render_mf_desfire_file_settings_data(
uint32_t record_count = 1;
uint32_t record_size = 0;
const uint32_t total_size = simple_array_get_count(data->data);
switch(settings->type) {
case MfDesfireFileTypeStandard:
case MfDesfireFileTypeBackup:
@ -257,17 +257,14 @@ void nfc_render_mf_desfire_file_settings_data(
return;
}
for(uint32_t rec = 0; rec < record_count; rec++) {
const uint32_t size_offset = rec * record_size;
const uint32_t size_remaining = total_size > size_offset ? total_size - size_offset : 0;
// Limit record size
bool trim_data = record_size > MF_DESFIRE_RENDER_MAX_RECORD_SIZE;
if(trim_data) {
record_size = MF_DESFIRE_RENDER_MAX_RECORD_SIZE;
}
if(size_remaining < record_size) {
furi_string_cat_printf(
str, "record %lu (partial %lu of %lu)\n", rec, size_remaining, record_size);
record_size = size_remaining;
} else {
furi_string_cat_printf(str, "record %lu\n", rec);
}
for(uint32_t rec = 0; rec < record_count; rec++) {
furi_string_cat_printf(str, "record %lu\n", rec);
for(uint32_t ch = 0; ch < record_size; ch += 4) {
furi_string_cat_printf(str, "%03lx|", ch);
@ -296,6 +293,9 @@ void nfc_render_mf_desfire_file_settings_data(
furi_string_push_back(str, '\n');
}
if(trim_data) {
furi_string_cat_str(str, "...");
}
furi_string_push_back(str, '\n');
}

View file

@ -75,10 +75,10 @@ MfDesfireError mf_desfire_send_chunks(
const size_t rx_capacity_remaining =
bit_buffer_get_capacity_bytes(rx_buffer) - bit_buffer_get_size_bytes(rx_buffer);
if(rx_size <= rx_capacity_remaining) {
if(rx_size <= rx_capacity_remaining + 1) {
bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
} else {
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size);
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 1);
}
}
} while(false);
@ -327,36 +327,63 @@ MfDesfireError mf_desfire_poller_read_file_settings_multi(
return error;
}
MfDesfireError mf_desfire_poller_read_file_data(
static MfDesfireError mf_desfire_poller_read_file(
MfDesfirePoller* instance,
MfDesfireFileId id,
uint8_t read_cmd,
uint32_t offset,
size_t size,
MfDesfireFileData* data) {
furi_check(instance);
furi_check(data);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_READ_DATA);
bit_buffer_append_byte(instance->input_buffer, id);
bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&offset, 3);
bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&size, 3);
MfDesfireError error = MfDesfireErrorNone;
simple_array_init(data->data, size);
MfDesfireError error;
size_t buffer_capacity = bit_buffer_get_capacity_bytes(instance->result_buffer);
uint32_t current_offset = offset;
uint32_t bytes_read = 0;
while(bytes_read < size) {
size_t bytes_to_read = MIN(buffer_capacity, size - bytes_read);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, read_cmd);
bit_buffer_append_byte(instance->input_buffer, id);
bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&current_offset, 3);
bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&bytes_to_read, 3);
do {
error = mf_desfire_send_chunks(instance, instance->input_buffer, instance->result_buffer);
if(error != MfDesfireErrorNone) break;
if(!mf_desfire_file_data_parse(data, instance->result_buffer)) {
size_t bytes_received = bit_buffer_get_size_bytes(instance->result_buffer);
if(bytes_received != bytes_to_read) {
FURI_LOG_W(TAG, "Read %zu out of %zu bytes", bytes_received, bytes_to_read);
error = MfDesfireErrorProtocol;
break;
}
} while(false);
uint8_t* file_data = simple_array_get_data(data->data);
bit_buffer_write_bytes(instance->result_buffer, &file_data[current_offset], bytes_to_read);
bytes_read += bytes_to_read;
current_offset += bytes_to_read;
}
if(error != MfDesfireErrorNone) {
simple_array_reset(data->data);
}
return error;
}
MfDesfireError mf_desfire_poller_read_file_data(
MfDesfirePoller* instance,
MfDesfireFileId id,
uint32_t offset,
size_t size,
MfDesfireFileData* data) {
return mf_desfire_poller_read_file(instance, id, MF_DESFIRE_CMD_READ_DATA, offset, size, data);
}
MfDesfireError mf_desfire_poller_read_file_value(
MfDesfirePoller* instance,
MfDesfireFileId id,
@ -389,28 +416,8 @@ MfDesfireError mf_desfire_poller_read_file_records(
uint32_t offset,
size_t size,
MfDesfireFileData* data) {
furi_check(instance);
furi_check(data);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_READ_RECORDS);
bit_buffer_append_byte(instance->input_buffer, id);
bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&offset, 3);
bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&size, 3);
MfDesfireError error;
do {
error = mf_desfire_send_chunks(instance, instance->input_buffer, instance->result_buffer);
if(error != MfDesfireErrorNone) break;
if(!mf_desfire_file_data_parse(data, instance->result_buffer)) {
error = MfDesfireErrorProtocol;
}
} while(false);
return error;
return mf_desfire_poller_read_file(
instance, id, MF_DESFIRE_CMD_READ_RECORDS, offset, size, data);
}
MfDesfireError mf_desfire_poller_read_file_data_multi(