mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
NFC: Support DESFire Transaction MAC file type [ci skip]
by Willy-JL in OFW PR 4159
This commit is contained in:
@@ -180,6 +180,9 @@ void nfc_render_mf_desfire_file_settings_data(
|
|||||||
case MfDesfireFileTypeCyclicRecord:
|
case MfDesfireFileTypeCyclicRecord:
|
||||||
type = "cyclic";
|
type = "cyclic";
|
||||||
break;
|
break;
|
||||||
|
case MfDesfireFileTypeTransactionMac:
|
||||||
|
type = "txn-mac";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
type = "unknown";
|
type = "unknown";
|
||||||
}
|
}
|
||||||
@@ -237,6 +240,15 @@ void nfc_render_mf_desfire_file_settings_data(
|
|||||||
furi_string_cat_printf(str, "size %lu\n", record_size);
|
furi_string_cat_printf(str, "size %lu\n", record_size);
|
||||||
furi_string_cat_printf(str, "num %lu max %lu\n", record_count, settings->record.max);
|
furi_string_cat_printf(str, "num %lu max %lu\n", record_count, settings->record.max);
|
||||||
break;
|
break;
|
||||||
|
case MfDesfireFileTypeTransactionMac:
|
||||||
|
record_count = 0;
|
||||||
|
furi_string_cat_printf(
|
||||||
|
str,
|
||||||
|
"key opt %02X ver %02X\n",
|
||||||
|
settings->transaction_mac.key_option,
|
||||||
|
settings->transaction_mac.key_version);
|
||||||
|
furi_string_cat_printf(str, "cnt limit %lu\n", settings->transaction_mac.counter_limit);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_auth_required = true;
|
bool is_auth_required = true;
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ typedef enum {
|
|||||||
MfDesfireFileTypeValue = 2,
|
MfDesfireFileTypeValue = 2,
|
||||||
MfDesfireFileTypeLinearRecord = 3,
|
MfDesfireFileTypeLinearRecord = 3,
|
||||||
MfDesfireFileTypeCyclicRecord = 4,
|
MfDesfireFileTypeCyclicRecord = 4,
|
||||||
|
MfDesfireFileTypeTransactionMac = 5,
|
||||||
} MfDesfireFileType;
|
} MfDesfireFileType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -128,6 +129,11 @@ typedef struct {
|
|||||||
uint32_t max;
|
uint32_t max;
|
||||||
uint32_t cur;
|
uint32_t cur;
|
||||||
} record;
|
} record;
|
||||||
|
struct {
|
||||||
|
uint8_t key_option;
|
||||||
|
uint8_t key_version;
|
||||||
|
uint32_t counter_limit;
|
||||||
|
} transaction_mac;
|
||||||
};
|
};
|
||||||
} MfDesfireFileSettings;
|
} MfDesfireFileSettings;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "mf_desfire_i.h"
|
#include "mf_desfire_i.h"
|
||||||
|
|
||||||
|
#include <bit_lib/bit_lib.h>
|
||||||
|
|
||||||
#define TAG "MfDesfire"
|
#define TAG "MfDesfire"
|
||||||
|
|
||||||
#define BITS_IN_BYTE (8U)
|
#define BITS_IN_BYTE (8U)
|
||||||
@@ -47,6 +49,10 @@
|
|||||||
#define MF_DESFIRE_FFF_FILE_MAX_KEY "Max"
|
#define MF_DESFIRE_FFF_FILE_MAX_KEY "Max"
|
||||||
#define MF_DESFIRE_FFF_FILE_CUR_KEY "Cur"
|
#define MF_DESFIRE_FFF_FILE_CUR_KEY "Cur"
|
||||||
|
|
||||||
|
#define MF_DESFIRE_FFF_FILE_KEY_OPTION_KEY "Key Option"
|
||||||
|
#define MF_DESFIRE_FFF_FILE_KEY_VERSION_KEY "Key Version"
|
||||||
|
#define MF_DESFIRE_FFF_FILE_COUNTER_LIMIT_KEY "Counter Limit"
|
||||||
|
|
||||||
bool mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf) {
|
bool mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf) {
|
||||||
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfDesfireVersion);
|
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfDesfireVersion);
|
||||||
|
|
||||||
@@ -168,12 +174,19 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer
|
|||||||
uint32_t cur : 3 * BITS_IN_BYTE;
|
uint32_t cur : 3 * BITS_IN_BYTE;
|
||||||
} MfDesfireFileSettingsRecord;
|
} MfDesfireFileSettingsRecord;
|
||||||
|
|
||||||
|
typedef struct FURI_PACKED {
|
||||||
|
uint8_t key_option;
|
||||||
|
uint8_t key_version;
|
||||||
|
uint8_t counter_limit[];
|
||||||
|
} MfDesfireFileSettingsTransactionMac;
|
||||||
|
|
||||||
typedef struct FURI_PACKED {
|
typedef struct FURI_PACKED {
|
||||||
MfDesfireFileSettingsHeader header;
|
MfDesfireFileSettingsHeader header;
|
||||||
union {
|
union {
|
||||||
MfDesfireFileSettingsData data;
|
MfDesfireFileSettingsData data;
|
||||||
MfDesfireFileSettingsValue value;
|
MfDesfireFileSettingsValue value;
|
||||||
MfDesfireFileSettingsRecord record;
|
MfDesfireFileSettingsRecord record;
|
||||||
|
MfDesfireFileSettingsTransactionMac transaction_mac;
|
||||||
};
|
};
|
||||||
} MfDesfireFileSettingsLayout;
|
} MfDesfireFileSettingsLayout;
|
||||||
|
|
||||||
@@ -182,7 +195,7 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer
|
|||||||
const size_t data_size = bit_buffer_get_size_bytes(buf);
|
const size_t data_size = bit_buffer_get_size_bytes(buf);
|
||||||
const uint8_t* data_ptr = bit_buffer_get_data(buf);
|
const uint8_t* data_ptr = bit_buffer_get_data(buf);
|
||||||
const size_t min_data_size =
|
const size_t min_data_size =
|
||||||
sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsData);
|
sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsTransactionMac);
|
||||||
|
|
||||||
if(data_size < min_data_size) {
|
if(data_size < min_data_size) {
|
||||||
FURI_LOG_E(
|
FURI_LOG_E(
|
||||||
@@ -202,17 +215,11 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer
|
|||||||
|
|
||||||
if(file_settings_temp.type == MfDesfireFileTypeStandard ||
|
if(file_settings_temp.type == MfDesfireFileTypeStandard ||
|
||||||
file_settings_temp.type == MfDesfireFileTypeBackup) {
|
file_settings_temp.type == MfDesfireFileTypeBackup) {
|
||||||
memcpy(
|
memcpy(&layout.data, &data_ptr[bytes_processed], sizeof(MfDesfireFileSettingsData));
|
||||||
&layout.data,
|
|
||||||
&data_ptr[sizeof(MfDesfireFileSettingsHeader)],
|
|
||||||
sizeof(MfDesfireFileSettingsData));
|
|
||||||
file_settings_temp.data.size = layout.data.size;
|
file_settings_temp.data.size = layout.data.size;
|
||||||
bytes_processed += sizeof(MfDesfireFileSettingsData);
|
bytes_processed += sizeof(MfDesfireFileSettingsData);
|
||||||
} else if(file_settings_temp.type == MfDesfireFileTypeValue) {
|
} else if(file_settings_temp.type == MfDesfireFileTypeValue) {
|
||||||
memcpy(
|
memcpy(&layout.value, &data_ptr[bytes_processed], sizeof(MfDesfireFileSettingsValue));
|
||||||
&layout.value,
|
|
||||||
&data_ptr[sizeof(MfDesfireFileSettingsHeader)],
|
|
||||||
sizeof(MfDesfireFileSettingsValue));
|
|
||||||
file_settings_temp.value.lo_limit = layout.value.lo_limit;
|
file_settings_temp.value.lo_limit = layout.value.lo_limit;
|
||||||
file_settings_temp.value.hi_limit = layout.value.hi_limit;
|
file_settings_temp.value.hi_limit = layout.value.hi_limit;
|
||||||
file_settings_temp.value.limited_credit_value = layout.value.limited_credit_value;
|
file_settings_temp.value.limited_credit_value = layout.value.limited_credit_value;
|
||||||
@@ -222,13 +229,34 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer
|
|||||||
file_settings_temp.type == MfDesfireFileTypeLinearRecord ||
|
file_settings_temp.type == MfDesfireFileTypeLinearRecord ||
|
||||||
file_settings_temp.type == MfDesfireFileTypeCyclicRecord) {
|
file_settings_temp.type == MfDesfireFileTypeCyclicRecord) {
|
||||||
memcpy(
|
memcpy(
|
||||||
&layout.record,
|
&layout.record, &data_ptr[bytes_processed], sizeof(MfDesfireFileSettingsRecord));
|
||||||
&data_ptr[sizeof(MfDesfireFileSettingsHeader)],
|
|
||||||
sizeof(MfDesfireFileSettingsRecord));
|
|
||||||
file_settings_temp.record.size = layout.record.size;
|
file_settings_temp.record.size = layout.record.size;
|
||||||
file_settings_temp.record.max = layout.record.max;
|
file_settings_temp.record.max = layout.record.max;
|
||||||
file_settings_temp.record.cur = layout.record.cur;
|
file_settings_temp.record.cur = layout.record.cur;
|
||||||
bytes_processed += sizeof(MfDesfireFileSettingsRecord);
|
bytes_processed += sizeof(MfDesfireFileSettingsRecord);
|
||||||
|
} else if(file_settings_temp.type == MfDesfireFileTypeTransactionMac) {
|
||||||
|
const bool has_counter_limit = (layout.header.comm & 0x20) != 0;
|
||||||
|
memcpy(
|
||||||
|
&layout.transaction_mac,
|
||||||
|
&data_ptr[bytes_processed],
|
||||||
|
sizeof(MfDesfireFileSettingsTransactionMac));
|
||||||
|
file_settings_temp.transaction_mac.key_option = layout.transaction_mac.key_option;
|
||||||
|
file_settings_temp.transaction_mac.key_version = layout.transaction_mac.key_version;
|
||||||
|
if(!has_counter_limit) {
|
||||||
|
file_settings_temp.transaction_mac.counter_limit = 0;
|
||||||
|
} else {
|
||||||
|
// AES (4b) or LRP (2b)
|
||||||
|
const size_t counter_limit_size = (layout.transaction_mac.key_option & 0x02) ? 4 :
|
||||||
|
2;
|
||||||
|
memcpy(
|
||||||
|
&layout.transaction_mac,
|
||||||
|
&data_ptr[bytes_processed],
|
||||||
|
sizeof(MfDesfireFileSettingsTransactionMac) + counter_limit_size);
|
||||||
|
file_settings_temp.transaction_mac.counter_limit = bit_lib_bytes_to_num_be(
|
||||||
|
layout.transaction_mac.counter_limit, counter_limit_size);
|
||||||
|
bytes_processed += counter_limit_size;
|
||||||
|
}
|
||||||
|
bytes_processed += sizeof(MfDesfireFileSettingsTransactionMac);
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_W(TAG, "Unknown file type: %02x", file_settings_temp.type);
|
FURI_LOG_W(TAG, "Unknown file type: %02x", file_settings_temp.type);
|
||||||
break;
|
break;
|
||||||
@@ -468,6 +496,21 @@ bool mf_desfire_file_settings_load(
|
|||||||
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_CUR_KEY);
|
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_CUR_KEY);
|
||||||
if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->record.cur, 1))
|
if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->record.cur, 1))
|
||||||
break;
|
break;
|
||||||
|
} else if(data->type == MfDesfireFileTypeTransactionMac) {
|
||||||
|
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_KEY_OPTION_KEY);
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
ff, furi_string_get_cstr(key), &data->transaction_mac.key_option, 1))
|
||||||
|
break;
|
||||||
|
|
||||||
|
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_KEY_VERSION_KEY);
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
ff, furi_string_get_cstr(key), &data->transaction_mac.key_version, 1))
|
||||||
|
break;
|
||||||
|
|
||||||
|
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_COUNTER_LIMIT_KEY);
|
||||||
|
if(!flipper_format_read_uint32(
|
||||||
|
ff, furi_string_get_cstr(key), &data->transaction_mac.counter_limit, 1))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
@@ -716,6 +759,21 @@ bool mf_desfire_file_settings_save(
|
|||||||
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_CUR_KEY);
|
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_CUR_KEY);
|
||||||
if(!flipper_format_write_uint32(ff, furi_string_get_cstr(key), &data->record.cur, 1))
|
if(!flipper_format_write_uint32(ff, furi_string_get_cstr(key), &data->record.cur, 1))
|
||||||
break;
|
break;
|
||||||
|
} else if(data->type == MfDesfireFileTypeTransactionMac) {
|
||||||
|
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_KEY_OPTION_KEY);
|
||||||
|
if(!flipper_format_write_hex(
|
||||||
|
ff, furi_string_get_cstr(key), &data->transaction_mac.key_option, 1))
|
||||||
|
break;
|
||||||
|
|
||||||
|
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_KEY_VERSION_KEY);
|
||||||
|
if(!flipper_format_write_hex(
|
||||||
|
ff, furi_string_get_cstr(key), &data->transaction_mac.key_version, 1))
|
||||||
|
break;
|
||||||
|
|
||||||
|
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_COUNTER_LIMIT_KEY);
|
||||||
|
if(!flipper_format_write_uint32(
|
||||||
|
ff, furi_string_get_cstr(key), &data->transaction_mac.counter_limit, 1))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
|
|||||||
@@ -468,7 +468,7 @@ MfDesfireError mf_desfire_poller_read_file_data_multi(
|
|||||||
file_type == MfDesfireFileTypeLinearRecord ||
|
file_type == MfDesfireFileTypeLinearRecord ||
|
||||||
file_type == MfDesfireFileTypeCyclicRecord) {
|
file_type == MfDesfireFileTypeCyclicRecord) {
|
||||||
error = mf_desfire_poller_read_file_records(
|
error = mf_desfire_poller_read_file_records(
|
||||||
instance, file_id, 0, file_settings_cur->data.size, file_data);
|
instance, file_id, 0, file_settings_cur->record.size, file_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user