Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mifare Ultralight authentication #1365

Merged
merged 25 commits into from
Aug 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0b83441
mifare ultralight auth prototype
ezhevita May 20, 2022
3c2a338
Merge remote-tracking branch 'upstream/dev' into ezhevita/mf-ul-auth
ezhevita Jul 1, 2022
2f89011
Merge remote-tracking branch 'upstream/dev' into ezhevita/mf-ul-auth
ezhevita Jul 4, 2022
89c5e07
it works!
ezhevita Jul 4, 2022
d1ca499
Reference source
ezhevita Jul 4, 2022
775087d
formatting
ezhevita Jul 4, 2022
3a04cf6
use countof
ezhevita Jul 5, 2022
f34955b
Merge branch 'dev' into ezhevita/mf-ul-auth
ezhevita Jul 5, 2022
56b0307
Merge remote-tracking branch 'upstream/dev' into ezhevita/mf-ul-auth
ezhevita Jul 26, 2022
d71a248
rework everything
ezhevita Jul 31, 2022
54395c1
oops forgot scenes
ezhevita Jul 31, 2022
695e9ee
Merge remote-tracking branch 'upstream/dev' into ezhevita/mf-ul-auth
ezhevita Jul 31, 2022
34c3a52
build: revert changes in manifest, stack size
gornekich Aug 2, 2022
bef8ec7
Merge branch 'dev' into ezhevita/mf-ul-auth
gornekich Aug 2, 2022
9c8addc
build: fix buid, format sources
gornekich Aug 2, 2022
3edc1f1
nfc: update unlock ultralight GUI
gornekich Aug 5, 2022
97d7173
nfc: fix byte input header
gornekich Aug 5, 2022
efe0d77
nfc: add new scenes for locked ultralight
gornekich Aug 5, 2022
34610a8
nfc: add data read to ultralights
gornekich Aug 7, 2022
4383cab
nfc: add unlock option in mf ultralight menu
gornekich Aug 7, 2022
ab6ce83
nfc: add data read init in ultralight generation
gornekich Aug 7, 2022
d25c160
Merge branch 'dev' into ezhevita/mf-ul-auth
gornekich Aug 7, 2022
dcf3cc5
nfc: lin sources, fix unlocked save
gornekich Aug 7, 2022
64f4aff
nfc: format python sources
gornekich Aug 7, 2022
b058a09
nfc: clean up
gornekich Aug 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion applications/nfc/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ App(
],
provides=["nfc_start"],
icon="A_NFC_14",
stack_size=4 * 1024,
stack_size=5 * 1024,
order=30,
)

Expand Down
4 changes: 4 additions & 0 deletions applications/nfc/helpers/nfc_generators.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ static void nfc_generate_mf_ul_orig(NfcDeviceData* data) {
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUnknown;
mful->data_size = 16 * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
// TODO: what's internal byte on page 2?
memset(&mful->data[4 * 4], 0xFF, 4);
Expand All @@ -67,6 +68,7 @@ static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) {
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeNTAG203;
mful->data_size = 42 * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
mful->data[9] = 0x48; // Internal byte
memcpy(&mful->data[3 * 4], default_data_ntag203, sizeof(default_data_ntag203));
Expand All @@ -78,6 +80,7 @@ static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t n

MfUltralightData* mful = &data->mf_ul_data;
mful->data_size = num_pages * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
uint16_t config_index = (num_pages - 4) * 4;
mful->data[config_index] = 0x04; // STRG_MOD_EN
Expand Down Expand Up @@ -180,6 +183,7 @@ static void
mful->type = type;
memcpy(&mful->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c));
mful->data_size = num_pages * 4;
mful->data_read = mful->data_size;
memcpy(mful->data, data->nfc_data.uid, data->nfc_data.uid_len);
mful->data[7] = data->nfc_data.sak;
mful->data[8] = data->nfc_data.atqa[0];
Expand Down
Empty file modified applications/nfc/nfc_i.h
100755 → 100644
Empty file.
5 changes: 5 additions & 0 deletions applications/nfc/scenes/nfc_scene_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ ADD_SCENE(nfc, emulate_uid, EmulateUid)
ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess)
ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu)
ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate)
ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth)
ADD_SCENE(nfc, mf_ultralight_read_auth_result, MfUltralightReadAuthResult)
ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput)
ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu)
ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn)
ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess)
ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu)
ADD_SCENE(nfc, mf_desfire_data, MfDesfireData)
Expand Down
9 changes: 9 additions & 0 deletions applications/nfc/scenes/nfc_scene_extra_actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

