From e0d70441aae37cdd5774ea36cbd0ec9b8f37be06 Mon Sep 17 00:00:00 2001 From: Luu Date: Sat, 8 Feb 2025 00:32:52 +0100 Subject: [PATCH] pre-functional stuff for mfc data loading --- metroflip_i.h | 2 +- scenes/keys.c | 252 +++++++++++++++++++++------------- scenes/metroflip_scene_auto.c | 5 +- scenes/metroflip_scene_load.c | 55 +++++++- scenes/plugins/bip.c | 54 ++++++-- 5 files changed, 254 insertions(+), 114 deletions(-) diff --git a/metroflip_i.h b/metroflip_i.h index 7bad446..edd4764 100644 --- a/metroflip_i.h +++ b/metroflip_i.h @@ -149,7 +149,7 @@ typedef enum { MISSING_KEYFILE } KeyfileManager; -CardType determine_card_type(Nfc* nfc); +CardType determine_card_type(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded); #ifdef FW_ORIGIN_Official #define submenu_add_lockable_item( \ diff --git a/scenes/keys.c b/scenes/keys.c index be46247..bbe3f89 100644 --- a/scenes/keys.c +++ b/scenes/keys.c @@ -9,11 +9,11 @@ #define TAG "keys_check" -const MfClassicKeyPair troika_1k_key[1] = { +const MfClassicKeyPair troika_1k_key[] = { {.a = 0x08b386463229}, }; -const MfClassicKeyPair troika_4k_key[1] = { +const MfClassicKeyPair troika_4k_key[] = { {.a = 0xA73F5DC1D333}, }; @@ -25,111 +25,157 @@ const MfClassicKeyPair charliecard_1k_verify_key[] = { {.a = 0x5EC39B022F2B}, }; -const MfClassicKeyPair bip_1k_verify_key[1] = { +const MfClassicKeyPair bip_1k_verify_key[] = { {.a = 0x3a42f33af429}, }; -const MfClassicKeyPair metromoney_1k_verify_key[1] = { +const MfClassicKeyPair metromoney_1k_verify_key[] = { {.a = 0x9C616585E26D}, }; -static bool charliecard_verify(Nfc* nfc) { +static bool charliecard_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) { bool verified = false; FURI_LOG_I(TAG, "verifying charliecard.."); - + const uint8_t verify_sector = 1; do { - const uint8_t verify_sector = 1; - const uint8_t verify_block = mf_classic_get_first_block_num_of_sector(verify_sector) + 1; - FURI_LOG_I(TAG, "Verifying sector %u", verify_sector); - - MfClassicKey key = {0}; - bit_lib_num_to_bytes_be(charliecard_1k_verify_key[0].a, COUNT_OF(key.data), key.data); - - MfClassicAuthContext auth_context; - MfClassicError error = - mf_classic_poller_sync_auth(nfc, verify_block, &key, MfClassicKeyTypeA, &auth_context); - if(error != MfClassicErrorNone) { - FURI_LOG_I(TAG, "Failed to read block %u: %d", verify_block, error); - break; + if(!data_loaded) { + const uint8_t verify_block = + mf_classic_get_first_block_num_of_sector(verify_sector) + 1; + FURI_LOG_I(TAG, "Verifying sector %u", verify_sector); + + MfClassicKey key = {0}; + bit_lib_num_to_bytes_be(charliecard_1k_verify_key[0].a, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_context; + MfClassicError error = mf_classic_poller_sync_auth( + nfc, verify_block, &key, MfClassicKeyTypeA, &auth_context); + if(error != MfClassicErrorNone) { + FURI_LOG_I(TAG, "Failed to read block %u: %d", verify_block, error); + break; + } + + verified = true; + } else { + MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(mfc_data, verify_sector); + FURI_LOG_I(TAG, "%2x", sec_tr->key_a.data[1]); + uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6); + if(key != charliecard_1k_verify_key[0].a) { + FURI_LOG_I(TAG, "not equall"); + break; + } + + verified = true; } - - verified = true; } while(false); return verified; } -bool bip_verify(Nfc* nfc) { +bool bip_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) { bool verified = false; do { - const uint8_t verify_sector = 0; - uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector); - FURI_LOG_I(TAG, "Verifying sector %u", verify_sector); + if(!data_loaded) { + const uint8_t verify_sector = 0; + uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector); + FURI_LOG_I(TAG, "Verifying sector %u", verify_sector); - MfClassicKey key = {}; - bit_lib_num_to_bytes_be(bip_1k_verify_key[0].a, COUNT_OF(key.data), key.data); + MfClassicKey key = {}; + bit_lib_num_to_bytes_be(bip_1k_verify_key[0].a, COUNT_OF(key.data), key.data); - MfClassicAuthContext auth_ctx = {}; - MfClassicError error = - mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx); + MfClassicAuthContext auth_ctx = {}; + MfClassicError error = + mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx); - if(error != MfClassicErrorNone) { - FURI_LOG_I(TAG, "Failed to read block %u: %d", block_num, error); - break; - } + if(error != MfClassicErrorNone) { + FURI_LOG_I(TAG, "Failed to read block %u: %d", block_num, error); + break; + } + + verified = true; + } else { + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(mfc_data, 0); - verified = true; + uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6); + if(key != bip_1k_verify_key[0].a) { + break; + } + + verified = true; + } } while(false); return verified; } -static bool metromoney_verify(Nfc* nfc) { +static bool metromoney_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) { bool verified = false; - + const uint8_t ticket_sector_number = 1; do { - const uint8_t ticket_sector_number = 1; - const uint8_t ticket_block_number = - mf_classic_get_first_block_num_of_sector(ticket_sector_number) + 1; - FURI_LOG_D(TAG, "Verifying sector %u", ticket_sector_number); - - MfClassicKey key = {0}; - bit_lib_num_to_bytes_be(metromoney_1k_verify_key[0].a, COUNT_OF(key.data), key.data); - - MfClassicAuthContext auth_context; - MfClassicError error = mf_classic_poller_sync_auth( - nfc, ticket_block_number, &key, MfClassicKeyTypeA, &auth_context); - if(error != MfClassicErrorNone) { - FURI_LOG_D(TAG, "Failed to read block %u: %d", ticket_block_number, error); - break; + if(!data_loaded) { + const uint8_t ticket_block_number = + mf_classic_get_first_block_num_of_sector(ticket_sector_number) + 1; + FURI_LOG_D(TAG, "Verifying sector %u", ticket_sector_number); + + MfClassicKey key = {0}; + bit_lib_num_to_bytes_be(metromoney_1k_verify_key[0].a, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_context; + MfClassicError error = mf_classic_poller_sync_auth( + nfc, ticket_block_number, &key, MfClassicKeyTypeA, &auth_context); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", ticket_block_number, error); + break; + } + + verified = true; + } else { + MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(mfc_data, ticket_sector_number); + + uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6); + if(key != metromoney_1k_verify_key[0].a) { + break; + } + + verified = true; } - - verified = true; } while(false); return verified; } -static bool smartrider_verify(Nfc* nfc) { +static bool smartrider_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) { bool verified = false; do { - const uint8_t block_number = mf_classic_get_first_block_num_of_sector(0) + 1; - FURI_LOG_D(TAG, "Verifying sector 0"); - - MfClassicKey key = {0}; - bit_lib_num_to_bytes_be(smartrider_verify_key[0].a, COUNT_OF(key.data), key.data); - - MfClassicAuthContext auth_context; - MfClassicError error = - mf_classic_poller_sync_auth(nfc, block_number, &key, MfClassicKeyTypeA, &auth_context); - if(error != MfClassicErrorNone) { - FURI_LOG_D(TAG, "Failed to read block %u: %d", block_number, error); - break; + if(!data_loaded) { + const uint8_t block_number = mf_classic_get_first_block_num_of_sector(0) + 1; + FURI_LOG_D(TAG, "Verifying sector 0"); + + MfClassicKey key = {0}; + bit_lib_num_to_bytes_be(smartrider_verify_key[0].a, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_context; + MfClassicError error = mf_classic_poller_sync_auth( + nfc, block_number, &key, MfClassicKeyTypeA, &auth_context); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", block_number, error); + break; + } + + verified = true; + } else { + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(mfc_data, 0); + + uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6); + if(key != smartrider_verify_key[0].a) { + break; + } + + verified = true; } - - verified = true; } while(false); return verified; @@ -151,50 +197,66 @@ static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) return success; } -static bool troika_verify_type(Nfc* nfc, MfClassicType type) { +static bool + troika_verify_type(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded, MfClassicType type) { bool verified = false; do { - TroikaCardConfig cfg = {}; - if(!troika_get_card_config(&cfg, type)) break; - - const uint8_t block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector); - FURI_LOG_D(TAG, "Verifying sector %lu", cfg.data_sector); - - MfClassicKey key = {0}; - bit_lib_num_to_bytes_be(cfg.keys[0].a, COUNT_OF(key.data), key.data); - - MfClassicAuthContext auth_context; - MfClassicError error = - mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context); - if(error != MfClassicErrorNone) { - FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); - break; + if(!data_loaded) { + TroikaCardConfig cfg = {}; + if(!troika_get_card_config(&cfg, type)) break; + + const uint8_t block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector); + FURI_LOG_D(TAG, "Verifying sector %lu", cfg.data_sector); + + MfClassicKey key = {0}; + bit_lib_num_to_bytes_be(cfg.keys[0].a, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_context; + MfClassicError error = mf_classic_poller_sync_auth( + nfc, block_num, &key, MfClassicKeyTypeA, &auth_context); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); + break; + } + FURI_LOG_D(TAG, "Verify success!"); + verified = true; + } else { + TroikaCardConfig cfg = {}; + if(!troika_get_card_config(&cfg, type)) break; + MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(mfc_data, cfg.data_sector); + + uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6); + if(key != cfg.keys[0].a) { + break; + } + + verified = true; } - FURI_LOG_D(TAG, "Verify success!"); - verified = true; } while(false); return verified; } -static bool troika_verify(Nfc* nfc) { - return troika_verify_type(nfc, MfClassicType1k) || troika_verify_type(nfc, MfClassicType4k); +static bool troika_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) { + return troika_verify_type(nfc, mfc_data, data_loaded, MfClassicType1k) || + troika_verify_type(nfc, mfc_data, data_loaded, MfClassicType4k); } -CardType determine_card_type(Nfc* nfc) { +CardType determine_card_type(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) { FURI_LOG_I(TAG, "checking keys.."); UNUSED(bip_verify); - if(bip_verify(nfc)) { - return CARD_TYPE_METROMONEY; - } else if(metromoney_verify(nfc)) { + if(bip_verify(nfc, mfc_data, data_loaded)) { + return CARD_TYPE_BIP; + } else if(metromoney_verify(nfc, mfc_data, data_loaded)) { return CARD_TYPE_METROMONEY; - } else if(smartrider_verify(nfc)) { + } else if(smartrider_verify(nfc, mfc_data, data_loaded)) { return CARD_TYPE_SMARTRIDER; - } else if(troika_verify(nfc)) { + } else if(troika_verify(nfc, mfc_data, data_loaded)) { return CARD_TYPE_TROIKA; - } else if(charliecard_verify(nfc)) { + } else if(charliecard_verify(nfc, mfc_data, data_loaded)) { return CARD_TYPE_CHARLIECARD; } else { FURI_LOG_I(TAG, "its unknown"); diff --git a/scenes/metroflip_scene_auto.c b/scenes/metroflip_scene_auto.c index 5cbeeeb..3c72c4d 100644 --- a/scenes/metroflip_scene_auto.c +++ b/scenes/metroflip_scene_auto.c @@ -160,7 +160,10 @@ bool metroflip_scene_auto_on_event(void* context, SceneManagerEvent event) { app->auto_mode = true; if(nfc_detected_protocols_get_protocol(app->detected_protocols, 0) == NfcProtocolMfClassic) { - CardType card_type = determine_card_type(app->nfc); + MfClassicData* mfc_data = mf_classic_alloc(); + app->data_loaded = false; + CardType card_type = determine_card_type(app->nfc, mfc_data, app->data_loaded); + mf_classic_free(mfc_data); app->mfc_card_type = card_type; Popup* popup = app->popup; UNUSED(popup); diff --git a/scenes/metroflip_scene_load.c b/scenes/metroflip_scene_load.c index ef1cb0c..b16eed3 100644 --- a/scenes/metroflip_scene_load.c +++ b/scenes/metroflip_scene_load.c @@ -5,11 +5,14 @@ #include #include "../api/metroflip/metroflip_api.h" #define TAG "Metroflip:Scene:Load" +#include "keys.h" +#include void metroflip_scene_load_on_enter(void* context) { Metroflip* app = (Metroflip*)context; // We initialized this to be false every time we enter app->data_loaded = false; + bool has_card_type = false; // The same string we will use to direct parse scene which plugin to call // Extracted from the file FuriString* card_type = furi_string_alloc(); @@ -26,7 +29,52 @@ void metroflip_scene_load_on_enter(void* context) { FlipperFormat* format = flipper_format_file_alloc(storage); do { if(!flipper_format_file_open_existing(format, furi_string_get_cstr(file_path))) break; - if(!flipper_format_read_string(format, "Card Type", card_type)) break; + if(!flipper_format_read_string(format, "Card Type", card_type)) { + flipper_format_file_close(format); + flipper_format_file_open_existing(format, furi_string_get_cstr(file_path)); + FURI_LOG_I(TAG, "dont have card type in file, detecting.."); + MfClassicData* mfc_data = mf_classic_alloc(); + if(!mf_classic_load(mfc_data, format, 2)) { + FURI_LOG_I(TAG, "failed"); + } else { + FURI_LOG_I(TAG, "success"); + } + FURI_LOG_I(TAG, "%d", mfc_data->block[3].data[1]); + app->data_loaded = true; + CardType card_type = determine_card_type(app->nfc, mfc_data, app->data_loaded); + app->mfc_card_type = card_type; + switch(card_type) { + case CARD_TYPE_METROMONEY: + app->card_type = "metromoney"; + FURI_LOG_I(TAG, "Detected: Metromoney\n"); + break; + case CARD_TYPE_CHARLIECARD: + app->card_type = "charliecard"; + FURI_LOG_I(TAG, "Detected: CharlieCard\n"); + break; + case CARD_TYPE_SMARTRIDER: + app->card_type = "smartrider"; + FURI_LOG_I(TAG, "Detected: SmartRider\n"); + break; + case CARD_TYPE_TROIKA: + app->card_type = "troika"; + FURI_LOG_I(TAG, "Detected: Troika\n"); + break; + case CARD_TYPE_UNKNOWN: + app->card_type = "unknown"; + FURI_LOG_I(TAG, "Detected: Unknown card type\n"); + + //popup_set_header(popup, "Unsupported\n card", 58, 31, AlignLeft, AlignTop); + break; + default: + app->card_type = "unknown"; + FURI_LOG_I(TAG, "Detected: Unknown card type\n"); + //popup_set_header(popup, "Unsupported\n card", 58, 31, AlignLeft, AlignTop); + break; + } + mf_classic_free(mfc_data); + has_card_type = true; + } app->file_path = furi_string_get_cstr(file_path); app->data_loaded = true; } while(0); @@ -35,7 +83,10 @@ void metroflip_scene_load_on_enter(void* context) { if(app->data_loaded) { // Direct to the parsing screen just like the auto scene does - app->card_type = furi_string_get_cstr(card_type); + if(!has_card_type) { + app->card_type = furi_string_get_cstr(card_type); + has_card_type = false; + } scene_manager_next_scene(app->scene_manager, MetroflipSceneParse); } else { scene_manager_next_scene(app->scene_manager, MetroflipSceneStart); diff --git a/scenes/plugins/bip.c b/scenes/plugins/bip.c index 3fe120d..bd3b248 100644 --- a/scenes/plugins/bip.c +++ b/scenes/plugins/bip.c @@ -133,9 +133,7 @@ static bool is_bip_block_empty(const MfClassicBlock* block) { return true; } -static bool - bip_parse(const NfcDevice* device, FuriString* parsed_data, const MfClassicData* data) { - furi_assert(device); +static bool bip_parse(FuriString* parsed_data, const MfClassicData* data) { furi_assert(parsed_data); struct { @@ -311,7 +309,7 @@ static NfcCommand bip_poller_callback(NfcGenericEvent event, void* context) { dolphin_deed(DolphinDeedNfcReadSuccess); furi_string_reset(app->text_box_store); - if(!bip_parse(app->nfc_device, parsed_data, mfc_data)) { + if(!bip_parse(parsed_data, mfc_data)) { furi_string_reset(app->text_box_store); FURI_LOG_I(TAG, "Unknown card type"); furi_string_printf(parsed_data, "\e#Unknown card\n"); @@ -339,18 +337,44 @@ static void bip_on_enter(Metroflip* app) { app->sec_num = 0; - // Setup view - Popup* popup = app->popup; - popup_set_header(popup, "Apply\n card to\nthe back", 68, 30, AlignLeft, AlignTop); - popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); + if(app->data_loaded) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_file_alloc(storage); + if(flipper_format_file_open_existing(ff, app->file_path)) { + MfClassicData* mfc_data = mf_classic_alloc(); + mf_classic_load(mfc_data, ff, 2); + FuriString* parsed_data = furi_string_alloc(); + Widget* widget = app->widget; - // Start worker - view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewPopup); - nfc_scanner_alloc(app->nfc); - app->poller = nfc_poller_alloc(app->nfc, NfcProtocolMfClassic); - nfc_poller_start(app->poller, bip_poller_callback, app); - - metroflip_app_blink_start(app); + furi_string_reset(app->text_box_store); + if(!bip_parse(parsed_data, mfc_data)) { + furi_string_reset(app->text_box_store); + FURI_LOG_I(TAG, "Unknown card type"); + furi_string_printf(parsed_data, "\e#Unknown card\n"); + } + widget_add_text_scroll_element( + widget, 0, 0, 128, 64, furi_string_get_cstr(parsed_data)); + + widget_add_button_element( + widget, GuiButtonTypeRight, "Exit", metroflip_exit_widget_callback, app); + mf_classic_free(mfc_data); + furi_string_free(parsed_data); + view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewWidget); + } + flipper_format_free(ff); + } else { + // Setup view + Popup* popup = app->popup; + popup_set_header(popup, "Apply\n card to\nthe back", 68, 30, AlignLeft, AlignTop); + popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); + + // Start worker + view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewPopup); + app->poller = nfc_poller_alloc(app->nfc, NfcProtocolMfClassic); + nfc_poller_start(app->poller, bip_poller_callback, app); + + metroflip_app_blink_start(app); + } } static bool bip_on_event(Metroflip* app, SceneManagerEvent event) {