Skip to content

Commit

Permalink
nfc: rework mifare classic key cache
Browse files Browse the repository at this point in the history
  • Loading branch information
gornekich committed Jul 12, 2022
1 parent 2685cdf commit dc5f3b8
Show file tree
Hide file tree
Showing 18 changed files with 229 additions and 98 deletions.
3 changes: 2 additions & 1 deletion applications/nfc/nfc.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ void nfc_rpc_exit_callback(Nfc* nfc) {
}
}

static void nfc_rpc_emulate_callback(NfcWorkerEvent event, void* context) {
static bool nfc_rpc_emulate_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
Nfc* nfc = context;

nfc->rpc_state = NfcRpcStateEmulated;
return true;
}

static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) {
Expand Down
3 changes: 2 additions & 1 deletion applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
#define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL)
#define NFC_MF_CLASSIC_DATA_CHANGED (1UL)

void nfc_emulate_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) {
bool nfc_emulate_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
Nfc* nfc = context;

scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneEmulateMifareClassic, NFC_MF_CLASSIC_DATA_CHANGED);
return true;
}

void nfc_scene_emulate_mifare_classic_on_enter(void* context) {
Expand Down
3 changes: 2 additions & 1 deletion applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
#define NFC_MF_UL_DATA_NOT_CHANGED (0UL)
#define NFC_MF_UL_DATA_CHANGED (1UL)

void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
bool nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
Nfc* nfc = context;

scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
return true;
}

void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
Expand Down
3 changes: 2 additions & 1 deletion applications/nfc/scenes/nfc_scene_emulate_uid.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ enum {
NfcSceneEmulateUidStateTextBox,
};

void nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) {
bool nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
furi_assert(context);
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
return true;
}

void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) {
Expand Down
12 changes: 9 additions & 3 deletions applications/nfc/scenes/nfc_scene_read.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>

void nfc_read_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
bool nfc_read_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
bool consumed = false;
if(event == NfcWorkerEventReadMifareClassicLoadKeyCache) {
consumed = nfc_device_load_key_cache(nfc->dev);
} else {
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
consumed = true;
}
return consumed;
}

void nfc_scene_read_on_enter(void* context) {
Expand Down
3 changes: 2 additions & 1 deletion applications/nfc/scenes/nfc_scene_read_card.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>

void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) {
bool nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
return true;
}

void nfc_scene_read_card_on_enter(void* context) {
Expand Down
3 changes: 2 additions & 1 deletion applications/nfc/scenes/nfc_scene_read_emv_app.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>

void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) {
bool nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
return true;
}

void nfc_scene_read_emv_app_on_enter(void* context) {
Expand Down
3 changes: 2 additions & 1 deletion applications/nfc/scenes/nfc_scene_read_emv_data.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>

void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) {
bool nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
return true;
}

void nfc_scene_read_emv_data_on_enter(void* context) {
Expand Down
3 changes: 2 additions & 1 deletion applications/nfc/scenes/nfc_scene_read_mifare_classic.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ enum {
NfcSceneReadMifareClassicStateDone,
};

void nfc_read_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) {
bool nfc_read_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) {
furi_assert(context);
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
return true;
}

void nfc_read_mifare_classic_dict_attack_result_callback(void* context) {
Expand Down
3 changes: 2 additions & 1 deletion applications/nfc/scenes/nfc_scene_read_mifare_desfire.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>

void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) {
bool nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
return true;
}

void nfc_scene_read_mifare_desfire_on_enter(void* context) {
Expand Down
3 changes: 2 additions & 1 deletion applications/nfc/scenes/nfc_scene_read_mifare_ul.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>

void nfc_read_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
bool nfc_read_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
return true;
}

void nfc_scene_read_mifare_ul_on_enter(void* context) {
Expand Down
106 changes: 93 additions & 13 deletions lib/nfc/nfc_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -753,31 +753,111 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice*
return parsed;
}

