Fix MiFare DESFire GetKeySettings response parsing (#1267)

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 <git+flipperzero@kevin.wallace.seattle.wa.us>
Co-authored-by: gornekich <n.gorbadey@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Kevin Wallace 2022-05-24 07:05:46 -07:00 committed by GitHub
parent d31578508a
commit 4b45746b8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 16 additions and 1 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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;