mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 12:42:30 +04:00
NFC: Ultralight C App Key Management, Dictionary Attack (#4271)
* Upstream Ultralight C dictionary attack (squashed) * linter: formatting * unit_tests: nfc: split nfc data to named var * Fix mf_ultralight_poller_sync_read_card * linter: suppressed warnings on TODOs --------- Co-authored-by: hedger <hedger@users.noreply.github.com> Co-authored-by: hedger <hedger@nanode.su>
This commit is contained in:
@@ -268,9 +268,9 @@ static void mf_ultralight_reader_test(const char* path) {
|
||||
nfc_listener_stop(mfu_listener);
|
||||
nfc_listener_free(mfu_listener);
|
||||
|
||||
mu_assert(
|
||||
mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)),
|
||||
"Data not matches");
|
||||
MfUltralightData* mfu_other_data =
|
||||
(MfUltralightData*)nfc_device_get_data(nfc_device, NfcProtocolMfUltralight);
|
||||
mu_assert(mf_ultralight_is_equal(mfu_data, mfu_other_data), "Data mismatch");
|
||||
|
||||
mf_ultralight_free(mfu_data);
|
||||
nfc_device_free(nfc_device);
|
||||
|
||||
@@ -15,6 +15,7 @@ enum {
|
||||
SubmenuIndexUnlockByReader,
|
||||
SubmenuIndexUnlockByPassword,
|
||||
SubmenuIndexWrite,
|
||||
SubmenuIndexDictAttack
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -150,7 +151,15 @@ static NfcCommand
|
||||
}
|
||||
if(!mf_ultralight_event->data->auth_context.skip_auth) {
|
||||
mf_ultralight_event->data->auth_context.password = instance->mf_ul_auth->password;
|
||||
mf_ultralight_event->data->auth_context.tdes_key = instance->mf_ul_auth->tdes_key;
|
||||
|
||||
// Only set tdes_key for Manual/Reader auth types, not for dictionary attacks
|
||||
if(instance->mf_ul_auth->type == MfUltralightAuthTypeManual ||
|
||||
instance->mf_ul_auth->type == MfUltralightAuthTypeReader) {
|
||||
mf_ultralight_event->data->key_request_data.key = instance->mf_ul_auth->tdes_key;
|
||||
mf_ultralight_event->data->key_request_data.key_provided = true;
|
||||
} else {
|
||||
mf_ultralight_event->data->key_request_data.key_provided = false;
|
||||
}
|
||||
}
|
||||
} else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthSuccess) {
|
||||
instance->mf_ul_auth->pack = mf_ultralight_event->data->auth_context.pack;
|
||||
@@ -166,16 +175,32 @@ static void nfc_scene_read_on_enter_mf_ultralight(NfcApp* instance) {
|
||||
|
||||
bool nfc_scene_read_on_event_mf_ultralight(NfcApp* instance, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventCardDetected) {
|
||||
nfc_unlock_helper_card_detected_handler(instance);
|
||||
if(event.event == NfcCustomEventPollerSuccess) {
|
||||
notification_message(instance->notifications, &sequence_success);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||
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 &&
|
||||
instance->mf_ul_auth->type == MfUltralightAuthTypeNone) {
|
||||
// Start dict attack for MFUL C cards only if no specific auth was attempted
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightCDictAttack);
|
||||
} else {
|
||||
if(data->pages_read == data->pages_total) {
|
||||
notification_message(instance->notifications, &sequence_success);
|
||||
} else {
|
||||
notification_message(instance->notifications, &sequence_semi_success);
|
||||
}
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instance) {
|
||||
Submenu* submenu = instance->submenu;
|
||||
@@ -190,6 +215,14 @@ static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instanc
|
||||
SubmenuIndexUnlock,
|
||||
nfc_protocol_support_common_submenu_callback,
|
||||
instance);
|
||||
if(data->type == MfUltralightTypeMfulC) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Unlock with Dictionary",
|
||||
SubmenuIndexDictAttack,
|
||||
nfc_protocol_support_common_submenu_callback,
|
||||
instance);
|
||||
}
|
||||
} else if(
|
||||
data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 ||
|
||||
data->type == MfUltralightTypeNTAG216 || data->type == MfUltralightTypeUL11 ||
|
||||
@@ -258,6 +291,12 @@ static bool nfc_scene_read_and_saved_menu_on_event_mf_ultralight(
|
||||
} else if(event.event == SubmenuIndexCommonEdit) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexDictAttack) {
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
instance->scene_manager, NfcSceneMfUltralightCDictAttack)) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightCDictAttack);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <lib/nfc/nfc.h>
|
||||
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a.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 <nfc/nfc_poller.h>
|
||||
@@ -64,7 +65,7 @@
|
||||
|
||||
#define NFC_NAME_SIZE 22
|
||||
#define NFC_TEXT_STORE_SIZE 128
|
||||
#define NFC_BYTE_INPUT_STORE_SIZE 10
|
||||
#define NFC_BYTE_INPUT_STORE_SIZE 16
|
||||
#define NFC_LOG_SIZE_MAX (1024)
|
||||
#define NFC_APP_FOLDER EXT_PATH("nfc")
|
||||
#define NFC_APP_EXTENSION ".nfc"
|
||||
@@ -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_NESTED_PATH \
|
||||
(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")
|
||||
|
||||
#define NFC_MFKEY32_APP_PATH (EXT_PATH("apps/NFC/mfkey.fap"))
|
||||
|
||||
@@ -107,6 +112,14 @@ typedef struct {
|
||||
bool enhanced_dict;
|
||||
} 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 {
|
||||
DialogsApp* dialogs;
|
||||
Storage* storage;
|
||||
@@ -145,6 +158,7 @@ struct NfcApp {
|
||||
MfUltralightAuth* mf_ul_auth;
|
||||
SlixUnlock* slix_unlock;
|
||||
NfcMfClassicDictAttackContext nfc_dict_context;
|
||||
NfcMfUltralightCDictContext mf_ultralight_c_dict_context;
|
||||
Mfkey32Logger* mfkey32_logger;
|
||||
MfUserDict* mf_user_dict;
|
||||
MfClassicKeyCache* mfc_key_cache;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# Sample Key (BREAKMEIFYOUCAN!)
|
||||
425245414B4D454946594F5543414E21
|
||||
# Hexadecimal-Reversed Sample Key
|
||||
12E4143455F495649454D4B414542524
|
||||
# Byte-Reversed Sample Key (!NACUOYFIEMKAERB)
|
||||
214E4143554F594649454D4B41455242
|
||||
# Semnox Key (IEMKAERB!NACUOY )
|
||||
49454D4B41455242214E4143554F5900
|
||||
# Modified Semnox Key (IEMKAERB!NACUOYF)
|
||||
49454D4B41455242214E4143554F5946
|
||||
|
||||
# Mix of Proxmark and ChameleonMiniLiveDebugger
|
||||
00000000000000000000000000000000
|
||||
000102030405060708090A0B0C0D0E0F
|
||||
01010101010101010101010101010101
|
||||
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||
00112233445566778899AABBCCDDEEFF
|
||||
47454D5850524553534F53414D504C45
|
||||
79702553797025537970255379702553
|
||||
4E617468616E2E4C6920546564647920
|
||||
43464F494D48504E4C4359454E528841
|
||||
6AC292FAA1315B4D858AB3A3D7D5933A
|
||||
404142434445464748494A4B4C4D4E4F
|
||||
2B7E151628AED2A6ABF7158809CF4F3C
|
||||
FBEED618357133667C85E08F7236A8DE
|
||||
F7DDAC306AE266CCF90BC11EE46D513B
|
||||
54686973206973206D79206B65792020
|
||||
A0A1A2A3A4A5A6A7A0A1A2A3A4A5A6A7
|
||||
B0B1B2B3B4B5B6B7B0B1B2B3B4B5B6B7
|
||||
B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF
|
||||
D3F7D3F7D3F7D3F7D3F7D3F7D3F7D3F7
|
||||
11111111111111111111111111111111
|
||||
22222222222222222222222222222222
|
||||
33333333333333333333333333333333
|
||||
44444444444444444444444444444444
|
||||
55555555555555555555555555555555
|
||||
66666666666666666666666666666666
|
||||
77777777777777777777777777777777
|
||||
88888888888888888888888888888888
|
||||
99999999999999999999999999999999
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
|
||||
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
|
||||
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
|
||||
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
|
||||
0102030405060708090A0B0C0D0E0F10
|
||||
00010203040506070809101112131415
|
||||
01020304050607080910111213141516
|
||||
16151413121110090807060504030201
|
||||
15141312111009080706050403020100
|
||||
0F0E0D0C0B0A09080706050403020100
|
||||
100F0E0D0C0B0A090807060504030201
|
||||
303132333435363738393A3B3C3D3E3F
|
||||
9CABF398358405AE2F0E2B3D31C99A8A
|
||||
605F5E5D5C5B5A59605F5E5D5C5B5A59
|
||||
@@ -25,6 +25,7 @@ ADD_SCENE(nfc, retry_confirm, RetryConfirm)
|
||||
ADD_SCENE(nfc, exit_confirm, ExitConfirm)
|
||||
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_success, MfUltralightWriteSuccess)
|
||||
ADD_SCENE(nfc, mf_ultralight_write_fail, MfUltralightWriteFail)
|
||||
@@ -57,6 +58,12 @@ ADD_SCENE(nfc, mf_classic_keys_delete, MfClassicKeysDelete)
|
||||
ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd)
|
||||
ADD_SCENE(nfc, mf_classic_keys_warn_duplicate, MfClassicKeysWarnDuplicate)
|
||||
|
||||
ADD_SCENE(nfc, mf_ultralight_c_keys, MfUltralightCKeys)
|
||||
ADD_SCENE(nfc, mf_ultralight_c_keys_list, MfUltralightCKeysList)
|
||||
ADD_SCENE(nfc, mf_ultralight_c_keys_delete, MfUltralightCKeysDelete)
|
||||
ADD_SCENE(nfc, mf_ultralight_c_keys_add, MfUltralightCKeysAdd)
|
||||
ADD_SCENE(nfc, mf_ultralight_c_keys_warn_duplicate, MfUltralightCKeysWarnDuplicate)
|
||||
|
||||
ADD_SCENE(nfc, set_type, SetType)
|
||||
ADD_SCENE(nfc, set_sak, SetSak)
|
||||
ADD_SCENE(nfc, set_atqa, SetAtqa)
|
||||
|
||||
@@ -28,6 +28,10 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicKeys);
|
||||
} else if(scene_manager_has_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfUltralightCKeys)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfUltralightCKeys);
|
||||
} else {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneFileSelect);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexReadCardType,
|
||||
SubmenuIndexMfClassicKeys,
|
||||
SubmenuIndexMfUltralightCKeys,
|
||||
SubmenuIndexMfUltralightUnlock,
|
||||
SubmenuIndexSlixUnlock,
|
||||
};
|
||||
@@ -29,6 +30,12 @@ void nfc_scene_extra_actions_on_enter(void* context) {
|
||||
SubmenuIndexMfClassicKeys,
|
||||
nfc_scene_extra_actions_submenu_callback,
|
||||
instance);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"MIFARE Ultralight C Keys",
|
||||
SubmenuIndexMfUltralightCKeys,
|
||||
nfc_scene_extra_actions_submenu_callback,
|
||||
instance);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Unlock NTAG/Ultralight",
|
||||
@@ -54,6 +61,9 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.event == SubmenuIndexMfClassicKeys) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeys);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexMfUltralightCKeys) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightCKeys);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
|
||||
mf_ultralight_auth_reset(instance->mf_ul_auth);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
#define NFC_SCENE_MF_CLASSIC_KEYS_MAX (100)
|
||||
|
||||
void nfc_scene_mf_classic_keys_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
NfcApp* instance = context;
|
||||
if(type == InputTypeShort) {
|
||||
|
||||
@@ -39,7 +39,7 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve
|
||||
instance->scene_manager, NfcSceneMfClassicKeysWarnDuplicate);
|
||||
} else if(keys_dict_add_key(dict, key.data, sizeof(MfClassicKey))) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess);
|
||||
dolphin_deed(DolphinDeedNfcMfcAdd);
|
||||
dolphin_deed(DolphinDeedNfcKeyAdd);
|
||||
} else {
|
||||
scene_manager_previous_scene(instance->scene_manager);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
#include "../nfc_app_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define TAG "NfcMfUlCDictAttack"
|
||||
|
||||
// TODO: Support card_detected properly -nofl
|
||||
|
||||
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));
|
||||
// Check if this is a successful authentication by looking at the poller's auth context
|
||||
const MfUltralightData* data = nfc_poller_get_data(instance->poller);
|
||||
|
||||
// Update page information
|
||||
dict_attack_set_pages_read(instance->dict_attack, data->pages_read);
|
||||
dict_attack_set_pages_total(instance->dict_attack, data->pages_total);
|
||||
|
||||
if(data->pages_read == data->pages_total) {
|
||||
// Full read indicates successful authentication in dict attack mode
|
||||
instance->mf_ultralight_c_dict_context.auth_success = true;
|
||||
dict_attack_set_key_found(instance->dict_attack, true);
|
||||
}
|
||||
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);
|
||||
|
||||
// Set attack type to Ultralight C
|
||||
dict_attack_set_type(instance->dict_attack, DictAttackTypeMfUltralightC);
|
||||
|
||||
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_current_dict_key(
|
||||
instance->dict_attack, instance->mf_ultralight_c_dict_context.dict_keys_current);
|
||||
|
||||
// Set initial Ultralight C specific values
|
||||
dict_attack_set_key_found(instance->dict_attack, false);
|
||||
dict_attack_set_pages_total(instance->dict_attack, 48); // Ultralight C page count
|
||||
dict_attack_set_pages_read(instance->dict_attack, 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);
|
||||
|
||||
dict_attack_set_card_state(instance->dict_attack, true);
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewDictAttack);
|
||||
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) {
|
||||
if(instance->mf_ultralight_c_dict_context.auth_success) {
|
||||
notification_message(instance->notifications, &sequence_success);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||
consumed = true;
|
||||
} else {
|
||||
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 {
|
||||
// Could check if card is fully read here like MFC dict attack, but found key means fully read
|
||||
if(instance->mf_ultralight_c_dict_context.auth_success) {
|
||||
notification_message(instance->notifications, &sequence_success);
|
||||
} else {
|
||||
notification_message(instance->notifications, &sequence_semi_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(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 {
|
||||
notification_message(instance->notifications, &sequence_semi_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);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
NfcApp* instance = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
// Load flipper dict keys total
|
||||
uint32_t flipper_dict_keys_total = 0;
|
||||
KeysDict* dict = keys_dict_alloc(
|
||||
NFC_APP_MF_ULTRALIGHT_C_DICT_SYSTEM_PATH,
|
||||
KeysDictModeOpenExisting,
|
||||
sizeof(MfUltralightC3DesAuthKey));
|
||||
flipper_dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
keys_dict_free(dict);
|
||||
|
||||
// Load user dict keys total
|
||||
uint32_t user_dict_keys_total = 0;
|
||||
dict = keys_dict_alloc(
|
||||
NFC_APP_MF_ULTRALIGHT_C_DICT_USER_PATH,
|
||||
KeysDictModeOpenAlways,
|
||||
sizeof(MfUltralightC3DesAuthKey));
|
||||
user_dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
keys_dict_free(dict);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
widget_add_string_element(
|
||||
instance->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MIFARE Ultralight C Keys");
|
||||
furi_string_printf(temp_str, "System dict: %lu", flipper_dict_keys_total);
|
||||
widget_add_string_element(
|
||||
instance->widget,
|
||||
0,
|
||||
20,
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
furi_string_get_cstr(temp_str));
|
||||
furi_string_printf(temp_str, "User dict: %lu", user_dict_keys_total);
|
||||
widget_add_string_element(
|
||||
instance->widget,
|
||||
0,
|
||||
32,
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
furi_string_get_cstr(temp_str));
|
||||
widget_add_icon_element(instance->widget, 87, 13, &I_Keychain_39x36);
|
||||
widget_add_button_element(
|
||||
instance->widget,
|
||||
GuiButtonTypeCenter,
|
||||
"Add",
|
||||
nfc_scene_mf_ultralight_c_keys_widget_callback,
|
||||
instance);
|
||||
if(user_dict_keys_total > 0) {
|
||||
widget_add_button_element(
|
||||
instance->widget,
|
||||
GuiButtonTypeRight,
|
||||
"List",
|
||||
nfc_scene_mf_ultralight_c_keys_widget_callback,
|
||||
instance);
|
||||
}
|
||||
furi_string_free(temp_str);
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_ultralight_c_keys_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeCenter) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightCKeysAdd);
|
||||
consumed = true;
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightCKeysList);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
widget_reset(instance->widget);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_add_byte_input_callback(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_add_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = instance->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter the key in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
nfc_scene_mf_ultralight_c_keys_add_byte_input_callback,
|
||||
NULL,
|
||||
instance,
|
||||
instance->byte_input_store,
|
||||
sizeof(MfUltralightC3DesAuthKey));
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewByteInput);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_ultralight_c_keys_add_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventByteInputDone) {
|
||||
// Add key to dict
|
||||
KeysDict* dict = keys_dict_alloc(
|
||||
NFC_APP_MF_ULTRALIGHT_C_DICT_USER_PATH,
|
||||
KeysDictModeOpenAlways,
|
||||
sizeof(MfUltralightC3DesAuthKey));
|
||||
|
||||
MfUltralightC3DesAuthKey key = {};
|
||||
memcpy(key.data, instance->byte_input_store, sizeof(MfUltralightC3DesAuthKey));
|
||||
if(keys_dict_is_key_present(dict, key.data, sizeof(MfUltralightC3DesAuthKey))) {
|
||||
scene_manager_next_scene(
|
||||
instance->scene_manager, NfcSceneMfUltralightCKeysWarnDuplicate);
|
||||
} else if(keys_dict_add_key(dict, key.data, sizeof(MfUltralightC3DesAuthKey))) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess);
|
||||
dolphin_deed(DolphinDeedNfcKeyAdd);
|
||||
} else {
|
||||
scene_manager_previous_scene(instance->scene_manager);
|
||||
}
|
||||
|
||||
keys_dict_free(dict);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_add_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(instance->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(instance->byte_input, "");
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_delete_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
NfcApp* instance = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_delete_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
uint32_t key_index =
|
||||
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfUltralightCKeysDelete);
|
||||
FuriString* key_str = furi_string_alloc();
|
||||
|
||||
widget_add_string_element(
|
||||
instance->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Delete this key?");
|
||||
widget_add_button_element(
|
||||
instance->widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Cancel",
|
||||
nfc_scene_mf_ultralight_c_keys_delete_widget_callback,
|
||||
instance);
|
||||
widget_add_button_element(
|
||||
instance->widget,
|
||||
GuiButtonTypeRight,
|
||||
"Delete",
|
||||
nfc_scene_mf_ultralight_c_keys_delete_widget_callback,
|
||||
instance);
|
||||
|
||||
KeysDict* mf_ultralight_c_user_dict = keys_dict_alloc(
|
||||
NFC_APP_MF_ULTRALIGHT_C_DICT_USER_PATH,
|
||||
KeysDictModeOpenAlways,
|
||||
sizeof(MfUltralightC3DesAuthKey));
|
||||
size_t dict_keys_num = keys_dict_get_total_keys(mf_ultralight_c_user_dict);
|
||||
furi_assert(key_index < dict_keys_num);
|
||||
MfUltralightC3DesAuthKey stack_key;
|
||||
for(size_t i = 0; i < (key_index + 1); i++) {
|
||||
bool key_loaded = keys_dict_get_next_key(
|
||||
mf_ultralight_c_user_dict, stack_key.data, sizeof(MfUltralightC3DesAuthKey));
|
||||
furi_assert(key_loaded);
|
||||
}
|
||||
furi_string_reset(key_str);
|
||||
for(size_t i = 0; i < sizeof(MfUltralightC3DesAuthKey); i++) {
|
||||
furi_string_cat_printf(key_str, "%02X", stack_key.data[i]);
|
||||
}
|
||||
|
||||
widget_add_string_element(
|
||||
instance->widget,
|
||||
64,
|
||||
32,
|
||||
AlignCenter,
|
||||
AlignCenter,
|
||||
FontSecondary,
|
||||
furi_string_get_cstr(key_str));
|
||||
|
||||
keys_dict_free(mf_ultralight_c_user_dict);
|
||||
furi_string_free(key_str);
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_ultralight_c_keys_delete_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeRight) {
|
||||
uint32_t key_index = scene_manager_get_scene_state(
|
||||
instance->scene_manager, NfcSceneMfUltralightCKeysDelete);
|
||||
KeysDict* mf_ultralight_c_user_dict = keys_dict_alloc(
|
||||
NFC_APP_MF_ULTRALIGHT_C_DICT_USER_PATH,
|
||||
KeysDictModeOpenAlways,
|
||||
sizeof(MfUltralightC3DesAuthKey));
|
||||
size_t dict_keys_num = keys_dict_get_total_keys(mf_ultralight_c_user_dict);
|
||||
furi_assert(key_index < dict_keys_num);
|
||||
MfUltralightC3DesAuthKey stack_key;
|
||||
for(size_t i = 0; i < (key_index + 1); i++) {
|
||||
bool key_loaded = keys_dict_get_next_key(
|
||||
mf_ultralight_c_user_dict, stack_key.data, sizeof(MfUltralightC3DesAuthKey));
|
||||
furi_assert(key_loaded);
|
||||
}
|
||||
bool key_delete_success = keys_dict_delete_key(
|
||||
mf_ultralight_c_user_dict, stack_key.data, sizeof(MfUltralightC3DesAuthKey));
|
||||
keys_dict_free(mf_ultralight_c_user_dict);
|
||||
if(key_delete_success) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneDeleteSuccess);
|
||||
} else {
|
||||
scene_manager_previous_scene(instance->scene_manager);
|
||||
}
|
||||
} else if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_previous_scene(instance->scene_manager);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_delete_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
widget_reset(instance->widget);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
#define NFC_SCENE_MF_ULTRALIGHT_C_KEYS_LIST_MAX (100)
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_list_submenu_callback(void* context, uint32_t index) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_list_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
KeysDict* mf_ultralight_c_user_dict = keys_dict_alloc(
|
||||
NFC_APP_MF_ULTRALIGHT_C_DICT_USER_PATH,
|
||||
KeysDictModeOpenAlways,
|
||||
sizeof(MfUltralightC3DesAuthKey));
|
||||
|
||||
submenu_set_header(instance->submenu, "Select key to delete:");
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
|
||||
size_t dict_keys_num = keys_dict_get_total_keys(mf_ultralight_c_user_dict);
|
||||
size_t keys_num = MIN((size_t)NFC_SCENE_MF_ULTRALIGHT_C_KEYS_LIST_MAX, dict_keys_num);
|
||||
MfUltralightC3DesAuthKey stack_key;
|
||||
|
||||
if(keys_num > 0) {
|
||||
for(size_t i = 0; i < keys_num; i++) {
|
||||
bool key_loaded = keys_dict_get_next_key(
|
||||
mf_ultralight_c_user_dict, stack_key.data, sizeof(MfUltralightC3DesAuthKey));
|
||||
furi_assert(key_loaded);
|
||||
furi_string_reset(temp_str);
|
||||
for(size_t i = 0; i < sizeof(MfUltralightC3DesAuthKey); i++) {
|
||||
furi_string_cat_printf(temp_str, "%02X", stack_key.data[i]);
|
||||
}
|
||||
submenu_add_item(
|
||||
instance->submenu,
|
||||
furi_string_get_cstr(temp_str),
|
||||
i,
|
||||
nfc_scene_mf_ultralight_c_keys_list_submenu_callback,
|
||||
instance);
|
||||
}
|
||||
}
|
||||
keys_dict_free(mf_ultralight_c_user_dict);
|
||||
furi_string_free(temp_str);
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_ultralight_c_keys_list_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
bool consumed = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager, NfcSceneMfUltralightCKeysDelete, event.event);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightCKeysDelete);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_list_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
submenu_reset(instance->submenu);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_warn_duplicate_popup_callback(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventViewExit);
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_warn_duplicate_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
// Setup view
|
||||
Popup* popup = instance->popup;
|
||||
popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42);
|
||||
popup_set_header(popup, "Key Already Exists!", 64, 3, AlignCenter, AlignTop);
|
||||
popup_set_text(
|
||||
popup,
|
||||
"Please enter a\n"
|
||||
"different key.",
|
||||
4,
|
||||
24,
|
||||
AlignLeft,
|
||||
AlignTop);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_set_context(popup, instance);
|
||||
popup_set_callback(popup, nfc_scene_mf_ultralight_c_keys_warn_duplicate_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_ultralight_c_keys_warn_duplicate_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
instance->scene_manager, NfcSceneMfUltralightCKeysAdd);
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_ultralight_c_keys_warn_duplicate_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
popup_reset(instance->popup);
|
||||
}
|
||||
@@ -28,6 +28,10 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicKeys);
|
||||
} else if(scene_manager_has_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfUltralightCKeys)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfUltralightCKeys);
|
||||
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSaveConfirm)) {
|
||||
NfcSceneSaveConfirmState scene_state =
|
||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSaveConfirm);
|
||||
|
||||
@@ -13,12 +13,13 @@ struct DictAttack {
|
||||
typedef struct {
|
||||
FuriString* header;
|
||||
bool card_detected;
|
||||
DictAttackType attack_type;
|
||||
|
||||
// MIFARE Classic specific
|
||||
uint8_t sectors_total;
|
||||
uint8_t sectors_read;
|
||||
uint8_t current_sector;
|
||||
uint8_t keys_found;
|
||||
size_t dict_keys_total;
|
||||
size_t dict_keys_current;
|
||||
bool is_key_attack;
|
||||
uint8_t key_attack_current_sector;
|
||||
MfClassicNestedPhase nested_phase;
|
||||
@@ -26,17 +27,18 @@ typedef struct {
|
||||
MfClassicBackdoor backdoor;
|
||||
uint16_t nested_target_key;
|
||||
uint16_t msb_count;
|
||||
|
||||
// Ultralight C specific
|
||||
uint8_t pages_total;
|
||||
uint8_t pages_read;
|
||||
bool key_found;
|
||||
|
||||
// Common
|
||||
size_t dict_keys_total;
|
||||
size_t dict_keys_current;
|
||||
} DictAttackViewModel;
|
||||
|
||||
static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
DictAttackViewModel* m = model;
|
||||
if(!m->card_detected) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly.");
|
||||
} else {
|
||||
static void dict_attack_draw_mf_classic(Canvas* canvas, DictAttackViewModel* m) {
|
||||
char draw_str[32] = {};
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
@@ -72,8 +74,7 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
}
|
||||
}
|
||||
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(m->header));
|
||||
canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(m->header));
|
||||
if(m->nested_phase == MfClassicNestedPhaseCollectNtEnc) {
|
||||
uint8_t nonce_sector =
|
||||
m->nested_target_key / (m->prng_type == MfClassicPrngTypeWeak ? 4 : 2);
|
||||
@@ -122,11 +123,7 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
snprintf(draw_str, sizeof(draw_str), "%d/%zu", 1, m->dict_keys_total);
|
||||
} else {
|
||||
snprintf(
|
||||
draw_str,
|
||||
sizeof(draw_str),
|
||||
"%zu/%zu",
|
||||
m->dict_keys_current,
|
||||
m->dict_keys_total);
|
||||
draw_str, sizeof(draw_str), "%zu/%zu", m->dict_keys_current, m->dict_keys_total);
|
||||
}
|
||||
}
|
||||
if(dict_progress > 1.0f) {
|
||||
@@ -141,10 +138,54 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
m->keys_found,
|
||||
m->sectors_total * NFC_CLASSIC_KEYS_PER_SECTOR);
|
||||
canvas_draw_str_aligned(canvas, 0, 33, AlignLeft, AlignTop, draw_str);
|
||||
snprintf(
|
||||
draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total);
|
||||
snprintf(draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total);
|
||||
canvas_draw_str_aligned(canvas, 0, 43, AlignLeft, AlignTop, draw_str);
|
||||
}
|
||||
|
||||
static void dict_attack_draw_mf_ultralight_c(Canvas* canvas, DictAttackViewModel* m) {
|
||||
char draw_str[32] = {};
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(m->header));
|
||||
|
||||
snprintf(draw_str, sizeof(draw_str), "Trying keys");
|
||||
canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str);
|
||||
|
||||
float dict_progress =
|
||||
m->dict_keys_total == 0 ? 0 : (float)(m->dict_keys_current) / (float)(m->dict_keys_total);
|
||||
if(m->dict_keys_current == 0) {
|
||||
snprintf(draw_str, sizeof(draw_str), "%d/%zu", 1, m->dict_keys_total);
|
||||
} else {
|
||||
snprintf(draw_str, sizeof(draw_str), "%zu/%zu", m->dict_keys_current, m->dict_keys_total);
|
||||
}
|
||||
if(dict_progress > 1.0f) {
|
||||
dict_progress = 1.0f;
|
||||
}
|
||||
elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(draw_str, sizeof(draw_str), "Key found: %s", m->key_found ? "Yes" : "No");
|
||||
canvas_draw_str_aligned(canvas, 0, 33, AlignLeft, AlignTop, draw_str);
|
||||
|
||||
snprintf(draw_str, sizeof(draw_str), "Pages read: %d/%d", m->pages_read, m->pages_total);
|
||||
canvas_draw_str_aligned(canvas, 0, 43, AlignLeft, AlignTop, draw_str);
|
||||
}
|
||||
|
||||
static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
DictAttackViewModel* m = model;
|
||||
if(!m->card_detected) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly.");
|
||||
} else {
|
||||
if(m->attack_type == DictAttackTypeMfClassic) {
|
||||
dict_attack_draw_mf_classic(canvas, m);
|
||||
} else if(m->attack_type == DictAttackTypeMfUltralightC) {
|
||||
dict_attack_draw_mf_ultralight_c(canvas, m);
|
||||
}
|
||||
}
|
||||
elements_button_center(canvas, "Skip");
|
||||
}
|
||||
|
||||
@@ -195,18 +236,28 @@ void dict_attack_reset(DictAttack* instance) {
|
||||
instance->view,
|
||||
DictAttackViewModel * model,
|
||||
{
|
||||
model->attack_type = DictAttackTypeMfClassic;
|
||||
|
||||
// MIFARE Classic fields
|
||||
model->sectors_total = 0;
|
||||
model->sectors_read = 0;
|
||||
model->current_sector = 0;
|
||||
model->keys_found = 0;
|
||||
model->dict_keys_total = 0;
|
||||
model->dict_keys_current = 0;
|
||||
model->is_key_attack = false;
|
||||
model->nested_phase = MfClassicNestedPhaseNone;
|
||||
model->prng_type = MfClassicPrngTypeUnknown;
|
||||
model->backdoor = MfClassicBackdoorUnknown;
|
||||
model->nested_target_key = 0;
|
||||
model->msb_count = 0;
|
||||
|
||||
// Ultralight C fields
|
||||
model->pages_total = 0;
|
||||
model->pages_read = 0;
|
||||
model->key_found = false;
|
||||
|
||||
// Common fields
|
||||
model->dict_keys_total = 0;
|
||||
model->dict_keys_current = 0;
|
||||
furi_string_reset(model->header);
|
||||
},
|
||||
false);
|
||||
@@ -355,3 +406,31 @@ void dict_attack_set_msb_count(DictAttack* instance, uint16_t msb_count) {
|
||||
with_view_model(
|
||||
instance->view, DictAttackViewModel * model, { model->msb_count = msb_count; }, true);
|
||||
}
|
||||
|
||||
void dict_attack_set_type(DictAttack* instance, DictAttackType type) {
|
||||
furi_assert(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view, DictAttackViewModel * model, { model->attack_type = type; }, true);
|
||||
}
|
||||
|
||||
void dict_attack_set_pages_total(DictAttack* instance, uint8_t pages_total) {
|
||||
furi_assert(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view, DictAttackViewModel * model, { model->pages_total = pages_total; }, true);
|
||||
}
|
||||
|
||||
void dict_attack_set_pages_read(DictAttack* instance, uint8_t pages_read) {
|
||||
furi_assert(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view, DictAttackViewModel * model, { model->pages_read = pages_read; }, true);
|
||||
}
|
||||
|
||||
void dict_attack_set_key_found(DictAttack* instance, bool key_found) {
|
||||
furi_assert(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view, DictAttackViewModel * model, { model->key_found = key_found; }, true);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
DictAttackTypeMfClassic,
|
||||
DictAttackTypeMfUltralightC,
|
||||
} DictAttackType;
|
||||
|
||||
typedef struct DictAttack DictAttack;
|
||||
|
||||
typedef enum {
|
||||
@@ -56,6 +61,14 @@ void dict_attack_set_nested_target_key(DictAttack* instance, uint16_t target_key
|
||||
|
||||
void dict_attack_set_msb_count(DictAttack* instance, uint16_t msb_count);
|
||||
|
||||
void dict_attack_set_type(DictAttack* instance, DictAttackType type);
|
||||
|
||||
void dict_attack_set_pages_total(DictAttack* instance, uint8_t pages_total);
|
||||
|
||||
void dict_attack_set_pages_read(DictAttack* instance, uint8_t pages_read);
|
||||
|
||||
void dict_attack_set_key_found(DictAttack* instance, bool key_found);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,7 @@ static const DolphinDeedWeight dolphin_deed_weights[] = {
|
||||
{3, DolphinAppNfc}, // DolphinDeedNfcSave
|
||||
{1, DolphinAppNfc}, // DolphinDeedNfcDetectReader
|
||||
{2, DolphinAppNfc}, // DolphinDeedNfcEmulate
|
||||
{2, DolphinAppNfc}, // DolphinDeedNfcMfcAdd
|
||||
{2, DolphinAppNfc}, // DolphinDeedNfcKeyAdd
|
||||
{1, DolphinAppNfc}, // DolphinDeedNfcAddSave
|
||||
{1, DolphinAppNfc}, // DolphinDeedNfcAddEmulate
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ typedef enum {
|
||||
DolphinDeedNfcSave,
|
||||
DolphinDeedNfcDetectReader,
|
||||
DolphinDeedNfcEmulate,
|
||||
DolphinDeedNfcMfcAdd,
|
||||
DolphinDeedNfcKeyAdd,
|
||||
DolphinDeedNfcAddSave,
|
||||
DolphinDeedNfcAddEmulate,
|
||||
|
||||
|
||||
@@ -303,6 +303,26 @@ None, there are no versions yet.
|
||||
|
||||
This file contains a list of Mifare Classic keys. Each key is represented as a hex string. Lines starting with '#' are ignored as comments. Blank lines are ignored as well.
|
||||
|
||||
## Mifare Ultralight C Dictionary
|
||||
|
||||
### Example
|
||||
|
||||
# Hexadecimal-Reversed Sample Key
|
||||
12E4143455F495649454D4B414542524
|
||||
# Byte-Reversed Sample Key (!NACUOYFIEMKAERB)
|
||||
214E4143554F594649454D4B41455242
|
||||
# Sample Key (BREAKMEIFYOUCAN!)
|
||||
425245414B4D454946594F5543414E21
|
||||
# Semnox Key (IEMKAERB!NACUOY )
|
||||
49454D4B41455242214E4143554F5900
|
||||
# Modified Semnox Key (IEMKAERB!NACUOYF)
|
||||
49454D4B41455242214E4143554F5946
|
||||
...
|
||||
|
||||
### Description
|
||||
|
||||
This file contains a list of Mifare Ultralight C keys. Each key is represented as a hex string. Lines starting with '#' are ignored as comments. Blank lines are ignored as well.
|
||||
|
||||
## EMV resources
|
||||
|
||||
### Example
|
||||
|
||||
@@ -251,7 +251,7 @@ static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller*
|
||||
instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version);
|
||||
instance->state = MfUltralightPollerStateGetFeatureSet;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Didn't response. Check Ultralight C");
|
||||
FURI_LOG_D(TAG, "Didn't respond. Check Ultralight C");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->state = MfUltralightPollerStateDetectMfulC;
|
||||
}
|
||||
@@ -266,7 +266,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPo
|
||||
instance->data->type = MfUltralightTypeMfulC;
|
||||
instance->state = MfUltralightPollerStateGetFeatureSet;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Didn't response. Check NTAG 203");
|
||||
FURI_LOG_D(TAG, "Didn't respond. Check NTAG 203");
|
||||
instance->state = MfUltralightPollerStateDetectNtag203;
|
||||
}
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
@@ -452,7 +452,48 @@ static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPol
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
if(!instance->mfu_event.data->auth_context.skip_auth) {
|
||||
FURI_LOG_D(TAG, "Trying to authenticate with 3des key");
|
||||
// Only use the key if it was actually provided
|
||||
if(instance->mfu_event.data->key_request_data.key_provided) {
|
||||
instance->auth_context.tdes_key = instance->mfu_event.data->key_request_data.key;
|
||||
} else if(instance->mode == MfUltralightPollerModeDictAttack) {
|
||||
// TODO: -nofl Can logic be rearranged to request this key
|
||||
// before reaching mf_ultralight_poller_handler_auth_ultralight_c in poller?
|
||||
FURI_LOG_D(TAG, "No initial key provided, requesting key from dictionary");
|
||||
// Trigger dictionary key request
|
||||
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 = MfUltralightPollerStateReadPages;
|
||||
return command;
|
||||
} else {
|
||||
instance->auth_context.tdes_key =
|
||||
instance->mfu_event.data->key_request_data.key;
|
||||
}
|
||||
} else {
|
||||
// Fallback: use key from auth context (for sync poller compatibility)
|
||||
instance->auth_context.tdes_key = instance->mfu_event.data->auth_context.tdes_key;
|
||||
}
|
||||
instance->auth_context.auth_success = false;
|
||||
// For debugging
|
||||
FURI_LOG_D(
|
||||
"TAG",
|
||||
"Key data: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||
instance->auth_context.tdes_key.data[0],
|
||||
instance->auth_context.tdes_key.data[1],
|
||||
instance->auth_context.tdes_key.data[2],
|
||||
instance->auth_context.tdes_key.data[3],
|
||||
instance->auth_context.tdes_key.data[4],
|
||||
instance->auth_context.tdes_key.data[5],
|
||||
instance->auth_context.tdes_key.data[6],
|
||||
instance->auth_context.tdes_key.data[7],
|
||||
instance->auth_context.tdes_key.data[8],
|
||||
instance->auth_context.tdes_key.data[9],
|
||||
instance->auth_context.tdes_key.data[10],
|
||||
instance->auth_context.tdes_key.data[11],
|
||||
instance->auth_context.tdes_key.data[12],
|
||||
instance->auth_context.tdes_key.data[13],
|
||||
instance->auth_context.tdes_key.data[14],
|
||||
instance->auth_context.tdes_key.data[15]);
|
||||
do {
|
||||
uint8_t output[MF_ULTRALIGHT_C_AUTH_DATA_SIZE];
|
||||
uint8_t RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0};
|
||||
@@ -469,20 +510,40 @@ static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPol
|
||||
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, "Auth success");
|
||||
FURI_LOG_E(TAG, "Auth success");
|
||||
if(instance->mode == MfUltralightPollerModeDictAttack) {
|
||||
memcpy(
|
||||
&instance->data->page[44],
|
||||
instance->auth_context.tdes_key.data,
|
||||
MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE);
|
||||
// Continue to read pages after successful authentication
|
||||
instance->state = MfUltralightPollerStateReadPages;
|
||||
}
|
||||
}
|
||||
} while(false);
|
||||
|
||||
if(instance->error != MfUltralightErrorNone || !instance->auth_context.auth_success) {
|
||||
FURI_LOG_D(TAG, "Auth failed");
|
||||
FURI_LOG_E(TAG, "Auth failed");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(instance->mode == MfUltralightPollerModeDictAttack) {
|
||||
// Not needed? We already do a callback earlier?
|
||||
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 = MfUltralightPollerStateReadPages;
|
||||
|
||||
} else {
|
||||
instance->auth_context.tdes_key =
|
||||
instance->mfu_event.data->key_request_data.key;
|
||||
instance->state = MfUltralightPollerStateAuthMfulC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Regression review
|
||||
if(instance->mode != MfUltralightPollerModeDictAttack) {
|
||||
instance->state = MfUltralightPollerStateReadPages;
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
@@ -505,13 +566,17 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in
|
||||
instance->error = mf_ultralight_poller_read_page(instance, start_page, &data);
|
||||
}
|
||||
|
||||
// Regression review
|
||||
const uint8_t read_cnt = instance->data->type == MfUltralightTypeMfulC ? 1 : 4;
|
||||
if(instance->error == MfUltralightErrorNone) {
|
||||
if(start_page < instance->pages_total) {
|
||||
FURI_LOG_D(TAG, "Read page %d success", start_page);
|
||||
instance->data->page[start_page] = data.page[0];
|
||||
for(size_t i = 0; i < read_cnt; i++) {
|
||||
if(start_page + i < instance->pages_total) {
|
||||
FURI_LOG_D(TAG, "Read page %d success", start_page + i);
|
||||
instance->data->page[start_page + i] = data.page[i];
|
||||
instance->pages_read++;
|
||||
instance->data->pages_read = instance->pages_read;
|
||||
}
|
||||
}
|
||||
|
||||
if(instance->pages_read == instance->pages_total) {
|
||||
instance->state = MfUltralightPollerStateReadCounters;
|
||||
@@ -753,7 +818,6 @@ static const MfUltralightPollerReadHandler
|
||||
[MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages,
|
||||
[MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail,
|
||||
[MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success,
|
||||
|
||||
};
|
||||
|
||||
static NfcCommand mf_ultralight_poller_run(NfcGenericEvent event, void* context) {
|
||||
|
||||
@@ -27,6 +27,7 @@ typedef enum {
|
||||
MfUltralightPollerEventTypeCardLocked, /**< Presented card is locked by password, AUTH0 or lock bytes. */
|
||||
MfUltralightPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */
|
||||
MfUltralightPollerEventTypeWriteFail, /**< Poller failed to write card. */
|
||||
MfUltralightPollerEventTypeRequestKey, /**< Poller requests key for dict attack. */
|
||||
} MfUltralightPollerEventType;
|
||||
|
||||
/**
|
||||
@@ -35,6 +36,7 @@ typedef enum {
|
||||
typedef enum {
|
||||
MfUltralightPollerModeRead, /**< Poller will only read card. It's a default mode. */
|
||||
MfUltralightPollerModeWrite, /**< Poller will write already saved card to another presented card. */
|
||||
MfUltralightPollerModeDictAttack, /**< Poller will perform dictionary attack against card. */
|
||||
} MfUltralightPollerMode;
|
||||
|
||||
/**
|
||||
@@ -42,20 +44,29 @@ typedef enum {
|
||||
*/
|
||||
typedef struct {
|
||||
MfUltralightAuthPassword password; /**< Password to be used for authentication. */
|
||||
MfUltralightC3DesAuthKey tdes_key;
|
||||
MfUltralightAuthPack pack; /**< Pack received on successfull authentication. */
|
||||
MfUltralightC3DesAuthKey tdes_key; /**< 3DES key to be used for authentication. */
|
||||
MfUltralightAuthPack pack; /**< Pack received on successful authentication. */
|
||||
bool auth_success; /**< Set to true if authentication succeeded, false otherwise. */
|
||||
bool skip_auth; /**< Set to true if authentication should be skipped, false otherwise. */
|
||||
} 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.
|
||||
*/
|
||||
typedef union {
|
||||
MfUltralightPollerAuthContext auth_context; /**< Authentication context. */
|
||||
MfUltralightError error; /**< Error code indicating reading fail reason. */
|
||||
const MfUltralightData* write_data;
|
||||
MfUltralightPollerMode poller_mode;
|
||||
const MfUltralightData* write_data; /**< Data to be written to card. */
|
||||
MfUltralightPollerMode poller_mode; /**< Mode to operate in. */
|
||||
MfUltralightPollerKeyRequestData key_request_data; /**< Key request data. */
|
||||
} MfUltralightPollerEventData;
|
||||
|
||||
/**
|
||||
@@ -64,7 +75,7 @@ typedef union {
|
||||
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||
*/
|
||||
typedef struct {
|
||||
MfUltralightPollerEventType type; /**< Type of emmitted event. */
|
||||
MfUltralightPollerEventType type; /**< Type of emitted event. */
|
||||
MfUltralightPollerEventData* data; /**< Pointer to event specific data. */
|
||||
} MfUltralightPollerEvent;
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ MfUltralightError mf_ultralight_poller_authenticate_start(
|
||||
uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET;
|
||||
mf_ultralight_3des_decrypt(
|
||||
&instance->des_context,
|
||||
instance->mfu_event.data->auth_context.tdes_key.data,
|
||||
instance->auth_context.tdes_key.data,
|
||||
iv,
|
||||
encRndB,
|
||||
sizeof(encRndB),
|
||||
@@ -145,7 +145,7 @@ MfUltralightError mf_ultralight_poller_authenticate_start(
|
||||
|
||||
mf_ultralight_3des_encrypt(
|
||||
&instance->des_context,
|
||||
instance->mfu_event.data->auth_context.tdes_key.data,
|
||||
instance->auth_context.tdes_key.data,
|
||||
encRndB,
|
||||
output,
|
||||
MF_ULTRALIGHT_C_AUTH_DATA_SIZE,
|
||||
@@ -179,7 +179,7 @@ MfUltralightError mf_ultralight_poller_authenticate_end(
|
||||
|
||||
mf_ultralight_3des_decrypt(
|
||||
&instance->des_context,
|
||||
instance->mfu_event.data->auth_context.tdes_key.data,
|
||||
instance->auth_context.tdes_key.data,
|
||||
RndB,
|
||||
bit_buffer_get_data(instance->rx_buffer) + 1,
|
||||
MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE,
|
||||
|
||||
@@ -134,22 +134,21 @@ static void keys_dict_int_to_str(KeysDict* instance, const uint8_t* key_int, Fur
|
||||
furi_string_cat_printf(key_str, "%02X", key_int[i]);
|
||||
}
|
||||
|
||||
static void keys_dict_str_to_int(KeysDict* instance, FuriString* key_str, uint64_t* key_int) {
|
||||
static void keys_dict_str_to_int(KeysDict* instance, FuriString* key_str, uint8_t* key_out) {
|
||||
furi_assert(instance);
|
||||
furi_assert(key_str);
|
||||
furi_assert(key_int);
|
||||
furi_assert(key_out);
|
||||
|
||||
uint8_t key_byte_tmp;
|
||||
char h, l;
|
||||
|
||||
*key_int = 0ULL;
|
||||
|
||||
// Process two hex characters at a time to create each byte
|
||||
for(size_t i = 0; i < instance->key_size_symbols - 1; i += 2) {
|
||||
h = furi_string_get_char(key_str, i);
|
||||
l = furi_string_get_char(key_str, i + 1);
|
||||
|
||||
args_char_to_hex(h, l, &key_byte_tmp);
|
||||
*key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2));
|
||||
key_out[i / 2] = key_byte_tmp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,15 +192,7 @@ bool keys_dict_get_next_key(KeysDict* instance, uint8_t* key, size_t key_size) {
|
||||
bool key_read = keys_dict_get_next_key_str(instance, temp_key);
|
||||
|
||||
if(key_read) {
|
||||
size_t tmp_len = key_size;
|
||||
uint64_t key_int = 0;
|
||||
|
||||
keys_dict_str_to_int(instance, temp_key, &key_int);
|
||||
|
||||
while(tmp_len--) {
|
||||
key[tmp_len] = (uint8_t)key_int;
|
||||
key_int >>= 8;
|
||||
}
|
||||
keys_dict_str_to_int(instance, temp_key, key);
|
||||
}
|
||||
|
||||
furi_string_free(temp_key);
|
||||
|
||||
Reference in New Issue
Block a user