[FL-3008], [FL-2734], [FL-2766], [FL-2898] NFC bug fixes (#2098)

* nfc: rework mf classic update
* nfc: rename cache folder to .cache
* nfc: fix ATQA order bytes in nfc files
* file browser: add hide dot files option
* nfc: fix iso-14443-4 uid cards emulation
* nfc: fix unit tests

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
gornekich
2022-12-07 14:52:44 +04:00
committed by GitHub
parent c43ec414bb
commit 9a21dae29c
14 changed files with 88 additions and 60 deletions

View File

@@ -8,11 +8,11 @@
#include <flipper_format/flipper_format.h>
#define TAG "NfcDevice"
#define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/cache")
#define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/.cache")
#define NFC_DEVICE_KEYS_EXTENSION ".keys"
static const char* nfc_file_header = "Flipper NFC device";
static const uint32_t nfc_file_version = 2;
static const uint32_t nfc_file_version = 3;
static const char* nfc_keys_file_header = "Flipper NFC keys";
static const uint32_t nfc_keys_file_version = 1;
@@ -27,6 +27,11 @@ NfcDevice* nfc_device_alloc() {
nfc_dev->dialogs = furi_record_open(RECORD_DIALOGS);
nfc_dev->load_path = furi_string_alloc();
nfc_dev->dev_data.parsed_data = furi_string_alloc();
// Rename cache folder name for backward compatibility
if(storage_common_stat(nfc_dev->storage, "/ext/nfc/cache", NULL) == FSE_OK) {
storage_common_rename(nfc_dev->storage, "/ext/nfc/cache", NFC_DEVICE_KEYS_FOLDER);
}
return nfc_dev;
}
@@ -1041,7 +1046,9 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
break;
if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
if(!flipper_format_write_hex(file, "ATQA", data->atqa, 2)) break;
// Save ATQA in MSB order for correct companion apps display
uint8_t atqa[2] = {data->atqa[1], data->atqa[0]};
if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break;
if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break;
// Save more data if necessary
if(dev->format == NfcDeviceSaveFormatMifareUl) {
@@ -1089,6 +1096,9 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
temp_str = furi_string_alloc();
bool deprecated_version = false;
// Version 2 of file format had ATQA bytes swapped
uint32_t version_with_lsb_atqa = 2;
if(dev->loading_cb) {
dev->loading_cb(dev->loading_cb_ctx, true);
}
@@ -1107,9 +1117,12 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
// Read and verify file header
uint32_t version = 0;
if(!flipper_format_read_header(file, temp_str, &version)) break;
if(furi_string_cmp_str(temp_str, nfc_file_header) || (version != nfc_file_version)) {
deprecated_version = true;
break;
if(furi_string_cmp_str(temp_str, nfc_file_header)) break;
if(version != nfc_file_version) {
if(version < version_with_lsb_atqa) {
deprecated_version = true;
break;
}
}
// Read Nfc device type
if(!flipper_format_read_string(file, "Device type", temp_str)) break;
@@ -1119,7 +1132,14 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
if(!(data_cnt == 4 || data_cnt == 7)) break;
data->uid_len = data_cnt;
if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
if(version == version_with_lsb_atqa) {
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
} else {
uint8_t atqa[2] = {};
if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break;
data->atqa[0] = atqa[1];
data->atqa[1] = atqa[0];
}
if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break;
// Load CUID
uint8_t* cuid_start = data->uid;
@@ -1187,6 +1207,7 @@ bool nfc_file_select(NfcDevice* dev) {
const DialogsFileBrowserOptions browser_options = {
.extension = NFC_APP_EXTENSION,
.skip_assets = true,
.hide_dot_files = true,
.icon = &I_Nfc_10px,
.hide_ext = true,
.item_loader_callback = NULL,

View File

@@ -712,46 +712,16 @@ uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data
furi_assert(tx_rx);
furi_assert(data);
uint8_t sectors_read = 0;
Crypto1 crypto = {};
uint8_t total_sectors = mf_classic_get_total_sectors_num(data->type);
uint64_t key_a = 0;
uint64_t key_b = 0;
MfClassicSectorReader sec_reader = {};
MfClassicSector temp_sector = {};
for(size_t i = 0; i < total_sectors; i++) {
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i);
// Load key A
if(mf_classic_is_key_found(data, i, MfClassicKeyA)) {
sec_reader.key_a = nfc_util_bytes2num(sec_tr->key_a, 6);
} else {
sec_reader.key_a = MF_CLASSIC_NO_KEY;
}
// Load key B
if(mf_classic_is_key_found(data, i, MfClassicKeyB)) {
sec_reader.key_b = nfc_util_bytes2num(sec_tr->key_b, 6);
} else {
sec_reader.key_b = MF_CLASSIC_NO_KEY;
}
if((key_a != MF_CLASSIC_NO_KEY) || (key_b != MF_CLASSIC_NO_KEY)) {
sec_reader.sector_num = i;
if(mf_classic_read_sector_with_reader(tx_rx, &crypto, &sec_reader, &temp_sector)) {
uint8_t first_block = mf_classic_get_first_block_num_of_sector(i);
for(uint8_t j = 0; j < temp_sector.total_blocks; j++) {
mf_classic_set_block_read(data, first_block + j, &temp_sector.block[j]);
}
sectors_read++;
} else {
// Invalid key, set it to not found
if(key_a != MF_CLASSIC_NO_KEY) {
mf_classic_set_key_not_found(data, i, MfClassicKeyA);
} else {
mf_classic_set_key_not_found(data, i, MfClassicKeyB);
}
}
}
mf_classic_read_sector(tx_rx, data, i);
}
uint8_t sectors_read = 0;
uint8_t keys_found = 0;
mf_classic_get_read_sectors_and_keys(data, &sectors_read, &keys_found);
FURI_LOG_D(TAG, "Read %d sectors and %d keys", sectors_read, keys_found);
return sectors_read;
}