diff --git a/applications/main/nfc/helpers/nfc_supported_cards.c b/applications/main/nfc/helpers/nfc_supported_cards.c index a242ba3ae6..6016ae1784 100644 --- a/applications/main/nfc/helpers/nfc_supported_cards.c +++ b/applications/main/nfc/helpers/nfc_supported_cards.c @@ -1,4 +1,5 @@ #include "nfc_supported_cards.h" + #include "../plugins/supported_cards/nfc_supported_card_plugin.h" #include @@ -7,22 +8,72 @@ #include #include +#include #define TAG "NfcSupportedCards" #define NFC_SUPPORTED_CARDS_PLUGINS_PATH APP_DATA_PATH("plugins") #define NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX "_parser.fal" +typedef enum { + NfcSupportedCardsPluginFeatureHasVerify = (1U << 0), + NfcSupportedCardsPluginFeatureHasRead = (1U << 1), + NfcSupportedCardsPluginFeatureHasParse = (1U << 2), +} NfcSupportedCardsPluginFeature; + +typedef struct { + FuriString* path; + NfcProtocol protocol; + NfcSupportedCardsPluginFeature feature; +} NfcSupportedCardsPluginCache; + +ARRAY_DEF(NfcSupportedCardsPluginCache, NfcSupportedCardsPluginCache, M_POD_OPLIST); + +typedef enum { + NfcSupportedCardsLoadStateIdle, + NfcSupportedCardsLoadStateInProgress, + NfcSupportedCardsLoadStateSuccess, + NfcSupportedCardsLoadStateFail, +} NfcSupportedCardsLoadState; + typedef struct { Storage* storage; File* directory; FuriString* file_path; char file_name[256]; FlipperApplication* app; -} NfcSupportedCards; +} NfcSupportedCardsLoadContext; -static NfcSupportedCards* nfc_supported_cards_alloc() { +struct NfcSupportedCards { + NfcSupportedCardsPluginCache_t plugins_cache_arr; + NfcSupportedCardsLoadState load_state; + NfcSupportedCardsLoadContext* load_context; +}; + +NfcSupportedCards* nfc_supported_cards_alloc() { NfcSupportedCards* instance = malloc(sizeof(NfcSupportedCards)); + NfcSupportedCardsPluginCache_init(instance->plugins_cache_arr); + + return instance; +} + +void nfc_supported_cards_free(NfcSupportedCards* instance) { + furi_assert(instance); + + NfcSupportedCardsPluginCache_it_t iter; + for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr); + !NfcSupportedCardsPluginCache_end_p(iter); + NfcSupportedCardsPluginCache_next(iter)) { + NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter); + furi_string_free(plugin_cache->path); + } + + NfcSupportedCardsPluginCache_clear(instance->plugins_cache_arr); + free(instance); +} + +static NfcSupportedCardsLoadContext* nfc_supported_cards_load_context_alloc() { + NfcSupportedCardsLoadContext* instance = malloc(sizeof(NfcSupportedCardsLoadContext)); instance->storage = furi_record_open(RECORD_STORAGE); instance->directory = storage_file_alloc(instance->storage); @@ -35,7 +86,7 @@ static NfcSupportedCards* nfc_supported_cards_alloc() { return instance; } -static void nfc_supported_cards_free(NfcSupportedCards* instance) { +static void nfc_supported_cards_load_context_free(NfcSupportedCardsLoadContext* instance) { if(instance->app) { flipper_application_free(instance->app); } @@ -50,7 +101,36 @@ static void nfc_supported_cards_free(NfcSupportedCards* instance) { } static const NfcSupportedCardsPlugin* - nfc_supported_cards_get_next_plugin(NfcSupportedCards* instance) { + nfc_supported_cards_get_plugin(NfcSupportedCardsLoadContext* instance, FuriString* path) { + furi_assert(instance); + furi_assert(path); + + const NfcSupportedCardsPlugin* plugin = NULL; + do { + if(instance->app) flipper_application_free(instance->app); + instance->app = flipper_application_alloc(instance->storage, firmware_api_interface); + if(flipper_application_preload(instance->app, furi_string_get_cstr(path)) != + FlipperApplicationPreloadStatusSuccess) + break; + if(!flipper_application_is_plugin(instance->app)) break; + if(flipper_application_map_to_memory(instance->app) != FlipperApplicationLoadStatusSuccess) + break; + const FlipperAppPluginDescriptor* descriptor = + flipper_application_plugin_get_descriptor(instance->app); + + if(descriptor == NULL) break; + + if(strcmp(descriptor->appid, NFC_SUPPORTED_CARD_PLUGIN_APP_ID) != 0) break; + if(descriptor->ep_api_version != NFC_SUPPORTED_CARD_PLUGIN_API_VERSION) break; + + plugin = descriptor->entry_point; + } while(false); + + return plugin; +} + +static const NfcSupportedCardsPlugin* + nfc_supported_cards_get_next_plugin(NfcSupportedCardsLoadContext* instance) { const NfcSupportedCardsPlugin* plugin = NULL; do { @@ -65,83 +145,137 @@ static const NfcSupportedCardsPlugin* path_concat(NFC_SUPPORTED_CARDS_PLUGINS_PATH, instance->file_name, instance->file_path); - if(instance->app) flipper_application_free(instance->app); - instance->app = flipper_application_alloc(instance->storage, firmware_api_interface); + plugin = nfc_supported_cards_get_plugin(instance, instance->file_path); + } while(plugin == NULL); //-V654 - if(flipper_application_preload(instance->app, furi_string_get_cstr(instance->file_path)) != - FlipperApplicationPreloadStatusSuccess) - continue; - if(!flipper_application_is_plugin(instance->app)) continue; + return plugin; +} - if(flipper_application_map_to_memory(instance->app) != FlipperApplicationLoadStatusSuccess) - continue; +void nfc_supported_cards_load_cache(NfcSupportedCards* instance) { + furi_assert(instance); - const FlipperAppPluginDescriptor* descriptor = - flipper_application_plugin_get_descriptor(instance->app); + do { + if((instance->load_state == NfcSupportedCardsLoadStateSuccess) || + (instance->load_state == NfcSupportedCardsLoadStateFail)) + break; - if(descriptor == NULL) continue; + instance->load_context = nfc_supported_cards_load_context_alloc(); + + while(true) { + const NfcSupportedCardsPlugin* plugin = + nfc_supported_cards_get_next_plugin(instance->load_context); + if(plugin == NULL) break; //-V547 + + NfcSupportedCardsPluginCache plugin_cache = {}; //-V779 + plugin_cache.path = furi_string_alloc_set(instance->load_context->file_path); + plugin_cache.protocol = plugin->protocol; + if(plugin->verify) { + plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasVerify; + } + if(plugin->read) { + plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasRead; + } + if(plugin->parse) { + plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasParse; + } + NfcSupportedCardsPluginCache_push_back(instance->plugins_cache_arr, plugin_cache); + } - if(strcmp(descriptor->appid, NFC_SUPPORTED_CARD_PLUGIN_APP_ID) != 0) continue; - if(descriptor->ep_api_version != NFC_SUPPORTED_CARD_PLUGIN_API_VERSION) continue; + nfc_supported_cards_load_context_free(instance->load_context); - plugin = descriptor->entry_point; - } while(plugin == NULL); //-V654 + size_t plugins_loaded = NfcSupportedCardsPluginCache_size(instance->plugins_cache_arr); + if(plugins_loaded == 0) { + FURI_LOG_D(TAG, "Plugins not found"); + instance->load_state = NfcSupportedCardsLoadStateFail; + } else { + FURI_LOG_D(TAG, "Loaded %zu plugins", plugins_loaded); + instance->load_state = NfcSupportedCardsLoadStateSuccess; + } - return plugin; + } while(false); } -bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc) { +bool nfc_supported_cards_read(NfcSupportedCards* instance, NfcDevice* device, Nfc* nfc) { + furi_assert(instance); furi_assert(device); furi_assert(nfc); bool card_read = false; - - NfcSupportedCards* supported_cards = nfc_supported_cards_alloc(); + NfcProtocol protocol = nfc_device_get_protocol(device); do { - const NfcSupportedCardsPlugin* plugin = - nfc_supported_cards_get_next_plugin(supported_cards); - if(plugin == NULL) break; //-V547 - - const NfcProtocol protocol = nfc_device_get_protocol(device); //-V779 - if(plugin->protocol != protocol) continue; - - if(plugin->verify) { - if(!plugin->verify(nfc)) continue; - } - - if(plugin->read) { - card_read = plugin->read(nfc, device); + if(instance->load_state != NfcSupportedCardsLoadStateSuccess) break; + + instance->load_context = nfc_supported_cards_load_context_alloc(); + + NfcSupportedCardsPluginCache_it_t iter; + for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr); + !NfcSupportedCardsPluginCache_end_p(iter); + NfcSupportedCardsPluginCache_next(iter)) { + NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter); + if(plugin_cache->protocol != protocol) continue; + if((plugin_cache->feature & NfcSupportedCardsPluginFeatureHasRead) == 0) continue; + + const NfcSupportedCardsPlugin* plugin = + nfc_supported_cards_get_plugin(instance->load_context, plugin_cache->path); + if(plugin == NULL) continue; + + if(plugin->verify) { + if(!plugin->verify(nfc)) continue; + } + + if(plugin->read) { + if(plugin->read(nfc, device)) { + card_read = true; + break; + } + } } - } while(!card_read); + nfc_supported_cards_load_context_free(instance->load_context); + } while(false); - nfc_supported_cards_free(supported_cards); return card_read; } -bool nfc_supported_cards_parse(const NfcDevice* device, FuriString* parsed_data) { +bool nfc_supported_cards_parse( + NfcSupportedCards* instance, + NfcDevice* device, + FuriString* parsed_data) { + furi_assert(instance); furi_assert(device); furi_assert(parsed_data); - bool parsed = false; - - NfcSupportedCards* supported_cards = nfc_supported_cards_alloc(); + bool card_parsed = false; + NfcProtocol protocol = nfc_device_get_protocol(device); do { - const NfcSupportedCardsPlugin* plugin = - nfc_supported_cards_get_next_plugin(supported_cards); - if(plugin == NULL) break; //-V547 - - const NfcProtocol protocol = nfc_device_get_protocol(device); //-V779 - if(plugin->protocol != protocol) continue; - - if(plugin->parse) { - parsed = plugin->parse(device, parsed_data); + if(instance->load_state != NfcSupportedCardsLoadStateSuccess) break; + + instance->load_context = nfc_supported_cards_load_context_alloc(); + + NfcSupportedCardsPluginCache_it_t iter; + for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr); + !NfcSupportedCardsPluginCache_end_p(iter); + NfcSupportedCardsPluginCache_next(iter)) { + NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter); + if(plugin_cache->protocol != protocol) continue; + if((plugin_cache->feature & NfcSupportedCardsPluginFeatureHasParse) == 0) continue; + + const NfcSupportedCardsPlugin* plugin = + nfc_supported_cards_get_plugin(instance->load_context, plugin_cache->path); + if(plugin == NULL) continue; + + if(plugin->parse) { + if(plugin->parse(device, parsed_data)) { + card_parsed = true; + break; + } + } } - } while(!parsed); + nfc_supported_cards_load_context_free(instance->load_context); + } while(false); - nfc_supported_cards_free(supported_cards); - return parsed; + return card_parsed; } diff --git a/applications/main/nfc/helpers/nfc_supported_cards.h b/applications/main/nfc/helpers/nfc_supported_cards.h index 0c25a5b118..7778c6f22d 100644 --- a/applications/main/nfc/helpers/nfc_supported_cards.h +++ b/applications/main/nfc/helpers/nfc_supported_cards.h @@ -15,6 +15,34 @@ extern "C" { #endif +/** + * @brief NfcSupportedCards opaque type definition. + */ +typedef struct NfcSupportedCards NfcSupportedCards; + +/** + * @brief Allocate NfcSupportedCards instance. + * + * @return pointer to allocated NfcSupportedCards instance. + */ +NfcSupportedCards* nfc_supported_cards_alloc(); + +/** + * @brief Delete an NfcSupportedCards instance + * + * @param[in] instance pointer to instance to be deleted. + */ +void nfc_supported_cards_free(NfcSupportedCards* instance); + +/** + * @brief Load plugins information to cache. + * + * @note This function must be called before calling read and parse fanctions. + * + * @param[in, out] instance pointer to NfcSupportedCards instance. + */ +void nfc_supported_cards_load_cache(NfcSupportedCards* instance); + /** * @brief Read the card using a custom procedure. * @@ -22,13 +50,14 @@ extern "C" { * try to execute the custom read procedure specified in each. Upon first success, * no further attempts will be made and the function will return. * + * @param[in, out] instance pointer to NfcSupportedCards instance. * @param[in,out] device pointer to a device instance to hold the read data. * @param[in,out] nfc pointer to an Nfc instance. * @returns true if the card was successfully read, false otherwise. * * @see NfcSupportedCardPluginRead for detailed description. */ -bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc); +bool nfc_supported_cards_read(NfcSupportedCards* instance, NfcDevice* device, Nfc* nfc); /** * @brief Parse raw data into human-readable representation. @@ -37,13 +66,17 @@ bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc); * try to parse the data according to each implementation. Upon first success, * no further attempts will be made and the function will return. * + * @param[in, out] instance pointer to NfcSupportedCards instance. * @param[in] device pointer to a device instance holding the data is to be parsed. * @param[out] parsed_data pointer to the string to contain the formatted result. * @returns true if the card was successfully parsed, false otherwise. * * @see NfcSupportedCardPluginParse for detailed description. */ -bool nfc_supported_cards_parse(const NfcDevice* device, FuriString* parsed_data); +bool nfc_supported_cards_parse( + NfcSupportedCards* instance, + NfcDevice* device, + FuriString* parsed_data); #ifdef __cplusplus } diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 6ad4a22998..3cfeeeca0a 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -8,7 +8,6 @@ #include "nfc_protocol_support.h" #include "nfc/nfc_app_i.h" -#include "nfc/helpers/nfc_supported_cards.h" #include "nfc_protocol_support_defs.h" #include "nfc_protocol_support_gui_common.h" @@ -157,9 +156,11 @@ static void nfc_protocol_support_scene_read_on_enter(NfcApp* instance) { instance->protocols_detected[instance->protocols_detected_selected_idx]; instance->poller = nfc_poller_alloc(instance->nfc, protocol); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); + nfc_supported_cards_load_cache(instance->nfc_supported_cards); + // Start poller with the appropriate callback nfc_protocol_support[protocol]->scene_read.on_enter(instance); - view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); nfc_blink_detect_start(instance); } @@ -178,7 +179,8 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana } else if(event.event == NfcCustomEventPollerIncomplete) { nfc_poller_stop(instance->poller); nfc_poller_free(instance->poller); - bool card_read = nfc_supported_cards_read(instance->nfc_device, instance->nfc); + bool card_read = nfc_supported_cards_read( + instance->nfc_supported_cards, instance->nfc_device, instance->nfc); if(card_read) { notification_message(instance->notifications, &sequence_success); scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); @@ -303,7 +305,7 @@ static void nfc_protocol_support_scene_read_success_on_enter(NfcApp* instance) { Widget* widget = instance->widget; FuriString* temp_str = furi_string_alloc(); - if(nfc_supported_cards_parse(instance->nfc_device, temp_str)) { + if(nfc_supported_cards_parse(instance->nfc_supported_cards, instance->nfc_device, temp_str)) { widget_add_text_scroll_element( instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); } else { diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 5ae0ca5f57..ec528ad9c4 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -51,6 +51,7 @@ NfcApp* nfc_app_alloc() { instance->mf_ul_auth = mf_ultralight_auth_alloc(); instance->mfc_key_cache = mf_classic_key_cache_alloc(); + instance->nfc_supported_cards = nfc_supported_cards_alloc(); // Nfc device instance->nfc_device = nfc_device_alloc(); @@ -110,7 +111,6 @@ NfcApp* nfc_app_alloc() { instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget)); // Dict attack - instance->dict_attack = dict_attack_alloc(); view_dispatcher_add_view( instance->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(instance->dict_attack)); @@ -141,6 +141,7 @@ void nfc_app_free(NfcApp* instance) { mf_ultralight_auth_free(instance->mf_ul_auth); mf_classic_key_cache_free(instance->mfc_key_cache); + nfc_supported_cards_free(instance->nfc_supported_cards); // Nfc device nfc_device_free(instance->nfc_device); @@ -339,6 +340,8 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) { furi_assert(path); bool result = false; + nfc_supported_cards_load_cache(instance->nfc_supported_cards); + FuriString* load_path = furi_string_alloc(); if(nfc_has_shadow_file_internal(instance, path)) { nfc_set_shadow_file_path(path, load_path); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 3c0092007a..bde87b12b6 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -31,6 +31,7 @@ #include "helpers/mf_user_dict.h" #include "helpers/mfkey32_logger.h" #include "helpers/mf_classic_key_cache.h" +#include "helpers/nfc_supported_cards.h" #include #include @@ -132,6 +133,7 @@ struct NfcApp { Mfkey32Logger* mfkey32_logger; MfUserDict* mf_user_dict; MfClassicKeyCache* mfc_key_cache; + NfcSupportedCards* nfc_supported_cards; NfcDevice* nfc_device; Iso14443_3aData* iso14443_3a_edit_data; diff --git a/applications/main/nfc/plugins/supported_cards/mykey.c b/applications/main/nfc/plugins/supported_cards/mykey.c index d7a0ea4fda..a0e206f9c8 100644 --- a/applications/main/nfc/plugins/supported_cards/mykey.c +++ b/applications/main/nfc/plugins/supported_cards/mykey.c @@ -1,119 +1,112 @@ #include "nfc_supported_card_plugin.h" -#include -#include -#include -#include - -//Structures data of mykey card -enum { - MYKEY_BLOCK_KEY_ID = 0x07, - MYKEY_BLOCK_PRODUCTION_DATE = 0x08, - MYKEY_BLOCK_VENDOR_ID_1 = 0x18, - MYKEY_BLOCK_VENDOR_ID_2 = 0x19, - MYKEY_BLOCK_CURRENT_CREDIT = 0x21, - MYKEY_BLOCK_PREVIOUS_CREDIT = 0x23, - MYKEY_DEFAULT_VENDOR_ID = 0xFEDC0123, - MYKEY_DEFAULT_VENDOR_ID_1 = 0xFEDC, - MYKEY_DEFAULT_VENDOR_ID_2 = 0x0123, -}; - -typedef enum { - LockIdStatusNone, - LockIdStatusActive, -} LockIdStatus; - -/* Function to obtain the UID as a 32-bit */ -uint32_t get_uid(const uint8_t uid[8]) { - return (uid[7] | (uid[6] << 8) | (uid[5] << 16) | (uid[4] << 24)); -} -/* OTP calculation (reverse block 6, incremental. 1,2,3, ecc.) */ -uint32_t new_get_count_down_counter(uint32_t b6) { - return ~(b6 << 24 | (b6 & 0x0000FF00) << 8 | (b6 & 0x00FF0000) >> 8 | b6 >> 24); -} - -/* Function to check if the vendor is bound */ -int get_is_bound(uint32_t vendor_id) { - return (vendor_id != MYKEY_DEFAULT_VENDOR_ID); -} - -/* MK = UID * VENDOR */ -uint32_t get_master_key(uint32_t uid, uint32_t vendor_id) { - return uid * (vendor_id + 1); -} +#include +#include +#include -/* SK (Encryption key) = MK * OTP */ -uint32_t get_encryption_key(uint32_t master_key, uint32_t count_down_counter) { - return master_key * (count_down_counter + 1); -} +#define TAG "MyKey" -/* Encode or decode a MyKey block */ -uint32_t encode_decode_block(uint32_t input) { - /* - * Swap all values using XOR - * 32 bit: 1111222233334444 - */ - input ^= (input & 0x00C00000) << 6 | (input & 0x0000C000) << 12 | (input & 0x000000C0) << 18 | - (input & 0x000C0000) >> 6 | (input & 0x00030000) >> 12 | (input & 0x00000300) >> 6; - input ^= (input & 0x30000000) >> 6 | (input & 0x0C000000) >> 12 | (input & 0x03000000) >> 18 | - (input & 0x00003000) << 6 | (input & 0x00000030) << 12 | (input & 0x0000000C) << 6; - input ^= (input & 0x00C00000) << 6 | (input & 0x0000C000) << 12 | (input & 0x000000C0) << 18 | - (input & 0x000C0000) >> 6 | (input & 0x00030000) >> 12 | (input & 0x00000300) >> 6; - return input; -} - -uint32_t get_block(uint32_t block) { - return encode_decode_block(__bswap32(block)); -} +const uint32_t blankBlock18 = 0x480FCD8F, blankBlock19 = 0x070082C0; -uint32_t get_xored_block(uint32_t block, uint32_t key) { - return encode_decode_block(__bswap32(block) ^ key); +static bool mykey_is_blank(const St25tbData* data) { + return data->blocks[0x18] == blankBlock18 && data->blocks[0x19] == blankBlock19; } -uint32_t get_vendor(uint32_t b1, uint32_t b2) { - return b1 << 16 | (b2 & 0x0000FFFF); +static bool mykey_has_lockid(const St25tbData* data) { + return (data->blocks[5] & 0xFF) == 0x7F; } static bool mykey_parse(const NfcDevice* device, FuriString* parsed_data) { furi_assert(device); furi_assert(parsed_data); - bool parsed = false; - - do { - //Get data - const St25tbData* data = nfc_device_get_data(device, NfcProtocolSt25tb); - - //Calc data - uint32_t _uid = get_uid(data->uid); - uint32_t _count_down_counter_new = new_get_count_down_counter(__bswap32(data->blocks[6])); - uint32_t _vendor_id = get_vendor( - get_block(data->blocks[MYKEY_BLOCK_VENDOR_ID_1]), - get_block(data->blocks[MYKEY_BLOCK_VENDOR_ID_2])); - uint32_t _master_key = get_master_key(_uid, _vendor_id); - uint32_t _encryption_key = get_encryption_key(_master_key, _count_down_counter_new); - uint16_t credit = - get_xored_block(data->blocks[MYKEY_BLOCK_CURRENT_CREDIT], _encryption_key); - uint16_t _previous_credit = get_block(data->blocks[MYKEY_BLOCK_PREVIOUS_CREDIT]); - bool _is_bound = get_is_bound(_vendor_id); - - //parse data - furi_string_cat_printf(parsed_data, "\e#MyKey Card\n"); - furi_string_cat_printf(parsed_data, "UID: %08lX\n", _uid); - furi_string_cat_printf(parsed_data, "Vendor ID: %08lX\n", _vendor_id); + const St25tbData* data = nfc_device_get_data(device, NfcProtocolSt25tb); + + if(data->type != St25tbType04k && data->type != St25tbTypeX4k) { + FURI_LOG_D(TAG, "bad type"); + return false; + } + + for(int i = 0; i < 5; i++) { + if(data->blocks[i] != 0xFFFFFFFF) { + FURI_LOG_D(TAG, "bad otp block %d", i); + return false; + } + } + + if((data->blocks[8] >> 16 & 0xFF) > 0x31 || (data->blocks[8] >> 8 & 0xFF) > 0x12) { + FURI_LOG_D(TAG, "bad mfg date"); + return false; + } + + if(data->system_otp_block != 0xFEFFFFFF) { + FURI_LOG_D(TAG, "bad sys otp block"); + return false; + } + + furi_string_cat(parsed_data, "\e#MyKey\n"); + + if(data->blocks[6] == 0) { // Tag is actually a MyKey but it has been bricked by a reader + furi_string_cat(parsed_data, "\e#Bricked!\nBlock 6 is 0!"); + return true; + } + + bool is_blank = mykey_is_blank(data); + furi_string_cat_printf(parsed_data, "Serial#: %08lX\n", (uint32_t)__bswap32(data->blocks[7])); + furi_string_cat_printf(parsed_data, "Blank: %s\n", is_blank ? "yes" : "no"); + furi_string_cat_printf(parsed_data, "LockID: %s\n", mykey_has_lockid(data) ? "maybe" : "no"); + + uint32_t block8 = data->blocks[8]; + furi_string_cat_printf( + parsed_data, + "Prod. date: %02lX/%02lX/%04lX", + block8 >> 16 & 0xFF, + block8 >> 8 & 0xFF, + 0x2000 + (block8 & 0xFF)); + + if(!is_blank) { furi_string_cat_printf( - parsed_data, "Current Credit: %d.%02d E \n", credit / 100, credit % 100); - furi_string_cat_printf( - parsed_data, - "Previus Credit: %d.%02d E \n", - _previous_credit / 100, - _previous_credit % 100); - furi_string_cat_printf(parsed_data, "Is Bound: %s\n", _is_bound ? "yes" : "no"); - - parsed = true; - } while(false); - - return parsed; + parsed_data, "\nOp. count: %zu\n", (size_t)__bswap32(data->blocks[0x12] & 0xFFFFFF00)); + + uint32_t block3C = data->blocks[0x3C]; + if(block3C == 0xFFFFFFFF) { + furi_string_cat(parsed_data, "No history available!"); + } else { + block3C ^= data->blocks[0x07]; + uint32_t startingOffset = ((block3C & 0x30000000) >> 28) | + ((block3C & 0x00100000) >> 18); + furi_check(startingOffset < 8); //-V547 + for(int txnOffset = 8; txnOffset > 0; txnOffset--) { + uint32_t txnBlock = + __bswap32(data->blocks[0x34 + ((startingOffset + txnOffset) % 8)]); + + if(txnBlock == 0xFFFFFFFF) { + break; + } + + uint8_t day = txnBlock >> 27; + uint8_t month = txnBlock >> 23 & 0xF; + uint16_t year = 2000 + (txnBlock >> 16 & 0x7F); + uint16_t credit = txnBlock & 0xFFFF; + + if(txnOffset == 8) { + furi_string_cat_printf( + parsed_data, "Current credit: %d.%02d euros\n", credit / 100, credit % 100); + furi_string_cat(parsed_data, "Op. history (newest first):"); + } + + furi_string_cat_printf( + parsed_data, + "\n %02d/%02d/%04d %d.%02d", + day, + month, + year, + credit / 100, + credit % 100); + } + } + } + return true; } /* Actual implementation of app<>plugin interface */ @@ -134,4 +127,4 @@ static const FlipperAppPluginDescriptor mykey_plugin_descriptor = { /* Plugin entry point - must return a pointer to const descriptor */ const FlipperAppPluginDescriptor* mykey_plugin_ep() { return &mykey_plugin_descriptor; -} \ No newline at end of file +} diff --git a/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc b/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc index 9d8739f448..ee436125d3 100644 --- a/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc +++ b/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc @@ -3828,3 +3828,11 @@ F72CD208FDF9 555D8BBC2D3E 78DF1176C8FD ADC169F922CB + +# PIK Comfort Moscow keys (ISBC Mifare Plus SE 1K) +009FB42D98ED +002E626E2820 + +# Volgograd (Russia) Volna transport cards keys +2B787A063D5D +D37C8F1793F7 \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_supported_card.c b/applications/main/nfc/scenes/nfc_scene_supported_card.c index cea55b783b..e32571bf30 100644 --- a/applications/main/nfc/scenes/nfc_scene_supported_card.c +++ b/applications/main/nfc/scenes/nfc_scene_supported_card.c @@ -1,6 +1,5 @@ #include "nfc/nfc_app_i.h" -#include "nfc/helpers/nfc_supported_cards.h" #include "nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h" void nfc_scene_supported_card_on_enter(void* context) { @@ -8,7 +7,7 @@ void nfc_scene_supported_card_on_enter(void* context) { FuriString* temp_str = furi_string_alloc(); - if(nfc_supported_cards_parse(instance->nfc_device, temp_str)) { + if(nfc_supported_cards_parse(instance->nfc_supported_cards, instance->nfc_device, temp_str)) { widget_add_text_scroll_element( instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); widget_add_button_element( diff --git a/applications/services/cli/cli.c b/applications/services/cli/cli.c index ad3bbd6650..55a603a20c 100644 --- a/applications/services/cli/cli.c +++ b/applications/services/cli/cli.c @@ -118,7 +118,8 @@ void cli_motd() { "|_| |____||___||_| |_| |___||_|_\\ \\___||____||___|\r\n" "\r\n" "Welcome to Flipper Zero Command Line Interface!\r\n" - "Read Manual https://docs.flipperzero.one\r\n" + "Read the manual: https://docs.flipper.net/development/cli\r\n" + "Run `help` or `?` to list available commands\r\n" "\r\n"); const Version* firmware_version = furi_hal_version_get_firmware_version(); diff --git a/lib/nfc/helpers/nfc_util.c b/lib/nfc/helpers/nfc_util.c index 8cb6d57f21..b7a9f5ec9b 100644 --- a/lib/nfc/helpers/nfc_util.c +++ b/lib/nfc/helpers/nfc_util.c @@ -35,6 +35,19 @@ uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len) { return res; } +uint64_t nfc_util_bytes2num_little_endian(const uint8_t* src, uint8_t len) { + furi_assert(src); + furi_assert(len <= 8); + + uint64_t res = 0; + uint8_t shift = 0; + while(len--) { + res |= ((uint64_t)*src) << (8 * shift++); + src++; + } + return res; +} + uint8_t nfc_util_even_parity32(uint32_t data) { // data ^= data >> 16; // data ^= data >> 8; diff --git a/lib/nfc/helpers/nfc_util.h b/lib/nfc/helpers/nfc_util.h index a9d5a3f8ab..39eb401718 100644 --- a/lib/nfc/helpers/nfc_util.h +++ b/lib/nfc/helpers/nfc_util.h @@ -10,6 +10,8 @@ void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest); uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len); +uint64_t nfc_util_bytes2num_little_endian(const uint8_t* src, uint8_t len); + uint8_t nfc_util_even_parity32(uint32_t data); uint8_t nfc_util_odd_parity8(uint8_t data); diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index d684cc9e94..c166e78ee7 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,49.2,, +Version,+,49.3,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 34f7d36148..ef4f9b2eb0 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,49.2,, +Version,+,49.3,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -2527,6 +2527,7 @@ Function,+,nfc_set_mask_receive_time_fc,void,"Nfc*, uint32_t" Function,+,nfc_start,void,"Nfc*, NfcEventCallback, void*" Function,+,nfc_stop,void,Nfc* Function,+,nfc_util_bytes2num,uint64_t,"const uint8_t*, uint8_t" +Function,+,nfc_util_bytes2num_little_endian,uint64_t,"const uint8_t*, uint8_t" Function,+,nfc_util_even_parity32,uint8_t,uint32_t Function,+,nfc_util_num2bytes,void,"uint64_t, uint8_t, uint8_t*" Function,+,nfc_util_odd_parity,void,"const uint8_t*, uint8_t*, uint8_t"