diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c index 783cbb871c..96e4a30f9e 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c @@ -180,6 +180,9 @@ void nfc_render_mf_desfire_file_settings_data( case MfDesfireFileTypeCyclicRecord: type = "cyclic"; break; + case MfDesfireFileTypeTransactionMac: + type = "txn-mac"; + break; default: 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, "num %lu max %lu\n", record_count, settings->record.max); 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; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index fb50008dbd..ec60b336b3 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -97,6 +97,7 @@ typedef enum { MfDesfireFileTypeValue = 2, MfDesfireFileTypeLinearRecord = 3, MfDesfireFileTypeCyclicRecord = 4, + MfDesfireFileTypeTransactionMac = 5, } MfDesfireFileType; typedef enum { @@ -128,6 +129,11 @@ typedef struct { uint32_t max; uint32_t cur; } record; + struct { + uint8_t key_option; + uint8_t key_version; + uint32_t counter_limit; + } transaction_mac; }; } MfDesfireFileSettings; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c index d83a91ad1a..eba9c43124 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -1,5 +1,7 @@ #include "mf_desfire_i.h" +#include + #define TAG "MfDesfire" #define BITS_IN_BYTE (8U) @@ -47,6 +49,10 @@ #define MF_DESFIRE_FFF_FILE_MAX_KEY "Max" #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) { 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; } MfDesfireFileSettingsRecord; + typedef struct FURI_PACKED { + uint8_t key_option; + uint8_t key_version; + uint8_t counter_limit[]; + } MfDesfireFileSettingsTransactionMac; + typedef struct FURI_PACKED { MfDesfireFileSettingsHeader header; union { MfDesfireFileSettingsData data; MfDesfireFileSettingsValue value; MfDesfireFileSettingsRecord record; + MfDesfireFileSettingsTransactionMac transaction_mac; }; } 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 uint8_t* data_ptr = bit_buffer_get_data(buf); const size_t min_data_size = - sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsData); + sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsTransactionMac); if(data_size < min_data_size) { FURI_LOG_E( @@ -202,17 +215,11 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer if(file_settings_temp.type == MfDesfireFileTypeStandard || file_settings_temp.type == MfDesfireFileTypeBackup) { - memcpy( - &layout.data, - &data_ptr[sizeof(MfDesfireFileSettingsHeader)], - sizeof(MfDesfireFileSettingsData)); + memcpy(&layout.data, &data_ptr[bytes_processed], sizeof(MfDesfireFileSettingsData)); file_settings_temp.data.size = layout.data.size; bytes_processed += sizeof(MfDesfireFileSettingsData); } else if(file_settings_temp.type == MfDesfireFileTypeValue) { - memcpy( - &layout.value, - &data_ptr[sizeof(MfDesfireFileSettingsHeader)], - sizeof(MfDesfireFileSettingsValue)); + memcpy(&layout.value, &data_ptr[bytes_processed], sizeof(MfDesfireFileSettingsValue)); file_settings_temp.value.lo_limit = layout.value.lo_limit; file_settings_temp.value.hi_limit = layout.value.hi_limit; 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 == MfDesfireFileTypeCyclicRecord) { memcpy( - &layout.record, - &data_ptr[sizeof(MfDesfireFileSettingsHeader)], - sizeof(MfDesfireFileSettingsRecord)); + &layout.record, &data_ptr[bytes_processed], sizeof(MfDesfireFileSettingsRecord)); file_settings_temp.record.size = layout.record.size; file_settings_temp.record.max = layout.record.max; file_settings_temp.record.cur = layout.record.cur; 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 { FURI_LOG_W(TAG, "Unknown file type: %02x", file_settings_temp.type); break; @@ -468,6 +496,21 @@ bool mf_desfire_file_settings_load( 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)) 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; @@ -716,6 +759,21 @@ bool mf_desfire_file_settings_save( 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)) 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; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 6d8dfda160..8b57fcc4c0 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -468,7 +468,7 @@ MfDesfireError mf_desfire_poller_read_file_data_multi( file_type == MfDesfireFileTypeLinearRecord || file_type == MfDesfireFileTypeCyclicRecord) { 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); } }