mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-23 21:34:35 +03:00
[FL-3676] Slix disable privacy (#3425)
* slix: add unlock option * slix: add features for nxp get info and signature commands * slix: working unlock * nfc app: rewrite slix unlock * slix poller: simplify unlock state handler * nfc app: fix slix key setting * nfc app: fix navigation * slix poller: code clean up * slix: resolve TODO, clean code * nfc app: fix naming * nfc app: rework slix unlock success scene * slix poller: add documentation * slix listener: fix password comparison Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
f6eb79e1e5
commit
6bc63b7734
64
applications/main/nfc/helpers/slix_unlock.c
Normal file
64
applications/main/nfc/helpers/slix_unlock.c
Normal file
@ -0,0 +1,64 @@
|
||||
#include "slix_unlock.h"
|
||||
|
||||
#include <furi/furi.h>
|
||||
|
||||
#define SLIX_UNLOCK_PASSWORD_NUM_MAX (2)
|
||||
|
||||
struct SlixUnlock {
|
||||
SlixUnlockMethod method;
|
||||
SlixPassword password_arr[SLIX_UNLOCK_PASSWORD_NUM_MAX];
|
||||
size_t password_arr_len;
|
||||
size_t password_idx;
|
||||
};
|
||||
|
||||
static const SlixPassword tonie_box_pass_arr[] = {0x5B6EFD7F, 0x0F0F0F0F};
|
||||
|
||||
SlixUnlock* slix_unlock_alloc() {
|
||||
SlixUnlock* instance = malloc(sizeof(SlixUnlock));
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void slix_unlock_free(SlixUnlock* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void slix_unlock_reset(SlixUnlock* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
memset(instance, 0, sizeof(SlixUnlock));
|
||||
}
|
||||
|
||||
void slix_unlock_set_method(SlixUnlock* instance, SlixUnlockMethod method) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->method = method;
|
||||
if(method == SlixUnlockMethodTonieBox) {
|
||||
instance->password_arr_len = COUNT_OF(tonie_box_pass_arr);
|
||||
memcpy(instance->password_arr, tonie_box_pass_arr, sizeof(tonie_box_pass_arr));
|
||||
}
|
||||
}
|
||||
|
||||
void slix_unlock_set_password(SlixUnlock* instance, SlixPassword password) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->method == SlixUnlockMethodManual);
|
||||
|
||||
instance->password_arr[0] = password;
|
||||
instance->password_arr_len = 1;
|
||||
}
|
||||
|
||||
bool slix_unlock_get_next_password(SlixUnlock* instance, SlixPassword* password) {
|
||||
furi_assert(instance);
|
||||
furi_assert(password);
|
||||
|
||||
bool password_set = false;
|
||||
if(instance->password_arr_len) {
|
||||
*password = instance->password_arr[instance->password_idx++];
|
||||
instance->password_idx %= instance->password_arr_len;
|
||||
password_set = true;
|
||||
}
|
||||
|
||||
return password_set;
|
||||
}
|
30
applications/main/nfc/helpers/slix_unlock.h
Normal file
30
applications/main/nfc/helpers/slix_unlock.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/slix/slix.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
SlixUnlockMethodManual,
|
||||
SlixUnlockMethodTonieBox,
|
||||
} SlixUnlockMethod;
|
||||
|
||||
typedef struct SlixUnlock SlixUnlock;
|
||||
|
||||
SlixUnlock* slix_unlock_alloc();
|
||||
|
||||
void slix_unlock_free(SlixUnlock* instance);
|
||||
|
||||
void slix_unlock_reset(SlixUnlock* instance);
|
||||
|
||||
void slix_unlock_set_method(SlixUnlock* instance, SlixUnlockMethod method);
|
||||
|
||||
void slix_unlock_set_password(SlixUnlock* instance, SlixPassword password);
|
||||
|
||||
bool slix_unlock_get_next_password(SlixUnlock* instance, SlixPassword* password);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -51,6 +51,7 @@ NfcApp* nfc_app_alloc() {
|
||||
instance->nfc = nfc_alloc();
|
||||
|
||||
instance->mf_ul_auth = mf_ultralight_auth_alloc();
|
||||
instance->slix_unlock = slix_unlock_alloc();
|
||||
instance->mfc_key_cache = mf_classic_key_cache_alloc();
|
||||
instance->nfc_supported_cards = nfc_supported_cards_alloc();
|
||||
|
||||
@ -141,6 +142,7 @@ void nfc_app_free(NfcApp* instance) {
|
||||
nfc_free(instance->nfc);
|
||||
|
||||
mf_ultralight_auth_free(instance->mf_ul_auth);
|
||||
slix_unlock_free(instance->slix_unlock);
|
||||
mf_classic_key_cache_free(instance->mfc_key_cache);
|
||||
nfc_supported_cards_free(instance->nfc_supported_cards);
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "helpers/mfkey32_logger.h"
|
||||
#include "helpers/mf_classic_key_cache.h"
|
||||
#include "helpers/nfc_supported_cards.h"
|
||||
#include "helpers/slix_unlock.h"
|
||||
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <storage/storage.h>
|
||||
@ -129,6 +130,7 @@ struct NfcApp {
|
||||
NfcListener* listener;
|
||||
|
||||
MfUltralightAuth* mf_ul_auth;
|
||||
SlixUnlock* slix_unlock;
|
||||
NfcMfClassicDictAttackContext nfc_dict_context;
|
||||
Mfkey32Logger* mfkey32_logger;
|
||||
MfUserDict* mf_user_dict;
|
||||
|
@ -59,4 +59,9 @@ ADD_SCENE(nfc, set_sak, SetSak)
|
||||
ADD_SCENE(nfc, set_atqa, SetAtqa)
|
||||
ADD_SCENE(nfc, set_uid, SetUid)
|
||||
|
||||
ADD_SCENE(nfc, slix_unlock_menu, SlixUnlockMenu)
|
||||
ADD_SCENE(nfc, slix_key_input, SlixKeyInput)
|
||||
ADD_SCENE(nfc, slix_unlock, SlixUnlock)
|
||||
ADD_SCENE(nfc, slix_unlock_success, SlixUnlockSuccess)
|
||||
|
||||
ADD_SCENE(nfc, generate_info, GenerateInfo)
|
||||
|
@ -4,6 +4,7 @@ enum SubmenuIndex {
|
||||
SubmenuIndexReadCardType,
|
||||
SubmenuIndexMfClassicKeys,
|
||||
SubmenuIndexMfUltralightUnlock,
|
||||
SubmenuIndexSlixUnlock,
|
||||
};
|
||||
|
||||
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
|
||||
@ -34,6 +35,12 @@ void nfc_scene_extra_actions_on_enter(void* context) {
|
||||
SubmenuIndexMfUltralightUnlock,
|
||||
nfc_scene_extra_actions_submenu_callback,
|
||||
instance);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Unlock SLIX-L",
|
||||
SubmenuIndexSlixUnlock,
|
||||
nfc_scene_extra_actions_submenu_callback,
|
||||
instance);
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(instance->scene_manager, NfcSceneExtraActions));
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu);
|
||||
@ -54,6 +61,9 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
|
||||
} else if(event.event == SubmenuIndexReadCardType) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSelectProtocol);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexSlixUnlock) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSlixUnlockMenu);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(instance->scene_manager, NfcSceneExtraActions, event.event);
|
||||
}
|
||||
|
@ -28,7 +28,11 @@ bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.event == DialogExResultRight) {
|
||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||
} else if(event.event == DialogExResultLeft) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack)) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSlixUnlock)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneSlixUnlock);
|
||||
} else if(scene_manager_has_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicDictAttack)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicDictAttack);
|
||||
} else if(scene_manager_has_previous_scene(
|
||||
|
48
applications/main/nfc/scenes/nfc_scene_slix_key_input.c
Normal file
48
applications/main/nfc/scenes/nfc_scene_slix_key_input.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
#include <nfc/helpers/nfc_util.h>
|
||||
|
||||
void nfc_scene_slix_key_input_byte_input_callback(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
SlixPassword password = nfc_util_bytes2num(instance->byte_input_store, sizeof(SlixPassword));
|
||||
slix_unlock_set_password(instance->slix_unlock, password);
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void nfc_scene_slix_key_input_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = instance->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter the password in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
nfc_scene_slix_key_input_byte_input_callback,
|
||||
NULL,
|
||||
instance,
|
||||
instance->byte_input_store,
|
||||
sizeof(SlixPassword));
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewByteInput);
|
||||
}
|
||||
|
||||
bool nfc_scene_slix_key_input_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventByteInputDone) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSlixUnlock);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_slix_key_input_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, "");
|
||||
}
|
70
applications/main/nfc/scenes/nfc_scene_slix_unlock.c
Normal file
70
applications/main/nfc/scenes/nfc_scene_slix_unlock.c
Normal file
@ -0,0 +1,70 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
#include <nfc/protocols/slix/slix_poller.h>
|
||||
|
||||
NfcCommand nfc_scene_slix_unlock_worker_callback(NfcGenericEvent event, void* context) {
|
||||
furi_assert(event.protocol == NfcProtocolSlix);
|
||||
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
NfcApp* instance = context;
|
||||
SlixPollerEvent* slix_event = event.event_data;
|
||||
if(slix_event->type == SlixPollerEventTypePrivacyUnlockRequest) {
|
||||
SlixPassword pwd = 0;
|
||||
bool get_password_success = slix_unlock_get_next_password(instance->slix_unlock, &pwd);
|
||||
slix_event->data->privacy_password.password = pwd;
|
||||
slix_event->data->privacy_password.password_set = get_password_success;
|
||||
} else if(slix_event->type == SlixPollerEventTypeError) {
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerFailure);
|
||||
} else if(slix_event->type == SlixPollerEventTypeReady) {
|
||||
nfc_device_set_data(
|
||||
instance->nfc_device, NfcProtocolSlix, nfc_poller_get_data(instance->poller));
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
|
||||
command = NfcCommandStop;
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
void nfc_scene_slix_unlock_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
|
||||
popup_set_header(instance->popup, "Unlocking", 97, 15, AlignCenter, AlignTop);
|
||||
popup_set_text(
|
||||
instance->popup, "Apply card to\nFlipper's back", 97, 27, AlignCenter, AlignTop);
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
|
||||
|
||||
instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolSlix);
|
||||
nfc_poller_start(instance->poller, nfc_scene_slix_unlock_worker_callback, instance);
|
||||
}
|
||||
|
||||
bool nfc_scene_slix_unlock_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
UNUSED(instance);
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventPollerFailure) {
|
||||
consumed = true;
|
||||
} else if(event.event == NfcCustomEventPollerSuccess) {
|
||||
notification_message(instance->notifications, &sequence_success);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSlixUnlockSuccess);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
instance->scene_manager, NfcSceneSlixUnlockMenu);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_slix_unlock_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
nfc_poller_stop(instance->poller);
|
||||
nfc_poller_free(instance->poller);
|
||||
|
||||
popup_reset(instance->popup);
|
||||
}
|
60
applications/main/nfc/scenes/nfc_scene_slix_unlock_menu.c
Normal file
60
applications/main/nfc/scenes/nfc_scene_slix_unlock_menu.c
Normal file
@ -0,0 +1,60 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexSlixUnlockMenuManual,
|
||||
SubmenuIndexSlixUnlockMenuTonieBox,
|
||||
};
|
||||
|
||||
void nfc_scene_slix_unlock_menu_submenu_callback(void* context, uint32_t index) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_slix_unlock_menu_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
Submenu* submenu = instance->submenu;
|
||||
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(instance->scene_manager, NfcSceneSlixUnlockMenu);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Enter Password Manually",
|
||||
SubmenuIndexSlixUnlockMenuManual,
|
||||
nfc_scene_slix_unlock_menu_submenu_callback,
|
||||
instance);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Auth As TommyBox",
|
||||
SubmenuIndexSlixUnlockMenuTonieBox,
|
||||
nfc_scene_slix_unlock_menu_submenu_callback,
|
||||
instance);
|
||||
submenu_set_selected_item(submenu, state);
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_slix_unlock_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexSlixUnlockMenuManual) {
|
||||
slix_unlock_set_method(instance->slix_unlock, SlixUnlockMethodManual);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSlixKeyInput);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexSlixUnlockMenuTonieBox) {
|
||||
slix_unlock_set_method(instance->slix_unlock, SlixUnlockMethodTonieBox);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSlixUnlock);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager, NfcSceneSlixUnlockMenu, event.event);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_slix_unlock_menu_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
submenu_reset(instance->submenu);
|
||||
}
|
71
applications/main/nfc/scenes/nfc_scene_slix_unlock_success.c
Normal file
71
applications/main/nfc/scenes/nfc_scene_slix_unlock_success.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include "../nfc_app_i.h"
|
||||
|
||||
static void nfc_scene_slix_unlock_success_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_slix_unlock_success_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
Widget* widget = instance->widget;
|
||||
widget_add_string_element(widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "SLIX Unlocked!");
|
||||
|
||||
FuriString* temp_str = furi_string_alloc_set_str("UID:");
|
||||
size_t uid_len = 0;
|
||||
const uint8_t* uid = nfc_device_get_uid(instance->nfc_device, &uid_len);
|
||||
for(size_t i = 0; i < uid_len; i++) {
|
||||
furi_string_cat_printf(temp_str, " %02X", uid[i]);
|
||||
}
|
||||
furi_string_cat_printf(temp_str, "\nPrivacy Mode: Disabled");
|
||||
widget_add_string_multiline_element(
|
||||
widget, 0, 12, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
|
||||
furi_string_free(temp_str);
|
||||
|
||||
widget_add_button_element(
|
||||
widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Retry",
|
||||
nfc_scene_slix_unlock_success_widget_callback,
|
||||
instance);
|
||||
widget_add_button_element(
|
||||
widget,
|
||||
GuiButtonTypeRight,
|
||||
"More",
|
||||
nfc_scene_slix_unlock_success_widget_callback,
|
||||
instance);
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_scene_slix_unlock_success_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcApp* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneRetryConfirm);
|
||||
consumed = true;
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneReadMenu);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneExitConfirm);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_slix_unlock_success_on_exit(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
widget_reset(instance->widget);
|
||||
}
|
@ -32,17 +32,7 @@ static Iso15693_3Error iso15693_3_poller_filter_error(Iso15693_3Error error) {
|
||||
}
|
||||
}
|
||||
|
||||
static Iso15693_3Error iso15693_3_poller_prepare_trx(Iso15693_3Poller* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
if(instance->state == Iso15693_3PollerStateIdle) {
|
||||
return iso15693_3_poller_activate(instance, NULL);
|
||||
}
|
||||
|
||||
return Iso15693_3ErrorNone;
|
||||
}
|
||||
|
||||
static Iso15693_3Error iso15693_3_poller_frame_exchange(
|
||||
Iso15693_3Error iso15693_3_poller_send_frame(
|
||||
Iso15693_3Poller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer,
|
||||
@ -156,7 +146,7 @@ Iso15693_3Error iso15693_3_poller_inventory(Iso15693_3Poller* instance, uint8_t*
|
||||
Iso15693_3Error ret;
|
||||
|
||||
do {
|
||||
ret = iso15693_3_poller_frame_exchange(
|
||||
ret = iso15693_3_poller_send_frame(
|
||||
instance, instance->tx_buffer, instance->rx_buffer, ISO15693_3_FDT_POLL_FC);
|
||||
if(ret != Iso15693_3ErrorNone) break;
|
||||
|
||||
@ -183,7 +173,7 @@ Iso15693_3Error
|
||||
Iso15693_3Error ret;
|
||||
|
||||
do {
|
||||
ret = iso15693_3_poller_frame_exchange(
|
||||
ret = iso15693_3_poller_send_frame(
|
||||
instance, instance->tx_buffer, instance->rx_buffer, ISO15693_3_FDT_POLL_FC);
|
||||
if(ret != Iso15693_3ErrorNone) break;
|
||||
|
||||
@ -284,20 +274,3 @@ Iso15693_3Error iso15693_3_poller_get_blocks_security(
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Iso15693_3Error iso15693_3_poller_send_frame(
|
||||
Iso15693_3Poller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer,
|
||||
uint32_t fwt) {
|
||||
Iso15693_3Error ret;
|
||||
|
||||
do {
|
||||
ret = iso15693_3_poller_prepare_trx(instance);
|
||||
if(ret != Iso15693_3ErrorNone) break;
|
||||
|
||||
ret = iso15693_3_poller_frame_exchange(instance, tx_buffer, rx_buffer, fwt);
|
||||
} while(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ const Iso15693_3Data* slix_get_base_data(const SlixData* data) {
|
||||
}
|
||||
|
||||
SlixType slix_get_type(const SlixData* data) {
|
||||
SlixType type = SlixTypeCount;
|
||||
SlixType type = SlixTypeUnknown;
|
||||
|
||||
do {
|
||||
if(iso15693_3_get_manufacturer_id(data->iso15693_3_data) != SLIX_NXP_MANUFACTURER_CODE)
|
||||
|
@ -37,6 +37,7 @@ extern "C" {
|
||||
#define SLIX_TYPE_FEATURE_EAS (1U << 4)
|
||||
#define SLIX_TYPE_FEATURE_SIGNATURE (1U << 5)
|
||||
#define SLIX_TYPE_FEATURE_PROTECTION (1U << 6)
|
||||
#define SLIX_TYPE_FEATURE_NFC_SYSTEM_INFO (1U << 7)
|
||||
|
||||
typedef uint32_t SlixTypeFeatures;
|
||||
|
||||
@ -56,7 +57,9 @@ typedef enum {
|
||||
SlixTypeSlixS,
|
||||
SlixTypeSlixL,
|
||||
SlixTypeSlix2,
|
||||
|
||||
SlixTypeCount,
|
||||
SlixTypeUnknown,
|
||||
} SlixType;
|
||||
|
||||
typedef enum {
|
||||
@ -71,6 +74,7 @@ typedef enum {
|
||||
typedef uint32_t SlixPassword;
|
||||
typedef uint8_t SlixSignature[SLIX_SIGNATURE_SIZE];
|
||||
typedef bool SlixPrivacy;
|
||||
typedef uint16_t SlixRandomNumber;
|
||||
|
||||
typedef struct {
|
||||
uint8_t pointer;
|
||||
|
@ -99,6 +99,33 @@ SlixError slix_read_signature_response_parse(SlixSignature data, const BitBuffer
|
||||
return error;
|
||||
}
|
||||
|
||||
SlixError slix_get_random_number_response_parse(SlixRandomNumber* data, const BitBuffer* buf) {
|
||||
SlixError error = SlixErrorNone;
|
||||
|
||||
do {
|
||||
if(slix_error_response_parse(&error, buf)) break;
|
||||
|
||||
typedef struct {
|
||||
uint8_t flags;
|
||||
uint8_t random_number[2];
|
||||
} SlixGetRandomNumberResponseLayout;
|
||||
|
||||
const size_t size_received = bit_buffer_get_size_bytes(buf);
|
||||
const size_t size_required = sizeof(SlixGetRandomNumberResponseLayout);
|
||||
|
||||
if(size_received != size_required) {
|
||||
error = SlixErrorFormat;
|
||||
break;
|
||||
}
|
||||
|
||||
const SlixGetRandomNumberResponseLayout* response =
|
||||
(const SlixGetRandomNumberResponseLayout*)bit_buffer_get_data(buf);
|
||||
*data = (response->random_number[1] << 8) | response->random_number[0];
|
||||
} while(false);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void slix_set_password(SlixData* data, SlixPasswordType password_type, SlixPassword password) {
|
||||
furi_assert(data);
|
||||
furi_assert(password_type < SlixPasswordTypeCount);
|
||||
|
@ -48,7 +48,7 @@ extern "C" {
|
||||
#define SLIX_TYPE_FEATURES_SLIX2 \
|
||||
(SLIX_TYPE_FEATURE_READ | SLIX_TYPE_FEATURE_WRITE | SLIX_TYPE_FEATURE_PRIVACY | \
|
||||
SLIX_TYPE_FEATURE_DESTROY | SLIX_TYPE_FEATURE_EAS | SLIX_TYPE_FEATURE_SIGNATURE | \
|
||||
SLIX_TYPE_FEATURE_PROTECTION)
|
||||
SLIX_TYPE_FEATURE_PROTECTION | SLIX_TYPE_FEATURE_NFC_SYSTEM_INFO)
|
||||
|
||||
#define SLIX2_FEATURE_FLAGS \
|
||||
(SLIX_FEATURE_FLAG_UM_PP | SLIX_FEATURE_FLAG_COUNTER | SLIX_FEATURE_FLAG_EAS_ID | \
|
||||
@ -74,6 +74,8 @@ SlixError slix_get_nxp_system_info_response_parse(SlixData* data, const BitBuffe
|
||||
|
||||
SlixError slix_read_signature_response_parse(SlixSignature data, const BitBuffer* buf);
|
||||
|
||||
SlixError slix_get_random_number_response_parse(SlixRandomNumber* data, const BitBuffer* buf);
|
||||
|
||||
// Setters
|
||||
void slix_set_password(SlixData* data, SlixPasswordType password_type, SlixPassword password);
|
||||
|
||||
|
@ -63,7 +63,7 @@ static NfcCommand slix_listener_run(NfcGenericEvent event, void* context) {
|
||||
if(iso15693_3_event->type == Iso15693_3ListenerEventTypeCustomCommand) {
|
||||
const SlixError error = slix_listener_process_request(instance, rx_buffer);
|
||||
if(error == SlixErrorWrongPassword) {
|
||||
command = NfcCommandStop;
|
||||
command = NfcCommandSleep;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ static SlixPasswordType slix_listener_get_password_type_by_id(uint8_t id) {
|
||||
|
||||
static SlixPassword
|
||||
slix_listener_unxor_password(const SlixPassword password_xored, uint16_t random) {
|
||||
return password_xored ^ ((SlixPassword)random << 16 | random);
|
||||
return REVERSE_BYTES_U32(password_xored ^ ((SlixPassword)random << 16 | random));
|
||||
}
|
||||
|
||||
static SlixError slix_listener_set_password(
|
||||
|
@ -44,33 +44,83 @@ static void slix_poller_free(SlixPoller* instance) {
|
||||
static NfcCommand slix_poller_handler_idle(SlixPoller* instance) {
|
||||
iso15693_3_copy(
|
||||
instance->data->iso15693_3_data, iso15693_3_poller_get_data(instance->iso15693_3_poller));
|
||||
|
||||
instance->poller_state = SlixPollerStateGetNxpSysInfo;
|
||||
instance->type = slix_get_type(instance->data);
|
||||
if(instance->type >= SlixTypeCount) {
|
||||
instance->error = SlixErrorNotSupported;
|
||||
instance->poller_state = SlixPollerStateError;
|
||||
} else {
|
||||
instance->poller_state = SlixPollerStateGetNxpSysInfo;
|
||||
}
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand slix_poller_handler_get_nfc_system_info(SlixPoller* instance) {
|
||||
instance->error = slix_poller_get_nxp_system_info(instance, &instance->data->system_info);
|
||||
if(instance->error == SlixErrorNone) {
|
||||
instance->poller_state = SlixPollerStateReadSignature;
|
||||
if(slix_type_has_features(instance->type, SLIX_TYPE_FEATURE_NFC_SYSTEM_INFO)) {
|
||||
instance->error = slix_poller_get_nxp_system_info(instance, &instance->data->system_info);
|
||||
if(instance->error == SlixErrorNone) {
|
||||
instance->poller_state = SlixPollerStateReadSignature;
|
||||
} else {
|
||||
instance->poller_state = SlixPollerStateError;
|
||||
}
|
||||
} else {
|
||||
instance->poller_state = SlixPollerStateError;
|
||||
instance->poller_state = SlixPollerStateReadSignature;
|
||||
}
|
||||
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand slix_poller_handler_read_signature(SlixPoller* instance) {
|
||||
instance->error = slix_poller_read_signature(instance, &instance->data->signature);
|
||||
if(instance->error == SlixErrorNone) {
|
||||
instance->poller_state = SlixPollerStateReady;
|
||||
if(slix_type_has_features(instance->type, SLIX_TYPE_FEATURE_SIGNATURE)) {
|
||||
instance->error = slix_poller_read_signature(instance, &instance->data->signature);
|
||||
if(instance->error == SlixErrorNone) {
|
||||
instance->poller_state = SlixPollerStateReady;
|
||||
} else {
|
||||
instance->poller_state = SlixPollerStateError;
|
||||
}
|
||||
} else {
|
||||
instance->poller_state = SlixPollerStateError;
|
||||
instance->poller_state = SlixPollerStateReady;
|
||||
}
|
||||
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand slix_poller_handler_privacy_unlock(SlixPoller* instance) {
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
instance->poller_state = SlixPollerStateError;
|
||||
|
||||
instance->slix_event.type = SlixPollerEventTypePrivacyUnlockRequest;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
|
||||
bool slix_unlocked = false;
|
||||
do {
|
||||
if(!instance->slix_event_data.privacy_password.password_set) break;
|
||||
SlixPassword pwd = instance->slix_event_data.privacy_password.password;
|
||||
FURI_LOG_I(TAG, "Trying to disable privacy mode with password: %08lX", pwd);
|
||||
|
||||
instance->error = slix_poller_get_random_number(instance, &instance->random_number);
|
||||
if(instance->error != SlixErrorNone) break;
|
||||
|
||||
instance->error = slix_poller_set_password(instance, SlixPasswordTypePrivacy, pwd);
|
||||
if(instance->error != SlixErrorNone) {
|
||||
command = NfcCommandReset;
|
||||
break;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Privacy mode disabled");
|
||||
instance->data->passwords[SlixPasswordTypePrivacy] = pwd;
|
||||
instance->poller_state = SlixPollerStateIdle;
|
||||
slix_unlocked = true;
|
||||
} while(false);
|
||||
|
||||
if(!slix_unlocked) {
|
||||
instance->error = SlixErrorTimeout;
|
||||
instance->poller_state = SlixPollerStateError;
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
static NfcCommand slix_poller_handler_error(SlixPoller* instance) {
|
||||
instance->slix_event_data.error = instance->error;
|
||||
instance->slix_event.type = SlixPollerEventTypeError;
|
||||
@ -90,6 +140,7 @@ static const SlixPollerStateHandler slix_poller_state_handler[SlixPollerStateNum
|
||||
[SlixPollerStateError] = slix_poller_handler_error,
|
||||
[SlixPollerStateGetNxpSysInfo] = slix_poller_handler_get_nfc_system_info,
|
||||
[SlixPollerStateReadSignature] = slix_poller_handler_read_signature,
|
||||
[SlixPollerStatePrivacyUnlock] = slix_poller_handler_privacy_unlock,
|
||||
[SlixPollerStateReady] = slix_poller_handler_ready,
|
||||
};
|
||||
|
||||
@ -117,8 +168,8 @@ static NfcCommand slix_poller_run(NfcGenericEvent event, void* context) {
|
||||
if(iso15693_3_event->type == Iso15693_3PollerEventTypeReady) {
|
||||
command = slix_poller_state_handler[instance->poller_state](instance);
|
||||
} else if(iso15693_3_event->type == Iso15693_3PollerEventTypeError) {
|
||||
instance->slix_event.type = SlixPollerEventTypeError;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
instance->poller_state = SlixPollerStatePrivacyUnlock;
|
||||
command = slix_poller_state_handler[instance->poller_state](instance);
|
||||
}
|
||||
|
||||
return command;
|
||||
@ -138,11 +189,7 @@ static bool slix_poller_detect(NfcGenericEvent event, void* context) {
|
||||
bool protocol_detected = false;
|
||||
|
||||
if(iso15693_3_event->type == Iso15693_3PollerEventTypeReady) {
|
||||
if(slix_get_type(instance->data) < SlixTypeCount) {
|
||||
SlixSystemInfo system_info = {};
|
||||
SlixError error = slix_poller_get_nxp_system_info(instance, &system_info);
|
||||
protocol_detected = (error == SlixErrorNone);
|
||||
}
|
||||
protocol_detected = (slix_get_type(instance->data) < SlixTypeCount);
|
||||
}
|
||||
|
||||
return protocol_detected;
|
||||
|
@ -18,14 +18,24 @@ typedef struct SlixPoller SlixPoller;
|
||||
*/
|
||||
typedef enum {
|
||||
SlixPollerEventTypeError, /**< An error occured while reading card. */
|
||||
SlixPollerEventTypePrivacyUnlockRequest, /**< Poller requests password to disable privacy mode. */
|
||||
SlixPollerEventTypeReady, /**< The card was successfully read by the poller. */
|
||||
} SlixPollerEventType;
|
||||
|
||||
/**
|
||||
* @brief Slix poller privacy unlock context data.
|
||||
*/
|
||||
typedef struct {
|
||||
SlixPassword password; /**< Privacy password. */
|
||||
bool password_set; /**< Filed to indicate that password was set or not. */
|
||||
} SlixPollerEventDataPrivacyUnlockContext;
|
||||
|
||||
/**
|
||||
* @brief Slixs poller event data.
|
||||
*/
|
||||
typedef union {
|
||||
SlixError error; /**< Error code indicating card reaing fail reason. */
|
||||
SlixPollerEventDataPrivacyUnlockContext privacy_password; /**< Privacy unlock event context. */
|
||||
} SlixPollerEventData;
|
||||
|
||||
/**
|
||||
@ -80,6 +90,30 @@ SlixError slix_poller_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo*
|
||||
*/
|
||||
SlixError slix_poller_read_signature(SlixPoller* instance, SlixSignature* data);
|
||||
|
||||
/**
|
||||
* @brief Get random number from card.
|
||||
*
|
||||
* Must ONLY be used inside the callback function.
|
||||
*
|
||||
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||
* @param[out] data pointer to the SlixRandomNumber structure to be filled.
|
||||
* @return SlixErrorNone on success, an error code on failure.
|
||||
*/
|
||||
SlixError slix_poller_get_random_number(SlixPoller* instance, SlixRandomNumber* data);
|
||||
|
||||
/**
|
||||
* @brief Set password to card.
|
||||
*
|
||||
* Must ONLY be used inside the callback function.
|
||||
*
|
||||
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||
* @param[out] type SlixPasswordType instance.
|
||||
* @param[out] password SlixPassword instance.
|
||||
* @return SlixErrorNone on success, an error code on failure.
|
||||
*/
|
||||
SlixError
|
||||
slix_poller_set_password(SlixPoller* instance, SlixPasswordType type, SlixPassword password);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "slix_poller_i.h"
|
||||
#include <nfc/helpers/nfc_util.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
@ -6,18 +7,22 @@
|
||||
|
||||
#define TAG "SlixPoller"
|
||||
|
||||
static void slix_poller_prepare_request(SlixPoller* instance, uint8_t command) {
|
||||
static void slix_poller_prepare_request(SlixPoller* instance, uint8_t command, bool skip_uid) {
|
||||
bit_buffer_reset(instance->tx_buffer);
|
||||
bit_buffer_reset(instance->rx_buffer);
|
||||
|
||||
bit_buffer_append_byte(
|
||||
instance->tx_buffer,
|
||||
ISO15693_3_REQ_FLAG_SUBCARRIER_1 | ISO15693_3_REQ_FLAG_DATA_RATE_HI |
|
||||
ISO15693_3_REQ_FLAG_T4_ADDRESSED);
|
||||
uint8_t flags = ISO15693_3_REQ_FLAG_SUBCARRIER_1 | ISO15693_3_REQ_FLAG_DATA_RATE_HI;
|
||||
if(!skip_uid) {
|
||||
flags |= ISO15693_3_REQ_FLAG_T4_ADDRESSED;
|
||||
}
|
||||
|
||||
bit_buffer_append_byte(instance->tx_buffer, flags);
|
||||
bit_buffer_append_byte(instance->tx_buffer, command);
|
||||
bit_buffer_append_byte(instance->tx_buffer, SLIX_NXP_MANUFACTURER_CODE);
|
||||
|
||||
iso15693_3_append_uid(instance->data->iso15693_3_data, instance->tx_buffer);
|
||||
if(!skip_uid) {
|
||||
iso15693_3_append_uid(instance->data->iso15693_3_data, instance->tx_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
SlixError slix_poller_send_frame(
|
||||
@ -36,7 +41,7 @@ SlixError slix_poller_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo*
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
|
||||
slix_poller_prepare_request(instance, SLIX_CMD_GET_NXP_SYSTEM_INFORMATION);
|
||||
slix_poller_prepare_request(instance, SLIX_CMD_GET_NXP_SYSTEM_INFORMATION, false);
|
||||
|
||||
SlixError error = SlixErrorNone;
|
||||
|
||||
@ -54,7 +59,7 @@ SlixError slix_poller_read_signature(SlixPoller* instance, SlixSignature* data)
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
|
||||
slix_poller_prepare_request(instance, SLIX_CMD_READ_SIGNATURE);
|
||||
slix_poller_prepare_request(instance, SLIX_CMD_READ_SIGNATURE, false);
|
||||
|
||||
SlixError error = SlixErrorNone;
|
||||
|
||||
@ -67,3 +72,56 @@ SlixError slix_poller_read_signature(SlixPoller* instance, SlixSignature* data)
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
SlixError slix_poller_get_random_number(SlixPoller* instance, SlixRandomNumber* data) {
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
|
||||
slix_poller_prepare_request(instance, SLIX_CMD_GET_RANDOM_NUMBER, true);
|
||||
|
||||
SlixError error = SlixErrorNone;
|
||||
|
||||
do {
|
||||
error = slix_poller_send_frame(
|
||||
instance, instance->tx_buffer, instance->rx_buffer, ISO15693_3_FDT_POLL_FC);
|
||||
if(error != SlixErrorNone) break;
|
||||
|
||||
error = slix_get_random_number_response_parse(data, instance->rx_buffer);
|
||||
} while(false);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
SlixError
|
||||
slix_poller_set_password(SlixPoller* instance, SlixPasswordType type, SlixPassword password) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool skip_uid = (type == SlixPasswordTypePrivacy);
|
||||
slix_poller_prepare_request(instance, SLIX_CMD_SET_PASSWORD, skip_uid);
|
||||
|
||||
uint8_t password_type = (0x01 << type);
|
||||
bit_buffer_append_byte(instance->tx_buffer, password_type);
|
||||
|
||||
uint8_t rn_l = instance->random_number >> 8;
|
||||
uint8_t rn_h = instance->random_number;
|
||||
uint32_t double_rand_num = (rn_h << 24) | (rn_l << 16) | (rn_h << 8) | rn_l;
|
||||
uint32_t xored_password = double_rand_num ^ password;
|
||||
uint8_t xored_password_arr[4] = {};
|
||||
nfc_util_num2bytes(xored_password, 4, xored_password_arr);
|
||||
bit_buffer_append_bytes(instance->tx_buffer, xored_password_arr, 4);
|
||||
|
||||
SlixError error = SlixErrorNone;
|
||||
|
||||
do {
|
||||
error = slix_poller_send_frame(
|
||||
instance, instance->tx_buffer, instance->rx_buffer, SLIX_POLLER_SET_PASSWORD_FWT);
|
||||
if(error != SlixErrorNone) break;
|
||||
|
||||
size_t rx_len = bit_buffer_get_size_bytes(instance->rx_buffer);
|
||||
if(rx_len != 1) {
|
||||
error = SlixErrorWrongPassword;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include "slix_poller.h"
|
||||
|
||||
#define SLIX_POLLER_SET_PASSWORD_FWT (100000)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -12,6 +14,7 @@ typedef enum {
|
||||
SlixPollerStateIdle,
|
||||
SlixPollerStateGetNxpSysInfo,
|
||||
SlixPollerStateReadSignature,
|
||||
SlixPollerStatePrivacyUnlock,
|
||||
SlixPollerStateReady,
|
||||
SlixPollerStateError,
|
||||
SlixPollerStateNum,
|
||||
@ -19,9 +22,11 @@ typedef enum {
|
||||
|
||||
struct SlixPoller {
|
||||
Iso15693_3Poller* iso15693_3_poller;
|
||||
SlixType type;
|
||||
SlixData* data;
|
||||
SlixPollerState poller_state;
|
||||
SlixError error;
|
||||
SlixRandomNumber random_number;
|
||||
|
||||
BitBuffer* tx_buffer;
|
||||
BitBuffer* rx_buffer;
|
||||
|
Loading…
Reference in New Issue
Block a user