static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) {
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
static void nfc_device_get_key_cache_file_path(NfcDevice* dev, string_t file_path) {
uint8_t* uid = dev->dev_data.nfc_data.uid;
uint8_t uid_len = dev->dev_data.nfc_data.uid_len;
// Generate file name by UID
string_t file_path;
string_init(file_path);
string_set_str(file_path, NFC_DEVICE_KEYS_FOLDER "/");
for(size_t i = 0; i < uid_len; i++) {
string_cat_printf(NFC_DEVICE_KEYS_FOLDER "/%02X" NFC_DEVICE_KEYS_EXTENSION, uid[i]);
string_cat_printf(file_path, "%02X", uid[i]);
}
string_cat_printf(file_path, NFC_DEVICE_KEYS_EXTENSION);
}

bool key_save_success = false;
static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) {
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
MfClassicData* data = &dev->dev_data.mf_classic_data;
string_t temp_str;
string_init(temp_str);

nfc_device_get_key_cache_file_path(dev, temp_str);
bool save_success = false;
do {
if(!storage_simply_mkdir(dev->storage, NFC_DEVICE_KEYS_FOLDER)) break;
if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
if(!flipper_format_file_open_always(file, string_get_cstr(file_path))) break;
if(!storage_simply_remove(dev->storage, string_get_cstr(temp_str))) break;
if(!flipper_format_file_open_always(file, string_get_cstr(temp_str))) break;
if(!flipper_format_write_header_cstr(file, nfc_keys_file_header, nfc_keys_file_version))
break;


key_save_success = true;
if(data->type == MfClassicType1k) {
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break;
} else if(data->type == MfClassicType4k) {
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "4K")) break;
}
if(!flipper_format_write_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break;
if(!flipper_format_write_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break;
uint8_t sector_num = mf_classic_get_total_sectors_num(data->type);
bool key_save_success = true;
for(size_t i = 0; (i < sector_num) && (key_save_success); i++) {
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i);
if(FURI_BIT(data->key_a_mask, i)) {
string_printf(temp_str, "Key A sector %d", i);
key_save_success =
flipper_format_write_hex(file, string_get_cstr(temp_str), sec_tr->key_a, 6);
}
if(!key_save_success) break;
if(FURI_BIT(data->key_a_mask, i)) {
string_printf(temp_str, "Key B sector %d", i);
key_save_success =
flipper_format_write_hex(file, string_get_cstr(temp_str), sec_tr->key_b, 6);
}
}
save_success = key_save_success;
} while(false);

flipper_format_free(file);
string_clear(temp_str);
return save_success;
}

bool nfc_device_load_key_cache(NfcDevice* dev) {
furi_assert(dev);
string_t temp_str;
string_init(temp_str);

MfClassicData* data = &dev->dev_data.mf_classic_data;
nfc_device_get_key_cache_file_path(dev, temp_str);
FlipperFormat* file = flipper_format_file_alloc(dev->storage);

bool load_success = false;
do {
if(storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) != FSE_OK) break;
if(!flipper_format_file_open_existing(file, string_get_cstr(temp_str))) break;
uint32_t version = 0;
if(!flipper_format_read_header(file, temp_str, &version)) break;
if(string_cmp_str(temp_str, nfc_keys_file_header)) break;
if(version != nfc_keys_file_version) break;
if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break;
if(!string_cmp_str(temp_str, "1K")) {
data->type = MfClassicType1k;
} else if(!string_cmp_str(temp_str, "4K")) {
data->type = MfClassicType4k;
} else {
break;
}
if(!flipper_format_read_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break;
if(!flipper_format_read_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break;
uint8_t sectors = mf_classic_get_total_sectors_num(data->type);
bool key_read_success = true;
for(size_t i = 0; (i < sectors) && (key_read_success); i++) {
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i);
if(FURI_BIT(data->key_a_mask, i)) {
string_printf(temp_str, "Key A sector %d", i);
key_read_success =
flipper_format_read_hex(file, string_get_cstr(temp_str), sec_tr->key_a, 6);
}
if(!key_read_success) break;
if(FURI_BIT(data->key_b_mask, i)) {
string_printf(temp_str, "Key B sector %d", i);
key_read_success =
flipper_format_read_hex(file, string_get_cstr(temp_str), sec_tr->key_b, 6);
}
}
load_success = key_read_success;
} while(false);

string_clear(temp_str);
flipper_format_free(file);
return key_save_success;

return load_success;
}

