mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-18 19:01:47 +03:00
Merge branch 'dev' into nfc-parsers
This commit is contained in:
commit
afc2b14578
@ -1,4 +1,5 @@
|
||||
#include "nfc_supported_cards.h"
|
||||
|
||||
#include "../plugins/supported_cards/nfc_supported_card_plugin.h"
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
@ -7,22 +8,72 @@
|
||||
|
||||
#include <furi.h>
|
||||
#include <path.h>
|
||||
#include <m-array.h>
|
||||
|
||||
#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);
|
||||
|
||||
if(flipper_application_preload(instance->app, furi_string_get_cstr(instance->file_path)) !=
|
||||
FlipperApplicationPreloadStatusSuccess)
|
||||
continue;
|
||||
if(!flipper_application_is_plugin(instance->app)) continue;
|
||||
|
||||
if(flipper_application_map_to_memory(instance->app) != FlipperApplicationLoadStatusSuccess)
|
||||
continue;
|
||||
|
||||
const FlipperAppPluginDescriptor* descriptor =
|
||||
flipper_application_plugin_get_descriptor(instance->app);
|
||||
|
||||
if(descriptor == NULL) continue;
|
||||
|
||||
if(strcmp(descriptor->appid, NFC_SUPPORTED_CARD_PLUGIN_APP_ID) != 0) continue;
|
||||
if(descriptor->ep_api_version != NFC_SUPPORTED_CARD_PLUGIN_API_VERSION) continue;
|
||||
|
||||
plugin = descriptor->entry_point;
|
||||
plugin = nfc_supported_cards_get_plugin(instance, instance->file_path);
|
||||
} while(plugin == NULL); //-V654
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc) {
|
||||
void nfc_supported_cards_load_cache(NfcSupportedCards* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
do {
|
||||
if((instance->load_state == NfcSupportedCardsLoadStateSuccess) ||
|
||||
(instance->load_state == NfcSupportedCardsLoadStateFail))
|
||||
break;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
nfc_supported_cards_load_context_free(instance->load_context);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
} while(false);
|
||||
}
|
||||
|
||||
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
|
||||
if(instance->load_state != NfcSupportedCardsLoadStateSuccess) break;
|
||||
|
||||
const NfcProtocol protocol = nfc_device_get_protocol(device); //-V779
|
||||
if(plugin->protocol != protocol) continue;
|
||||
instance->load_context = nfc_supported_cards_load_context_alloc();
|
||||
|
||||
if(plugin->verify) {
|
||||
if(!plugin->verify(nfc)) continue;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(plugin->read) {
|
||||
card_read = plugin->read(nfc, device);
|
||||
}
|
||||
nfc_supported_cards_load_context_free(instance->load_context);
|
||||
} while(false);
|
||||
|
||||
} while(!card_read);
|
||||
|
||||
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
|
||||
if(instance->load_state != NfcSupportedCardsLoadStateSuccess) break;
|
||||
|
||||
const NfcProtocol protocol = nfc_device_get_protocol(device); //-V779
|
||||
if(plugin->protocol != protocol) continue;
|
||||
instance->load_context = nfc_supported_cards_load_context_alloc();
|
||||
|
||||
if(plugin->parse) {
|
||||
parsed = plugin->parse(device, parsed_data);
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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 <dialogs/dialogs.h>
|
||||
#include <storage/storage.h>
|
||||
@ -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;
|
||||
|
@ -1,119 +1,112 @@
|
||||
#include "nfc_supported_card_plugin.h"
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <lib/nfc/protocols/st25tb/st25tb.h>
|
||||
#include <nfc/nfc_device.h>
|
||||
#include <nfc/helpers/nfc_util.h>
|
||||
#include <machine/endian.h>
|
||||
#include <nfc/protocols/st25tb/st25tb.h>
|
||||
|
||||
//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,
|
||||
};
|
||||
#define TAG "MyKey"
|
||||
|
||||
typedef enum {
|
||||
LockIdStatusNone,
|
||||
LockIdStatusActive,
|
||||
} LockIdStatus;
|
||||
const uint32_t blankBlock18 = 0x480FCD8F, blankBlock19 = 0x070082C0;
|
||||
|
||||
/* 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));
|
||||
static bool mykey_is_blank(const St25tbData* data) {
|
||||
return data->blocks[0x18] == blankBlock18 && data->blocks[0x19] == blankBlock19;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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));
|
||||
}
|
||||
|
||||
uint32_t get_xored_block(uint32_t block, uint32_t key) {
|
||||
return encode_decode_block(__bswap32(block) ^ key);
|
||||
}
|
||||
|
||||
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;
|
||||
const St25tbData* data = nfc_device_get_data(device, NfcProtocolSt25tb);
|
||||
|
||||
do {
|
||||
//Get data
|
||||
const St25tbData* data = nfc_device_get_data(device, NfcProtocolSt25tb);
|
||||
if(data->type != St25tbType04k && data->type != St25tbTypeX4k) {
|
||||
FURI_LOG_D(TAG, "bad type");
|
||||
return false;
|
||||
}
|
||||
|
||||
//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);
|
||||
for(int i = 0; i < 5; i++) {
|
||||
if(data->blocks[i] != 0xFFFFFFFF) {
|
||||
FURI_LOG_D(TAG, "bad otp block %d", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
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_data, "\nOp. count: %zu\n", (size_t)__bswap32(data->blocks[0x12] & 0xFFFFFF00));
|
||||
|
||||
parsed = true;
|
||||
} while(false);
|
||||
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)]);
|
||||
|
||||
return parsed;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
@ -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(
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,,
|
||||
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue
Block a user