From 4b45746b8e10420887f40caf0faae41632a8a70e Mon Sep 17 00:00:00 2001 From: Kevin Wallace <184975+kevinwallace@users.noreply.github.com> Date: Tue, 24 May 2022 07:05:46 -0700 Subject: [PATCH] Fix MiFare DESFire GetKeySettings response parsing (#1267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the bottom nybble of buf[1] is the key ID; the top nybble contains flags. Notably, the top bit is set for AES mode on EV1+ cards, and ORCA cards in the Seattle area were just upgraded to include an app that uses AES. Prior to this, cards with flags set could be read and saved just fine, but loading them would fail due to missing keys. After this, tags saved with the old version will load fine, and when re-saved will have the flags separated out into a new field. Co-authored-by: Kevin Wallace Co-authored-by: gornekich Co-authored-by: あく --- applications/nfc/nfc_device.c | 10 ++++++++++ lib/nfc_protocols/mifare_desfire.c | 6 +++++- lib/nfc_protocols/mifare_desfire.h | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index 0771a1ef..63f0c3cc 100644 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -195,6 +195,10 @@ static bool nfc_device_save_mifare_df_key_settings( string_printf(key, "%s Key Changeable", prefix); if(!flipper_format_write_bool(file, string_get_cstr(key), &ks->master_key_changeable, 1)) break; + if(ks->flags) { + string_printf(key, "%s Flags", prefix); + if(!flipper_format_write_hex(file, string_get_cstr(key), &ks->flags, 1)) break; + } string_printf(key, "%s Max Keys", prefix); if(!flipper_format_write_hex(file, string_get_cstr(key), &ks->max_keys, 1)) break; for(MifareDesfireKeyVersion* kv = ks->key_version_head; kv; kv = kv->next) { @@ -230,8 +234,14 @@ bool nfc_device_load_mifare_df_key_settings( string_printf(key, "%s Key Changeable", prefix); if(!flipper_format_read_bool(file, string_get_cstr(key), &ks->master_key_changeable, 1)) break; + string_printf(key, "%s Flags", prefix); + if(flipper_format_key_exist(file, string_get_cstr(key))) { + if(!flipper_format_read_hex(file, string_get_cstr(key), &ks->flags, 1)) break; + } string_printf(key, "%s Max Keys", prefix); if(!flipper_format_read_hex(file, string_get_cstr(key), &ks->max_keys, 1)) break; + ks->flags |= ks->max_keys >> 4; + ks->max_keys &= 0xF; MifareDesfireKeyVersion** kv_head = &ks->key_version_head; for(int key_id = 0; key_id < ks->max_keys; key_id++) { string_printf(key, "%s Key %d Version", prefix, key_id); diff --git a/lib/nfc_protocols/mifare_desfire.c b/lib/nfc_protocols/mifare_desfire.c index 4f02e839..6f28dc5d 100644 --- a/lib/nfc_protocols/mifare_desfire.c +++ b/lib/nfc_protocols/mifare_desfire.c @@ -115,6 +115,9 @@ void mf_df_cat_key_settings(MifareDesfireKeySettings* ks, string_t out) { string_cat_printf(out, "freeCreateDelete %d\n", ks->free_create_delete); string_cat_printf(out, "freeDirectoryList %d\n", ks->free_directory_list); string_cat_printf(out, "masterChangeable %d\n", ks->master_key_changeable); + if(ks->flags) { + string_cat_printf(out, "flags %d\n", ks->flags); + } string_cat_printf(out, "maxKeys %d\n", ks->max_keys); for(MifareDesfireKeyVersion* kv = ks->key_version_head; kv; kv = kv->next) { string_cat_printf(out, "key %d version %d\n", kv->id, kv->version); @@ -274,7 +277,8 @@ bool mf_df_parse_get_key_settings_response( out->free_create_delete = (buf[0] & 0x4) != 0; out->free_directory_list = (buf[0] & 0x2) != 0; out->master_key_changeable = (buf[0] & 0x1) != 0; - out->max_keys = buf[1]; + out->flags = buf[1] >> 4; + out->max_keys = buf[1] & 0xF; return true; } diff --git a/lib/nfc_protocols/mifare_desfire.h b/lib/nfc_protocols/mifare_desfire.h index 809f1782..dbe0802e 100644 --- a/lib/nfc_protocols/mifare_desfire.h +++ b/lib/nfc_protocols/mifare_desfire.h @@ -56,6 +56,7 @@ typedef struct { bool free_create_delete; bool free_directory_list; bool master_key_changeable; + uint8_t flags; uint8_t max_keys; MifareDesfireKeyVersion* key_version_head; } MifareDesfireKeySettings;