enum SubmenuIndex {
SubmenuIndexMfClassicKeys,
SubmenuIndexMfUltralightUnlock,
};

void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
Expand All @@ -20,6 +21,12 @@ void nfc_scene_extra_actions_on_enter(void* context) {
SubmenuIndexMfClassicKeys,
nfc_scene_extra_actions_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Unlock NTAG/Ultralight",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly unclear wording. Unlock implies removing the protection on the tag, which this doesn't do.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it might be more clear for users who don't know internal MF Ultralight structure. They just want "unlock" card to read it :)
Feel free to suggest your naming!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just "Read protected NTAG/Ultralight" would work, though that might be a bit long. Can shorten "Ultralight" to "MFUL" in that case.

SubmenuIndexMfUltralightUnlock,
nfc_scene_extra_actions_submenu_callback,
nfc);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}

Expand All @@ -35,6 +42,8 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
}
consumed = true;
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
}
Expand Down
44 changes: 44 additions & 0 deletions applications/nfc/scenes/nfc_scene_mf_ultralight_key_input.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include "../nfc_i.h"

void nfc_scene_mf_ultralight_key_input_byte_input_callback(void* context) {
Nfc* nfc = context;

view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
}

void nfc_scene_mf_ultralight_key_input_on_enter(void* context) {
Nfc* nfc = context;

// Setup view
ByteInput* byte_input = nfc->byte_input;
byte_input_set_header_text(byte_input, "Enter the password in hex");
byte_input_set_result_callback(
byte_input,
nfc_scene_mf_ultralight_key_input_byte_input_callback,
NULL,
nfc,
nfc->byte_input_store,
4);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
}

bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn);
consumed = true;
}
}
return consumed;
}

void nfc_scene_mf_ultralight_key_input_on_exit(void* context) {
Nfc* nfc = context;

// Clear view
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(nfc->byte_input, "");
}
19 changes: 15 additions & 4 deletions applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "../nfc_i.h"

enum SubmenuIndex {
SubmenuIndexUnlock,
SubmenuIndexSave,
SubmenuIndexEmulate,
};
Expand All @@ -14,7 +15,16 @@ void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index
void nfc_scene_mf_ultralight_menu_on_enter(void* context) {
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data;

if(data->data_read != data->data_size) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would recommend checking whether authentication is supported by tag instead of whether the entire tag has been read, since some tags are not read-protected, but are write-protected and emulation may not work with original reader if PACK is incorrect.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

submenu_add_item(
submenu,
"Unlock With Password",
SubmenuIndexUnlock,
nfc_scene_mf_ultralight_menu_submenu_callback,
nfc);
}
submenu_add_item(
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc);
submenu_add_item(
Expand All @@ -35,19 +45,20 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even

if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSave) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexSave);
nfc->dev->format = NfcDeviceSaveFormatMifareUl;
// Clear device name
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
} else if(event.event == SubmenuIndexEmulate) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexEmulate);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
consumed = true;
} else if(event.event == SubmenuIndexUnlock) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
consumed = true;
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event);

} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
}
Expand Down
107 changes: 107 additions & 0 deletions applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>

typedef enum {
NfcSceneMfUlReadStateIdle,
NfcSceneMfUlReadStateDetecting,
NfcSceneMfUlReadStateReading,
NfcSceneMfUlReadStateNotSupportedCard,
} NfcSceneMfUlReadState;

bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = context;

if(event == NfcWorkerEventMfUltralightPassKey) {
memcpy(nfc->dev->dev_data.mf_ul_data.auth_key, nfc->byte_input_store, 4);
} else {
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
}
return true;
}