void nfc_device_set_name(NfcDevice* dev, const char* name) {
Expand Down
2 changes: 2 additions & 0 deletions lib/nfc/nfc_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name);

bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog);

bool nfc_device_load_key_cache(NfcDevice* dev);

bool nfc_file_select(NfcDevice* dev);

void nfc_device_data_clear(NfcDeviceData* dev);
Expand Down
33 changes: 19 additions & 14 deletions lib/nfc/nfc_worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,11 @@ static bool nfc_worker_read_mf_ul(NfcWorker* nfc_worker, FuriHalNfcTxRxContext*
}

static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
UNUSED(tx_rx);
furi_assert(nfc_worker->callback);
bool read_success = false;

nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false);
do {
if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break;
// Search for keys by uid

// Try to read supported card
for(size_t i = 0; i < NfcSupportedCardTypeEnd; i++) {
if(nfc_supported_card[i].protocol == NfcDeviceProtocolMifareClassic) {
Expand All @@ -158,6 +155,17 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont
}
}
}
if(read_success) break;
// Try to read card with key cache
if(nfc_worker->callback(NfcWorkerEventReadMifareClassicLoadKeyCache, nfc_worker->context)) {
FURI_LOG_D(TAG, "Load keys cache success. Start reading");
uint8_t sectors_read =
mf_classic_update_card(tx_rx, &nfc_worker->dev_data->mf_classic_data);
uint8_t sectors_total =
mf_classic_get_total_sectors_num(nfc_worker->dev_data->mf_classic_data.type);
FURI_LOG_D(TAG, "Read %d sectors out of %d total", sectors_read, sectors_total);
read_success = (sectors_read == sectors_total);
}
} while(false);

return read_success;
Expand Down Expand Up @@ -534,14 +542,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
// Detect Mifare Classic card
while(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
if(furi_hal_nfc_detect(nfc_data, 300)) {
if(mf_classic_get_type(
nfc_data->uid,
nfc_data->uid_len,
nfc_data->atqa[0],
nfc_data->atqa[1],
nfc_data->sak,
&reader)) {
total_sectors = mf_classic_get_total_sectors_num(&reader);
if(mf_classic_get_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak, &reader)) {
total_sectors = mf_classic_get_total_sectors_num(reader.type);
if(reader.type == MfClassicType1k) {
event = NfcWorkerEventDetectedClassic1k;
} else {
Expand All @@ -568,7 +570,10 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
bool sector_key_found = false;
while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) {
furi_hal_nfc_sleep();
if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) {
// TODO REWORK!
uint32_t cuid = 0;
if(furi_hal_nfc_activate_nfca(300, &cuid)) {
furi_hal_nfc_sleep();
if(!card_found_notified) {
if(reader.type == MfClassicType1k) {
event = NfcWorkerEventDetectedClassic1k;
Expand All @@ -585,7 +590,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
curr_sector,
(uint32_t)(curr_key >> 32),
(uint32_t)curr_key);
if(mf_classic_auth_attempt(&tx_rx_ctx, reader.cuid, &auth_ctx, curr_key)) {
if(mf_classic_auth_attempt(&tx_rx_ctx, &auth_ctx, curr_key)) {
sector_key_found = true;
if((auth_ctx.key_a != MF_CLASSIC_NO_KEY) &&
(auth_ctx.key_b != MF_CLASSIC_NO_KEY))
Expand Down
3 changes: 2 additions & 1 deletion lib/nfc/nfc_worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ typedef enum {
NfcWorkerEventReadMifareDesfire,
NfcWorkerEventReadBankCard,
NfcWorkerEventReadMifareClassicDone,
NfcWorkerEventReadMifareClassicLoadKeyCache,
NfcWorkerEventReadMifareClassicDictAttackRequired,

// Nfc worker common events
Expand All @@ -54,7 +55,7 @@ typedef enum {
NfcWorkerEventStartReading,
} NfcWorkerEvent;

typedef void (*NfcWorkerCallback)(NfcWorkerEvent event, void* context);
typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context);

NfcWorker* nfc_worker_alloc();

Expand Down
Loading

0 comments on commit dc5f3b8

Please sign in to comment.