mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-12 13:18:35 -07:00
Initial structure for UL-C dictionary attacks
This commit is contained in:
@@ -166,15 +166,26 @@ static void nfc_scene_read_on_enter_mf_ultralight(NfcApp* instance) {
|
|||||||
|
|
||||||
bool nfc_scene_read_on_event_mf_ultralight(NfcApp* instance, SceneManagerEvent event) {
|
bool nfc_scene_read_on_event_mf_ultralight(NfcApp* instance, SceneManagerEvent event) {
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventCardDetected) {
|
if(event.event == NfcCustomEventPollerSuccess) {
|
||||||
nfc_unlock_helper_card_detected_handler(instance);
|
notification_message(instance->notifications, &sequence_success);
|
||||||
} else if(event.event == NfcCustomEventPollerIncomplete) {
|
|
||||||
notification_message(instance->notifications, &sequence_semi_success);
|
|
||||||
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
return true;
|
||||||
|
} else if(event.event == NfcCustomEventPollerIncomplete) {
|
||||||
|
const MfUltralightData* data =
|
||||||
|
nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight);
|
||||||
|
if(data->type == MfUltralightTypeMfulC) {
|
||||||
|
// Start dict attack for MFUL C cards
|
||||||
|
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightCDictAttack);
|
||||||
|
} else {
|
||||||
|
notification_message(instance->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||||
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instance) {
|
static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instance) {
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
#include <lib/nfc/nfc.h>
|
#include <lib/nfc/nfc.h>
|
||||||
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a.h>
|
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a.h>
|
||||||
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h>
|
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h>
|
||||||
|
#include <lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h>
|
||||||
#include <lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h>
|
#include <lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h>
|
||||||
|
|
||||||
#include <nfc/nfc_poller.h>
|
#include <nfc/nfc_poller.h>
|
||||||
@@ -80,6 +81,10 @@
|
|||||||
#define NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict.nfc")
|
#define NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict.nfc")
|
||||||
#define NFC_APP_MF_CLASSIC_DICT_SYSTEM_NESTED_PATH \
|
#define NFC_APP_MF_CLASSIC_DICT_SYSTEM_NESTED_PATH \
|
||||||
(NFC_APP_FOLDER "/assets/mf_classic_dict_nested.nfc")
|
(NFC_APP_FOLDER "/assets/mf_classic_dict_nested.nfc")
|
||||||
|
#define NFC_APP_MF_ULTRALIGHT_C_DICT_USER_PATH \
|
||||||
|
(NFC_APP_FOLDER "/assets/mf_ultralight_c_dict_user.nfc")
|
||||||
|
#define NFC_APP_MF_ULTRALIGHT_C_DICT_SYSTEM_PATH \
|
||||||
|
(NFC_APP_FOLDER "/assets/mf_ultralight_c_dict.nfc")
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NfcRpcStateIdle,
|
NfcRpcStateIdle,
|
||||||
@@ -105,6 +110,14 @@ typedef struct {
|
|||||||
bool enhanced_dict;
|
bool enhanced_dict;
|
||||||
} NfcMfClassicDictAttackContext;
|
} NfcMfClassicDictAttackContext;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
KeysDict* dict;
|
||||||
|
bool auth_success;
|
||||||
|
bool is_card_present;
|
||||||
|
size_t dict_keys_total;
|
||||||
|
size_t dict_keys_current;
|
||||||
|
} NfcMfUltralightCDictContext;
|
||||||
|
|
||||||
struct NfcApp {
|
struct NfcApp {
|
||||||
DialogsApp* dialogs;
|
DialogsApp* dialogs;
|
||||||
Storage* storage;
|
Storage* storage;
|
||||||
@@ -143,6 +156,7 @@ struct NfcApp {
|
|||||||
MfUltralightAuth* mf_ul_auth;
|
MfUltralightAuth* mf_ul_auth;
|
||||||
SlixUnlock* slix_unlock;
|
SlixUnlock* slix_unlock;
|
||||||
NfcMfClassicDictAttackContext nfc_dict_context;
|
NfcMfClassicDictAttackContext nfc_dict_context;
|
||||||
|
NfcMfUltralightCDictContext mf_ultralight_c_dict_context;
|
||||||
Mfkey32Logger* mfkey32_logger;
|
Mfkey32Logger* mfkey32_logger;
|
||||||
MfUserDict* mf_user_dict;
|
MfUserDict* mf_user_dict;
|
||||||
MfClassicKeyCache* mfc_key_cache;
|
MfClassicKeyCache* mfc_key_cache;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ ADD_SCENE(nfc, retry_confirm, RetryConfirm)
|
|||||||
ADD_SCENE(nfc, exit_confirm, ExitConfirm)
|
ADD_SCENE(nfc, exit_confirm, ExitConfirm)
|
||||||
ADD_SCENE(nfc, save_confirm, SaveConfirm)
|
ADD_SCENE(nfc, save_confirm, SaveConfirm)
|
||||||
|
|
||||||
|
ADD_SCENE(nfc, mf_ultralight_c_dict_attack, MfUltralightCDictAttack)
|
||||||
ADD_SCENE(nfc, mf_ultralight_write, MfUltralightWrite)
|
ADD_SCENE(nfc, mf_ultralight_write, MfUltralightWrite)
|
||||||
ADD_SCENE(nfc, mf_ultralight_write_success, MfUltralightWriteSuccess)
|
ADD_SCENE(nfc, mf_ultralight_write_success, MfUltralightWriteSuccess)
|
||||||
ADD_SCENE(nfc, mf_ultralight_write_fail, MfUltralightWriteFail)
|
ADD_SCENE(nfc, mf_ultralight_write_fail, MfUltralightWriteFail)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
enum SubmenuIndex {
|
enum SubmenuIndex {
|
||||||
SubmenuIndexReadCardType,
|
SubmenuIndexReadCardType,
|
||||||
SubmenuIndexMfClassicKeys,
|
SubmenuIndexMfClassicKeys,
|
||||||
|
SubmenuIndexMfUlCKeys,
|
||||||
SubmenuIndexMfUltralightUnlock,
|
SubmenuIndexMfUltralightUnlock,
|
||||||
SubmenuIndexSlixUnlock,
|
SubmenuIndexSlixUnlock,
|
||||||
};
|
};
|
||||||
@@ -29,6 +30,12 @@ void nfc_scene_extra_actions_on_enter(void* context) {
|
|||||||
SubmenuIndexMfClassicKeys,
|
SubmenuIndexMfClassicKeys,
|
||||||
nfc_scene_extra_actions_submenu_callback,
|
nfc_scene_extra_actions_submenu_callback,
|
||||||
instance);
|
instance);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"MIFARE Ultralight C Keys",
|
||||||
|
SubmenuIndexMfUlCKeys,
|
||||||
|
nfc_scene_extra_actions_submenu_callback,
|
||||||
|
instance);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Unlock NTAG/Ultralight",
|
"Unlock NTAG/Ultralight",
|
||||||
@@ -54,6 +61,9 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(event.event == SubmenuIndexMfClassicKeys) {
|
if(event.event == SubmenuIndexMfClassicKeys) {
|
||||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeys);
|
scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeys);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexMfUlCKeys) {
|
||||||
|
// TODO: Add MFUL C key management scene here
|
||||||
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
|
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
|
||||||
mf_ultralight_auth_reset(instance->mf_ul_auth);
|
mf_ultralight_auth_reset(instance->mf_ul_auth);
|
||||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
#include "../nfc_app_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
#define TAG "NfcMfUlCDictAttack"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DictAttackStateUserDictInProgress,
|
||||||
|
DictAttackStateSystemDictInProgress,
|
||||||
|
};
|
||||||
|
|
||||||
|
NfcCommand nfc_mf_ultralight_c_dict_attack_worker_callback(NfcGenericEvent event, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
furi_assert(event.event_data);
|
||||||
|
furi_assert(event.protocol == NfcProtocolMfUltralight);
|
||||||
|
NfcCommand command = NfcCommandContinue;
|
||||||
|
NfcApp* instance = context;
|
||||||
|
MfUltralightPollerEvent* poller_event = event.event_data;
|
||||||
|
|
||||||
|
if(poller_event->type == MfUltralightPollerEventTypeRequestMode) {
|
||||||
|
poller_event->data->poller_mode = MfUltralightPollerModeDictAttack;
|
||||||
|
command = NfcCommandContinue;
|
||||||
|
} else if(poller_event->type == MfUltralightPollerEventTypeRequestKey) {
|
||||||
|
MfUltralightC3DesAuthKey key = {};
|
||||||
|
if(keys_dict_get_next_key(
|
||||||
|
instance->mf_ultralight_c_dict_context.dict,
|
||||||
|
key.data,
|
||||||
|
sizeof(MfUltralightC3DesAuthKey))) {
|
||||||
|
poller_event->data->key_request_data.key = key;
|
||||||
|
poller_event->data->key_request_data.key_provided = true;
|
||||||
|
instance->mf_ultralight_c_dict_context.dict_keys_current++;
|
||||||
|
|
||||||
|
if(instance->mf_ultralight_c_dict_context.dict_keys_current % 10 == 0) {
|
||||||
|
view_dispatcher_send_custom_event(
|
||||||
|
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
poller_event->data->key_request_data.key_provided = false;
|
||||||
|
}
|
||||||
|
} else if(poller_event->type == MfUltralightPollerEventTypeReadSuccess) {
|
||||||
|
nfc_device_set_data(
|
||||||
|
instance->nfc_device, NfcProtocolMfUltralight, nfc_poller_get_data(instance->poller));
|
||||||
|
view_dispatcher_send_custom_event(
|
||||||
|
instance->view_dispatcher, NfcCustomEventDictAttackComplete);
|
||||||
|
command = NfcCommandStop;
|
||||||
|
}
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_ultralight_c_dict_attack_dict_attack_result_callback(
|
||||||
|
DictAttackEvent event,
|
||||||
|
void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
NfcApp* instance = context;
|
||||||
|
if(event == DictAttackEventSkipPressed) {
|
||||||
|
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventDictAttackSkip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_ultralight_c_dict_attack_prepare_view(NfcApp* instance) {
|
||||||
|
uint32_t state =
|
||||||
|
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfUltralightCDictAttack);
|
||||||
|
if(state == DictAttackStateUserDictInProgress) {
|
||||||
|
do {
|
||||||
|
if(!keys_dict_check_presence(NFC_APP_MF_ULTRALIGHT_C_DICT_USER_PATH)) {
|
||||||
|
state = DictAttackStateSystemDictInProgress;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
instance->mf_ultralight_c_dict_context.dict = keys_dict_alloc(
|
||||||
|
NFC_APP_MF_ULTRALIGHT_C_DICT_USER_PATH,
|
||||||
|
KeysDictModeOpenAlways,
|
||||||
|
sizeof(MfUltralightC3DesAuthKey));
|
||||||
|
if(keys_dict_get_total_keys(instance->mf_ultralight_c_dict_context.dict) == 0) {
|
||||||
|
keys_dict_free(instance->mf_ultralight_c_dict_context.dict);
|
||||||
|
state = DictAttackStateSystemDictInProgress;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dict_attack_set_header(instance->dict_attack, "MFUL C User Dictionary");
|
||||||
|
} while(false);
|
||||||
|
}
|
||||||
|
if(state == DictAttackStateSystemDictInProgress) {
|
||||||
|
instance->mf_ultralight_c_dict_context.dict = keys_dict_alloc(
|
||||||
|
NFC_APP_MF_ULTRALIGHT_C_DICT_SYSTEM_PATH,
|
||||||
|
KeysDictModeOpenExisting,
|
||||||
|
sizeof(MfUltralightC3DesAuthKey));
|
||||||
|
dict_attack_set_header(instance->dict_attack, "MFUL C System Dictionary");
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->mf_ultralight_c_dict_context.dict_keys_total =
|
||||||
|
keys_dict_get_total_keys(instance->mf_ultralight_c_dict_context.dict);
|
||||||
|
dict_attack_set_total_dict_keys(
|
||||||
|
instance->dict_attack, instance->mf_ultralight_c_dict_context.dict_keys_total);
|
||||||
|
instance->mf_ultralight_c_dict_context.dict_keys_current = 0;
|
||||||
|
dict_attack_set_callback(
|
||||||
|
instance->dict_attack,
|
||||||
|
nfc_scene_mf_ultralight_c_dict_attack_dict_attack_result_callback,
|
||||||
|
instance);
|
||||||
|
scene_manager_set_scene_state(instance->scene_manager, NfcSceneMfUltralightCDictAttack, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_ultralight_c_dict_attack_on_enter(void* context) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
instance->scene_manager,
|
||||||
|
NfcSceneMfUltralightCDictAttack,
|
||||||
|
DictAttackStateUserDictInProgress);
|
||||||
|
nfc_scene_mf_ultralight_c_dict_attack_prepare_view(instance);
|
||||||
|
|
||||||
|
// Setup and start worker
|
||||||
|
instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfUltralight);
|
||||||
|
nfc_poller_start(instance->poller, nfc_mf_ultralight_c_dict_attack_worker_callback, instance);
|
||||||
|
|
||||||
|
nfc_blink_read_start(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_ul_c_dict_attack_update_view(NfcApp* instance) {
|
||||||
|
dict_attack_set_card_state(
|
||||||
|
instance->dict_attack, instance->mf_ultralight_c_dict_context.is_card_present);
|
||||||
|
dict_attack_set_current_dict_key(
|
||||||
|
instance->dict_attack, instance->mf_ultralight_c_dict_context.dict_keys_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_mf_ultralight_c_dict_attack_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
uint32_t state =
|
||||||
|
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfUltralightCDictAttack);
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcCustomEventDictAttackComplete) {
|
||||||
|
if(state == DictAttackStateUserDictInProgress) {
|
||||||
|
nfc_poller_stop(instance->poller);
|
||||||
|
nfc_poller_free(instance->poller);
|
||||||
|
keys_dict_free(instance->mf_ultralight_c_dict_context.dict);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
instance->scene_manager,
|
||||||
|
NfcSceneMfUltralightCDictAttack,
|
||||||
|
DictAttackStateSystemDictInProgress);
|
||||||
|
nfc_scene_mf_ultralight_c_dict_attack_prepare_view(instance);
|
||||||
|
instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfUltralight);
|
||||||
|
nfc_poller_start(
|
||||||
|
instance->poller, nfc_mf_ultralight_c_dict_attack_worker_callback, instance);
|
||||||
|
consumed = true;
|
||||||
|
} else {
|
||||||
|
notification_message(instance->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||||
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.event == NfcCustomEventDictAttackDataUpdate) {
|
||||||
|
dict_attack_set_current_dict_key(
|
||||||
|
instance->dict_attack, instance->mf_ultralight_c_dict_context.dict_keys_current);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventDictAttackSkip) {
|
||||||
|
if(instance->mf_ultralight_c_dict_context.is_card_present) {
|
||||||
|
if(state == DictAttackStateUserDictInProgress) {
|
||||||
|
nfc_poller_stop(instance->poller);
|
||||||
|
nfc_poller_free(instance->poller);
|
||||||
|
keys_dict_free(instance->mf_ultralight_c_dict_context.dict);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
instance->scene_manager,
|
||||||
|
NfcSceneMfUltralightCDictAttack,
|
||||||
|
DictAttackStateSystemDictInProgress);
|
||||||
|
nfc_scene_mf_ultralight_c_dict_attack_prepare_view(instance);
|
||||||
|
instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfUltralight);
|
||||||
|
nfc_poller_start(
|
||||||
|
instance->poller,
|
||||||
|
nfc_mf_ultralight_c_dict_attack_worker_callback,
|
||||||
|
instance);
|
||||||
|
} else {
|
||||||
|
nfc_poller_stop(instance->poller);
|
||||||
|
nfc_poller_free(instance->poller);
|
||||||
|
notification_message(instance->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||||
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
scene_manager_next_scene(instance->scene_manager, NfcSceneExitConfirm);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_ultralight_c_dict_attack_on_exit(void* context) {
|
||||||
|
NfcApp* instance = context;
|
||||||
|
nfc_poller_stop(instance->poller);
|
||||||
|
nfc_poller_free(instance->poller);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
instance->scene_manager,
|
||||||
|
NfcSceneMfUltralightCDictAttack,
|
||||||
|
DictAttackStateUserDictInProgress);
|
||||||
|
keys_dict_free(instance->mf_ultralight_c_dict_context.dict);
|
||||||
|
instance->mf_ultralight_c_dict_context.dict_keys_total = 0;
|
||||||
|
instance->mf_ultralight_c_dict_context.dict_keys_current = 0;
|
||||||
|
instance->mf_ultralight_c_dict_context.auth_success = false;
|
||||||
|
instance->mf_ultralight_c_dict_context.is_card_present = false;
|
||||||
|
nfc_blink_stop(instance);
|
||||||
|
}
|
||||||
@@ -181,6 +181,10 @@ MfUltralightPoller* mf_ultralight_poller_alloc(Iso14443_3aPoller* iso14443_3a_po
|
|||||||
instance->general_event.protocol = NfcProtocolMfUltralight;
|
instance->general_event.protocol = NfcProtocolMfUltralight;
|
||||||
instance->general_event.event_data = &instance->mfu_event;
|
instance->general_event.event_data = &instance->mfu_event;
|
||||||
instance->general_event.instance = instance;
|
instance->general_event.instance = instance;
|
||||||
|
|
||||||
|
instance->dict_attack_ctx.auth_success = false;
|
||||||
|
instance->dict_attack_ctx.is_card_present = false;
|
||||||
|
|
||||||
mbedtls_des3_init(&instance->des_context);
|
mbedtls_des3_init(&instance->des_context);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@@ -521,7 +525,7 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in
|
|||||||
} else {
|
} else {
|
||||||
if(instance->data->type == MfUltralightTypeMfulC &&
|
if(instance->data->type == MfUltralightTypeMfulC &&
|
||||||
!mf_ultralight_3des_key_valid(instance->data)) {
|
!mf_ultralight_3des_key_valid(instance->data)) {
|
||||||
instance->state = MfUltralightPollerStateCheckMfulCAuthStatus;
|
instance->state = MfUltralightPollerStateDictAttack;
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_D(TAG, "Read page %d failed", instance->pages_read);
|
FURI_LOG_D(TAG, "Read page %d failed", instance->pages_read);
|
||||||
if(instance->pages_read) {
|
if(instance->pages_read) {
|
||||||
@@ -730,6 +734,63 @@ static NfcCommand mf_ultralight_poller_handler_write_success(MfUltralightPoller*
|
|||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NfcCommand mf_ultralight_poller_handler_dict_attack(MfUltralightPoller* instance) {
|
||||||
|
NfcCommand command = NfcCommandContinue;
|
||||||
|
const MfUltralightData* tag_data = instance->data;
|
||||||
|
uint32_t features = mf_ultralight_get_feature_support_set(tag_data->type);
|
||||||
|
FURI_LOG_D(TAG, "Dict Attack");
|
||||||
|
do {
|
||||||
|
if(!mf_ultralight_support_feature(features, MfUltralightFeatureSupportAuthenticate)) {
|
||||||
|
instance->error = MfUltralightErrorProtocol;
|
||||||
|
instance->state = MfUltralightPollerStateReadFailed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->dict_attack_ctx.is_card_present = true;
|
||||||
|
instance->mfu_event.type = MfUltralightPollerEventTypeRequestKey;
|
||||||
|
command = instance->callback(instance->general_event, instance->context);
|
||||||
|
if(!instance->mfu_event.data->key_request_data.key_provided) {
|
||||||
|
instance->state = MfUltralightPollerStateReadSuccess;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Trying next 3DES key");
|
||||||
|
instance->error = MfUltralightErrorNone;
|
||||||
|
instance->auth_context.auth_success = false;
|
||||||
|
instance->auth_context.tdes_key = instance->mfu_event.data->key_request_data.key;
|
||||||
|
do {
|
||||||
|
uint8_t output[MF_ULTRALIGHT_C_AUTH_DATA_SIZE];
|
||||||
|
uint8_t RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0};
|
||||||
|
furi_hal_random_fill_buf(RndA, sizeof(RndA));
|
||||||
|
instance->error = mf_ultralight_poller_authenticate_start(instance, RndA, output);
|
||||||
|
if(instance->error != MfUltralightErrorNone) break;
|
||||||
|
|
||||||
|
uint8_t decoded_shifted_RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0};
|
||||||
|
const uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET;
|
||||||
|
instance->error = mf_ultralight_poller_authenticate_end(
|
||||||
|
instance, RndB, output, decoded_shifted_RndA);
|
||||||
|
if(instance->error != MfUltralightErrorNone) break;
|
||||||
|
|
||||||
|
mf_ultralight_3des_shift_data(RndA);
|
||||||
|
instance->auth_context.auth_success =
|
||||||
|
(memcmp(RndA, decoded_shifted_RndA, sizeof(decoded_shifted_RndA)) == 0);
|
||||||
|
if(instance->auth_context.auth_success) {
|
||||||
|
FURI_LOG_D(TAG, "Dict attack success");
|
||||||
|
instance->state = MfUltralightPollerStateReadPages;
|
||||||
|
instance->dict_attack_ctx.auth_success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
if(!instance->auth_context.auth_success) {
|
||||||
|
FURI_LOG_D(TAG, "Dict attack auth failed");
|
||||||
|
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
static const MfUltralightPollerReadHandler
|
static const MfUltralightPollerReadHandler
|
||||||
mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = {
|
mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = {
|
||||||
[MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle,
|
[MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle,
|
||||||
@@ -755,6 +816,7 @@ static const MfUltralightPollerReadHandler
|
|||||||
[MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages,
|
[MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages,
|
||||||
[MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail,
|
[MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail,
|
||||||
[MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success,
|
[MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success,
|
||||||
|
[MfUltralightPollerStateDictAttack] = mf_ultralight_poller_handler_dict_attack,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ typedef enum {
|
|||||||
MfUltralightPollerEventTypeCardLocked, /**< Presented card is locked by password, AUTH0 or lock bytes. */
|
MfUltralightPollerEventTypeCardLocked, /**< Presented card is locked by password, AUTH0 or lock bytes. */
|
||||||
MfUltralightPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */
|
MfUltralightPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */
|
||||||
MfUltralightPollerEventTypeWriteFail, /**< Poller failed to write card. */
|
MfUltralightPollerEventTypeWriteFail, /**< Poller failed to write card. */
|
||||||
|
MfUltralightPollerEventTypeRequestKey, /**< Poller requests key for dict attack. */
|
||||||
} MfUltralightPollerEventType;
|
} MfUltralightPollerEventType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +36,7 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
MfUltralightPollerModeRead, /**< Poller will only read card. It's a default mode. */
|
MfUltralightPollerModeRead, /**< Poller will only read card. It's a default mode. */
|
||||||
MfUltralightPollerModeWrite, /**< Poller will write already saved card to another presented card. */
|
MfUltralightPollerModeWrite, /**< Poller will write already saved card to another presented card. */
|
||||||
|
MfUltralightPollerModeDictAttack, /**< Poller will perform dictionary attack against card. */
|
||||||
} MfUltralightPollerMode;
|
} MfUltralightPollerMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,20 +44,29 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MfUltralightAuthPassword password; /**< Password to be used for authentication. */
|
MfUltralightAuthPassword password; /**< Password to be used for authentication. */
|
||||||
MfUltralightC3DesAuthKey tdes_key;
|
MfUltralightC3DesAuthKey tdes_key; /**< 3DES key to be used for authentication. */
|
||||||
MfUltralightAuthPack pack; /**< Pack received on successfull authentication. */
|
MfUltralightAuthPack pack; /**< Pack received on successful authentication. */
|
||||||
bool auth_success; /**< Set to true if authentication succeeded, false otherwise. */
|
bool auth_success; /**< Set to true if authentication succeeded, false otherwise. */
|
||||||
bool skip_auth; /**< Set to true if authentication should be skipped, false otherwise. */
|
bool skip_auth; /**< Set to true if authentication should be skipped, false otherwise. */
|
||||||
} MfUltralightPollerAuthContext;
|
} MfUltralightPollerAuthContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfUltralight poller key request data.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
MfUltralightC3DesAuthKey key; /**< Key to try. */
|
||||||
|
bool key_provided; /**< Set to true if key was provided, false to stop attack. */
|
||||||
|
} MfUltralightPollerKeyRequestData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief MfUltralight poller event data.
|
* @brief MfUltralight poller event data.
|
||||||
*/
|
*/
|
||||||
typedef union {
|
typedef union {
|
||||||
MfUltralightPollerAuthContext auth_context; /**< Authentication context. */
|
MfUltralightPollerAuthContext auth_context; /**< Authentication context. */
|
||||||
MfUltralightError error; /**< Error code indicating reading fail reason. */
|
MfUltralightError error; /**< Error code indicating reading fail reason. */
|
||||||
const MfUltralightData* write_data;
|
const MfUltralightData* write_data; /**< Data to be written to card. */
|
||||||
MfUltralightPollerMode poller_mode;
|
MfUltralightPollerMode poller_mode; /**< Mode to operate in. */
|
||||||
|
MfUltralightPollerKeyRequestData key_request_data; /**< Key request data. */
|
||||||
} MfUltralightPollerEventData;
|
} MfUltralightPollerEventData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,7 +75,7 @@ typedef union {
|
|||||||
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MfUltralightPollerEventType type; /**< Type of emmitted event. */
|
MfUltralightPollerEventType type; /**< Type of emitted event. */
|
||||||
MfUltralightPollerEventData* data; /**< Pointer to event specific data. */
|
MfUltralightPollerEventData* data; /**< Pointer to event specific data. */
|
||||||
} MfUltralightPollerEvent;
|
} MfUltralightPollerEvent;
|
||||||
|
|
||||||
|
|||||||
@@ -68,10 +68,17 @@ typedef enum {
|
|||||||
MfUltralightPollerStateWritePages,
|
MfUltralightPollerStateWritePages,
|
||||||
MfUltralightPollerStateWriteFail,
|
MfUltralightPollerStateWriteFail,
|
||||||
MfUltralightPollerStateWriteSuccess,
|
MfUltralightPollerStateWriteSuccess,
|
||||||
|
MfUltralightPollerStateDictAttack,
|
||||||
|
|
||||||
MfUltralightPollerStateNum,
|
MfUltralightPollerStateNum,
|
||||||
} MfUltralightPollerState;
|
} MfUltralightPollerState;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t sectors_total;
|
||||||
|
bool auth_success;
|
||||||
|
bool is_card_present;
|
||||||
|
} MfUltralightPollerDictAttackContext;
|
||||||
|
|
||||||
struct MfUltralightPoller {
|
struct MfUltralightPoller {
|
||||||
Iso14443_3aPoller* iso14443_3a_poller;
|
Iso14443_3aPoller* iso14443_3a_poller;
|
||||||
MfUltralightPollerState state;
|
MfUltralightPollerState state;
|
||||||
@@ -89,6 +96,7 @@ struct MfUltralightPoller {
|
|||||||
uint8_t tearing_flag_total;
|
uint8_t tearing_flag_total;
|
||||||
uint16_t current_page;
|
uint16_t current_page;
|
||||||
MfUltralightError error;
|
MfUltralightError error;
|
||||||
|
MfUltralightPollerDictAttackContext dict_attack_ctx;
|
||||||
mbedtls_des3_context des_context;
|
mbedtls_des3_context des_context;
|
||||||
|
|
||||||
NfcGenericEvent general_event;
|
NfcGenericEvent general_event;
|
||||||
|
|||||||
Reference in New Issue
Block a user