void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState state) {
uint32_t curr_state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth);
if(curr_state != state) {
if(state == NfcSceneMfUlReadStateDetecting) {
popup_reset(nfc->popup);
popup_set_text(
nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop);
popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual);
} else if(state == NfcSceneMfUlReadStateReading) {
popup_reset(nfc->popup);
popup_set_header(
nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop);
popup_set_icon(nfc->popup, 12, 23, &A_Loading_24);
} else if(state == NfcSceneMfUlReadStateNotSupportedCard) {
popup_reset(nfc->popup);
popup_set_header(nfc->popup, "Wrong type of card!", 64, 3, AlignCenter, AlignTop);
popup_set_text(
nfc->popup,
"Only MIFARE\nUltralight & NTAG\n are supported",
4,
22,
AlignLeft,
AlignTop);
popup_set_icon(nfc->popup, 73, 17, &I_DolphinFirstStart8_56x51);
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth, state);
}
}

void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) {
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcRead);

nfc_device_clear(nfc->dev);
// Setup view
nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
// Start worker
nfc_worker_start(
nfc->worker,
NfcWorkerStateReadMfUltralightReadAuth,
&nfc->dev->dev_data,
nfc_scene_mf_ultralight_read_auth_worker_callback,
nfc);

nfc_blink_start(nfc);
}

bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
if((event.event == NfcWorkerEventSuccess) || (event.event == NfcWorkerEventFail)) {
notification_message(nfc->notifications, &sequence_success);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuthResult);
consumed = true;
} else if(event.event == NfcWorkerEventCardDetected) {
nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateReading);
consumed = true;
} else if(event.event == NfcWorkerEventNoCardDetected) {
nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting);
consumed = true;
} else if(event.event == NfcWorkerEventWrongCardDetected) {
nfc_scene_mf_ultralight_read_auth_set_state(
nfc, NfcSceneMfUlReadStateNotSupportedCard);
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
}
return consumed;
}

void nfc_scene_mf_ultralight_read_auth_on_exit(void* context) {
Nfc* nfc = context;

// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
popup_reset(nfc->popup);
nfc_blink_stop(nfc);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightReadAuth, NfcSceneMfUlReadStateIdle);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>

void nfc_scene_mf_ultralight_read_auth_result_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
Nfc* nfc = context;

if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}

void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) {
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);

// Setup dialog view
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(mf_ul_data);
Widget* widget = nfc->widget;
string_t temp_str;
string_init(temp_str);

if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) {
widget_add_string_element(
widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "All pages are unlocked!");
} else {
widget_add_string_element(
widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Not all pages unlocked!");
}
string_set_str(temp_str, "UID:");
for(size_t i = 0; i < nfc_data->uid_len; i++) {
string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
}
widget_add_string_element(
widget, 0, 17, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
if(mf_ul_data->auth_success) {
string_printf(
temp_str,
"Password: %02X %02X %02X %02X",
config_pages->auth_data.pwd.raw[0],
config_pages->auth_data.pwd.raw[1],
config_pages->auth_data.pwd.raw[2],
config_pages->auth_data.pwd.raw[3]);
widget_add_string_element(
widget, 0, 28, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
string_printf(
temp_str,
"PACK: %02X %02X",
config_pages->auth_data.pack.raw[0],
config_pages->auth_data.pack.raw[1]);
widget_add_string_element(
widget, 0, 39, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
}
string_printf(
temp_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4);
widget_add_string_element(
widget, 0, 50, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
widget_add_button_element(
widget,
GuiButtonTypeRight,
"Save",
nfc_scene_mf_ultralight_read_auth_result_widget_callback,
nfc);

string_clear(temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}

bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeRight) {
nfc->dev->format = NfcDeviceSaveFormatMifareUl;
// Clear device name
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
}

return consumed;
}

void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) {
Nfc* nfc = context;

// Clean views
widget_reset(nfc->widget);
}
Loading