mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-14 08:08:36 -07:00
added ISO15693 reading, saving and revealing from privacy mode (unlock)
This commit is contained in:
@@ -14,6 +14,10 @@ ADD_SCENE(nfc, file_select, FileSelect)
|
|||||||
ADD_SCENE(nfc, emulate_uid, EmulateUid)
|
ADD_SCENE(nfc, emulate_uid, EmulateUid)
|
||||||
ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess)
|
ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess)
|
||||||
ADD_SCENE(nfc, nfca_menu, NfcaMenu)
|
ADD_SCENE(nfc, nfca_menu, NfcaMenu)
|
||||||
|
ADD_SCENE(nfc, nfcv_menu, NfcVMenu)
|
||||||
|
ADD_SCENE(nfc, nfcv_unlock_menu, NfcVUnlockMenu)
|
||||||
|
ADD_SCENE(nfc, nfcv_key_input, NfcVKeyInput)
|
||||||
|
ADD_SCENE(nfc, nfcv_read_auth, NfcVReadAuth)
|
||||||
ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess)
|
ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess)
|
||||||
ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData)
|
ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData)
|
||||||
ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu)
|
ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
enum SubmenuIndex {
|
enum SubmenuIndex {
|
||||||
SubmenuIndexMfClassicKeys,
|
SubmenuIndexMfClassicKeys,
|
||||||
SubmenuIndexMfUltralightUnlock,
|
SubmenuIndexMfUltralightUnlock,
|
||||||
|
SubmenuIndexNfcVUnlock,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
|
||||||
@@ -27,6 +28,12 @@ void nfc_scene_extra_actions_on_enter(void* context) {
|
|||||||
SubmenuIndexMfUltralightUnlock,
|
SubmenuIndexMfUltralightUnlock,
|
||||||
nfc_scene_extra_actions_submenu_callback,
|
nfc_scene_extra_actions_submenu_callback,
|
||||||
nfc);
|
nfc);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Unlock SLIX-L",
|
||||||
|
SubmenuIndexNfcVUnlock,
|
||||||
|
nfc_scene_extra_actions_submenu_callback,
|
||||||
|
nfc);
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +51,8 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
|
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
||||||
|
} else if(event.event == SubmenuIndexNfcVUnlock) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlockMenu);
|
||||||
}
|
}
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
|
|||||||
NfcDeviceData* dev_data = &nfc->dev->dev_data;
|
NfcDeviceData* dev_data = &nfc->dev->dev_data;
|
||||||
NfcProtocol protocol = dev_data->protocol;
|
NfcProtocol protocol = dev_data->protocol;
|
||||||
uint8_t text_scroll_height = 0;
|
uint8_t text_scroll_height = 0;
|
||||||
if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl)) {
|
if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl)|| (protocol == NfcDeviceProtocolSlixL)) {
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc);
|
widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc);
|
||||||
text_scroll_height = 52;
|
text_scroll_height = 52;
|
||||||
@@ -40,19 +40,47 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
|
|||||||
temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type));
|
temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type));
|
||||||
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
|
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n");
|
furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n");
|
||||||
|
} else if(protocol == NfcDeviceProtocolSlixL) {
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-L\n");
|
||||||
} else {
|
} else {
|
||||||
furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n");
|
furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set tag iso data
|
// Set tag iso data
|
||||||
char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3';
|
if(protocol == NfcDeviceProtocolSlixL) {
|
||||||
furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type);
|
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
|
||||||
furi_string_cat_printf(temp_str, "UID:");
|
|
||||||
for(size_t i = 0; i < nfc_data->uid_len; i++) {
|
furi_string_cat_printf(temp_str, "UID:\n");
|
||||||
furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
|
for(size_t i = 0; i < nfc_data->uid_len; i++) {
|
||||||
|
furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(temp_str, "\n");
|
||||||
|
|
||||||
|
furi_string_cat_printf(temp_str, "DSFID: %02X\n", nfcv_data->dsfid);
|
||||||
|
furi_string_cat_printf(temp_str, "AFI: %02X\n", nfcv_data->afi);
|
||||||
|
furi_string_cat_printf(temp_str, "IC Ref: %02X\n", nfcv_data->ic_ref);
|
||||||
|
furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num);
|
||||||
|
furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size);
|
||||||
|
|
||||||
|
furi_string_cat_printf(temp_str, "Data (%d byte)\n", nfcv_data->block_num * nfcv_data->block_size);
|
||||||
|
|
||||||
|
for(int block = 0; block < nfcv_data->block_num; block++) {
|
||||||
|
for(int pos = 0; pos < nfcv_data->block_size; pos++) {
|
||||||
|
furi_string_cat_printf(temp_str, " %02X", nfcv_data->data[block * nfcv_data->block_size + pos]);
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(temp_str, "\n");
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(temp_str, "\n");
|
||||||
|
} else {
|
||||||
|
char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3';
|
||||||
|
furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type);
|
||||||
|
furi_string_cat_printf(temp_str, "UID:");
|
||||||
|
for(size_t i = 0; i < nfc_data->uid_len; i++) {
|
||||||
|
furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]);
|
||||||
|
furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak);
|
||||||
}
|
}
|
||||||
furi_string_cat_printf(temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]);
|
|
||||||
furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak);
|
|
||||||
|
|
||||||
// Set application specific data
|
// Set application specific data
|
||||||
if(protocol == NfcDeviceProtocolMifareDesfire) {
|
if(protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
@@ -120,6 +148,9 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else if(protocol == NfcDeviceProtocolMifareUl) {
|
} else if(protocol == NfcDeviceProtocolMifareUl) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
} else if(protocol == NfcDeviceProtocolSlixL) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu);
|
||||||
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
47
applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c
Normal file
47
applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_key_input_byte_input_callback(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
memcpy(nfc->dev->dev_data.nfcv_data.key_privacy, nfc->byte_input_store, 4);
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_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_nfcv_key_input_byte_input_callback,
|
||||||
|
NULL,
|
||||||
|
nfc,
|
||||||
|
nfc->byte_input_store,
|
||||||
|
4);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_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, NfcSceneNfcVReadAuth);
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_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, "");
|
||||||
|
}
|
||||||
53
applications/main/nfc/scenes/nfc_scene_nfcv_menu.c
Normal file
53
applications/main/nfc/scenes/nfc_scene_nfcv_menu.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexSave,
|
||||||
|
};
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_menu_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Save", SubmenuIndexSave, nfc_scene_nfcv_menu_submenu_callback, nfc);
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVMenu));
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == SubmenuIndexSave) {
|
||||||
|
nfc->dev->format = NfcDeviceSaveFormatSlixL;
|
||||||
|
// Clear device name
|
||||||
|
nfc_device_set_name(nfc->dev, "");
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVMenu, event.event);
|
||||||
|
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_menu_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
submenu_reset(nfc->submenu);
|
||||||
|
}
|
||||||
133
applications/main/nfc/scenes/nfc_scene_nfcv_read_auth.c
Normal file
133
applications/main/nfc/scenes/nfc_scene_nfcv_read_auth.c
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcSceneNfcVReadStateIdle,
|
||||||
|
NfcSceneNfcVReadStateDetecting,
|
||||||
|
NfcSceneNfcVReadStateUnlocked,
|
||||||
|
NfcSceneNfcVReadStateAlreadyUnlocked,
|
||||||
|
NfcSceneNfcVReadStateNotSupportedCard,
|
||||||
|
} NfcSceneNfcVReadState;
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_read_auth_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
if(event == NfcWorkerEventNfcVPassKey) {
|
||||||
|
memcpy(nfc->dev->dev_data.nfcv_data.key_privacy, nfc->byte_input_store, 4);
|
||||||
|
} else {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_read_auth_popup_callback(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_read_auth_set_state(Nfc* nfc, NfcSceneNfcVReadState state) {
|
||||||
|
NfcVData* nfcv_data = &(nfc->dev->dev_data.nfcv_data);
|
||||||
|
|
||||||
|
uint32_t curr_state =
|
||||||
|
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVReadAuth);
|
||||||
|
if(curr_state != state) {
|
||||||
|
Popup* popup = nfc->popup;
|
||||||
|
if(state == NfcSceneNfcVReadStateDetecting) {
|
||||||
|
popup_reset(popup);
|
||||||
|
popup_set_text(
|
||||||
|
popup, "Put Tonie On\nFlipper's Back", 97, 24, AlignCenter, AlignTop);
|
||||||
|
popup_set_icon(popup, 0, 8, &I_NFC_manual_60x50);
|
||||||
|
} else if(state == NfcSceneNfcVReadStateUnlocked) {
|
||||||
|
popup_reset(popup);
|
||||||
|
|
||||||
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
|
||||||
|
popup_set_header(popup, "Successfully\nUnlocked!", 94, 3, AlignCenter, AlignTop);
|
||||||
|
popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57);
|
||||||
|
popup_set_context(popup, nfc);
|
||||||
|
popup_set_callback(popup, nfc_scene_nfcv_read_auth_popup_callback);
|
||||||
|
popup_set_timeout(popup, 1500);
|
||||||
|
//popup_enable_timeout(popup);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
|
} else if(state == NfcSceneNfcVReadStateAlreadyUnlocked) {
|
||||||
|
popup_reset(popup);
|
||||||
|
|
||||||
|
popup_set_header(popup, "Already\nUnlocked!", 94, 3, AlignCenter, AlignTop);
|
||||||
|
popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57);
|
||||||
|
popup_set_context(popup, nfc);
|
||||||
|
popup_set_callback(popup, nfc_scene_nfcv_read_auth_popup_callback);
|
||||||
|
popup_set_timeout(popup, 1500);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
} else if(state == NfcSceneNfcVReadStateNotSupportedCard) {
|
||||||
|
popup_reset(popup);
|
||||||
|
popup_set_header(popup, "Wrong Type Of Card!", 64, 3, AlignCenter, AlignTop);
|
||||||
|
popup_set_text(
|
||||||
|
popup,
|
||||||
|
nfcv_data->error,
|
||||||
|
4,
|
||||||
|
22,
|
||||||
|
AlignLeft,
|
||||||
|
AlignTop);
|
||||||
|
popup_set_icon(popup, 73, 20, &I_DolphinCommon_56x48);
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVReadAuth, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_read_auth_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
nfc_device_clear(nfc->dev);
|
||||||
|
// Setup view
|
||||||
|
nfc_scene_nfcv_read_auth_set_state(nfc, NfcSceneNfcVReadStateDetecting);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
// Start worker
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker,
|
||||||
|
NfcWorkerStateNfcVReadAuth,
|
||||||
|
&nfc->dev->dev_data,
|
||||||
|
nfc_scene_nfcv_read_auth_worker_callback,
|
||||||
|
nfc);
|
||||||
|
|
||||||
|
nfc_blink_read_start(nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_read_auth_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcWorkerEventCardDetected) {
|
||||||
|
nfc_scene_nfcv_read_auth_set_state(nfc, NfcSceneNfcVReadStateUnlocked);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventAborted) {
|
||||||
|
nfc_scene_nfcv_read_auth_set_state(nfc, NfcSceneNfcVReadStateAlreadyUnlocked);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventNoCardDetected) {
|
||||||
|
nfc_scene_nfcv_read_auth_set_state(nfc, NfcSceneNfcVReadStateDetecting);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventWrongCardDetected) {
|
||||||
|
nfc_scene_nfcv_read_auth_set_state(nfc, NfcSceneNfcVReadStateNotSupportedCard);
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVUnlockMenu);
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_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, NfcSceneNfcVReadAuth, NfcSceneNfcVReadStateIdle);
|
||||||
|
}
|
||||||
62
applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c
Normal file
62
applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexNfcVUnlockMenuManual,
|
||||||
|
SubmenuIndexNfcVUnlockMenuTonieBox,
|
||||||
|
};
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_menu_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
|
uint32_t state =
|
||||||
|
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVUnlockMenu);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Enter PWD Manually",
|
||||||
|
SubmenuIndexNfcVUnlockMenuManual,
|
||||||
|
nfc_scene_nfcv_unlock_menu_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Auth As TonieBox",
|
||||||
|
SubmenuIndexNfcVUnlockMenuTonieBox,
|
||||||
|
nfc_scene_nfcv_unlock_menu_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
submenu_set_selected_item(submenu, state);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_unlock_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == SubmenuIndexNfcVUnlockMenuManual) {
|
||||||
|
nfc->dev->dev_data.nfcv_data.auth_method = NfcVAuthMethodManual;
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVKeyInput);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexNfcVUnlockMenuTonieBox) {
|
||||||
|
nfc->dev->dev_data.nfcv_data.auth_method = NfcVAuthMethodTonieBox;
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVReadAuth);
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVUnlockMenu, event.event);
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_menu_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
submenu_reset(nfc->submenu);
|
||||||
|
}
|
||||||
@@ -68,6 +68,11 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventReadNfcV) {
|
||||||
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
consumed = true;
|
||||||
} else if(event.event == NfcWorkerEventReadMfUltralight) {
|
} else if(event.event == NfcWorkerEventReadMfUltralight) {
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
||||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneSavedMenu);
|
nfc->scene_manager, NfcSceneSavedMenu);
|
||||||
|
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNfcDataInfo)) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneNfcDataInfo);
|
||||||
} else {
|
} else {
|
||||||
consumed = scene_manager_search_and_switch_to_another_scene(
|
consumed = scene_manager_search_and_switch_to_another_scene(
|
||||||
nfc->scene_manager, NfcSceneFileSelect);
|
nfc->scene_manager, NfcSceneFileSelect);
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ TARGET_HW = 7
|
|||||||
|
|
||||||
# Optimization flags
|
# Optimization flags
|
||||||
## Optimize for size
|
## Optimize for size
|
||||||
COMPACT = 0
|
COMPACT = 1
|
||||||
## Optimize for debugging experience
|
## Optimize for debugging experience
|
||||||
DEBUG = 1
|
DEBUG = 0
|
||||||
|
|
||||||
# Suffix to add to files when building distribution
|
# Suffix to add to files when building distribution
|
||||||
# If OS environment has DIST_SUFFIX set, it will be used instead
|
# If OS environment has DIST_SUFFIX set, it will be used instead
|
||||||
DIST_SUFFIX = "local"
|
DIST_SUFFIX = "RevvoX"
|
||||||
|
|
||||||
# Coprocessor firmware
|
# Coprocessor firmware
|
||||||
COPRO_OB_DATA = "scripts/ob.data"
|
COPRO_OB_DATA = "scripts/ob.data"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,7.3,,
|
Version,+,7.4,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
Header,+,applications/services/cli/cli_vcp.h,,
|
Header,+,applications/services/cli/cli_vcp.h,,
|
||||||
@@ -1948,12 +1948,19 @@ Function,+,nfc_device_save_shadow,_Bool,"NfcDevice*, const char*"
|
|||||||
Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*"
|
Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*"
|
||||||
Function,+,nfc_device_set_name,void,"NfcDevice*, const char*"
|
Function,+,nfc_device_set_name,void,"NfcDevice*, const char*"
|
||||||
Function,+,nfc_file_select,_Bool,NfcDevice*
|
Function,+,nfc_file_select,_Bool,NfcDevice*
|
||||||
|
Function,-,nfc_util_bytes2num,uint64_t,"uint8_t*, uint8_t"
|
||||||
|
Function,-,nfc_util_even_parity32,uint8_t,uint32_t
|
||||||
|
Function,-,nfc_util_num2bytes,void,"uint64_t, uint8_t, uint8_t*"
|
||||||
|
Function,-,nfc_util_odd_parity8,uint8_t,uint8_t
|
||||||
Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t"
|
Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t"
|
||||||
Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*"
|
Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*"
|
||||||
Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t"
|
Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t"
|
||||||
Function,-,nfca_signal_alloc,NfcaSignal*,
|
Function,-,nfca_signal_alloc,NfcaSignal*,
|
||||||
Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*"
|
Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*"
|
||||||
Function,-,nfca_signal_free,void,NfcaSignal*
|
Function,-,nfca_signal_free,void,NfcaSignal*
|
||||||
|
Function,-,nfcv_inventory,ReturnCode,uint8_t*
|
||||||
|
Function,-,nfcv_read_blocks,ReturnCode,"NfcVReader*, NfcVData*"
|
||||||
|
Function,-,nfcv_read_sysinfo,ReturnCode,NfcVData*
|
||||||
Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*"
|
Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*"
|
||||||
Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*"
|
Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*"
|
||||||
Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*"
|
Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*"
|
||||||
|
|||||||
|
@@ -50,6 +50,8 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, FuriString* format_
|
|||||||
furi_string_set(format_string, "Mifare Classic");
|
furi_string_set(format_string, "Mifare Classic");
|
||||||
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
||||||
furi_string_set(format_string, "Mifare DESFire");
|
furi_string_set(format_string, "Mifare DESFire");
|
||||||
|
} else if(dev->format == NfcDeviceSaveFormatSlixL) {
|
||||||
|
furi_string_set(format_string, "NXP SLIX-L");
|
||||||
} else {
|
} else {
|
||||||
furi_string_set(format_string, "Unknown");
|
furi_string_set(format_string, "Unknown");
|
||||||
}
|
}
|
||||||
@@ -85,6 +87,11 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, FuriString* format_st
|
|||||||
dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire;
|
dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if(furi_string_start_with_str(format_string, "NXP SLIX-L")) {
|
||||||
|
dev->format = NfcDeviceSaveFormatSlixL;
|
||||||
|
dev->dev_data.protocol = NfcDeviceProtocolSlixL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,7 +643,87 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
|
|||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leave for backward compatibility
|
static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool saved = false;
|
||||||
|
NfcVData* data = &dev->dev_data.nfcv_data;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "SLIX-L specific data")) break;
|
||||||
|
if(!flipper_format_write_hex(file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) break;
|
||||||
|
if(!flipper_format_write_hex(file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) break;
|
||||||
|
if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) break;
|
||||||
|
if(!flipper_format_write_hex(file, "DSFID", &(data->dsfid), 1)) break;
|
||||||
|
if(!flipper_format_write_hex(file, "AFI", &(data->afi), 1)) break;
|
||||||
|
if(!flipper_format_write_hex(file, "IC Reference", &(data->ic_ref), 1)) break;
|
||||||
|
if(!flipper_format_write_hex(file, "Block Count", &(data->block_num), 1)) break;
|
||||||
|
if(!flipper_format_write_hex(file, "Block Size", &(data->block_size), 1)) break;
|
||||||
|
if(!flipper_format_write_hex(file, "Data Content", data->data, data->block_num * data->block_size)) break;
|
||||||
|
saved = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool parsed = false;
|
||||||
|
NfcVData* data = &dev->dev_data.nfcv_data;
|
||||||
|
memset(data, 0, sizeof(NfcVData));
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy)))
|
||||||
|
break;
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy)))
|
||||||
|
break;
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
file, "Password EAS", data->key_eas, sizeof(data->key_eas)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(!flipper_format_read_hex(file, "DSFID", &(data->dsfid), 1)) break;
|
||||||
|
if(!flipper_format_read_hex(file, "AFI", &(data->afi), 1)) break;
|
||||||
|
if(!flipper_format_read_hex(file, "IC Reference", &(data->ic_ref), 1)) break;
|
||||||
|
if(!flipper_format_read_hex(file, "Block Count", &(data->block_num), 1)) break;
|
||||||
|
if(!flipper_format_read_hex(file, "Block Size", &(data->block_size), 1)) break;
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
file, "Data Content", data->data, data->block_num * data->block_size))
|
||||||
|
break;
|
||||||
|
|
||||||
|
parsed = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool saved = false;
|
||||||
|
EmvData* data = &dev->dev_data.emv_data;
|
||||||
|
uint32_t data_temp = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// Write Bank card specific data
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "Bank card specific data")) break;
|
||||||
|
if(!flipper_format_write_hex(file, "AID", data->aid, data->aid_len)) break;
|
||||||
|
if(!flipper_format_write_string_cstr(file, "Name", data->name)) break;
|
||||||
|
if(!flipper_format_write_hex(file, "Number", data->number, data->number_len)) break;
|
||||||
|
if(data->exp_mon) {
|
||||||
|
uint8_t exp_data[2] = {data->exp_mon, data->exp_year};
|
||||||
|
if(!flipper_format_write_hex(file, "Exp data", exp_data, sizeof(exp_data))) break;
|
||||||
|
}
|
||||||
|
if(data->country_code) {
|
||||||
|
data_temp = data->country_code;
|
||||||
|
if(!flipper_format_write_uint32(file, "Country code", &data_temp, 1)) break;
|
||||||
|
}
|
||||||
|
if(data->currency_code) {
|
||||||
|
data_temp = data->currency_code;
|
||||||
|
if(!flipper_format_write_uint32(file, "Currency code", &data_temp, 1)) break;
|
||||||
|
}
|
||||||
|
saved = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
EmvData* data = &dev->dev_data.emv_data;
|
EmvData* data = &dev->dev_data.emv_data;
|
||||||
@@ -1044,17 +1131,25 @@ static bool nfc_device_save_file(
|
|||||||
break;
|
break;
|
||||||
nfc_device_prepare_format_string(dev, temp_str);
|
nfc_device_prepare_format_string(dev, temp_str);
|
||||||
if(!flipper_format_write_string(file, "Device type", temp_str)) break;
|
if(!flipper_format_write_string(file, "Device type", temp_str)) break;
|
||||||
// Write UID, ATQA, SAK
|
// Write UID
|
||||||
if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
|
if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats except ISO15693"))
|
||||||
break;
|
break;
|
||||||
if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
|
if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
|
||||||
if(!flipper_format_write_hex(file, "ATQA", data->atqa, 2)) break;
|
|
||||||
if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break;
|
if(dev->format != NfcDeviceSaveFormatSlixL) {
|
||||||
|
// Write ATQA, SAK
|
||||||
|
if(!flipper_format_write_hex(file, "ATQA", data->atqa, 2)) break;
|
||||||
|
if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break;
|
||||||
|
}
|
||||||
// Save more data if necessary
|
// Save more data if necessary
|
||||||
if(dev->format == NfcDeviceSaveFormatMifareUl) {
|
if(dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||||
if(!nfc_device_save_mifare_ul_data(file, dev)) break;
|
if(!nfc_device_save_mifare_ul_data(file, dev)) break;
|
||||||
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
||||||
if(!nfc_device_save_mifare_df_data(file, dev)) break;
|
if(!nfc_device_save_mifare_df_data(file, dev)) break;
|
||||||
|
} else if(dev->format == NfcDeviceSaveFormatSlixL) {
|
||||||
|
if(!nfc_device_save_slix_l_data(file, dev)) break;
|
||||||
|
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
|
||||||
|
if(!nfc_device_save_bank_card_data(file, dev)) break;
|
||||||
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
|
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
// Save data
|
// Save data
|
||||||
if(!nfc_device_save_mifare_classic_data(file, dev)) break;
|
if(!nfc_device_save_mifare_classic_data(file, dev)) break;
|
||||||
@@ -1117,11 +1212,13 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
|
|||||||
if(!nfc_device_parse_format_string(dev, temp_str)) break;
|
if(!nfc_device_parse_format_string(dev, temp_str)) break;
|
||||||
// Read and parse UID, ATQA and SAK
|
// Read and parse UID, ATQA and SAK
|
||||||
if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break;
|
if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break;
|
||||||
if(!(data_cnt == 4 || data_cnt == 7)) break;
|
if(!(data_cnt == 4 || data_cnt == 7 || data_cnt == 8)) break;
|
||||||
data->uid_len = data_cnt;
|
data->uid_len = data_cnt;
|
||||||
if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
|
if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
|
||||||
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
|
if(dev->format != NfcDeviceSaveFormatSlixL) {
|
||||||
if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break;
|
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
|
||||||
|
if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break;
|
||||||
|
}
|
||||||
// Load CUID
|
// Load CUID
|
||||||
uint8_t* cuid_start = data->uid;
|
uint8_t* cuid_start = data->uid;
|
||||||
if(data->uid_len == 7) {
|
if(data->uid_len == 7) {
|
||||||
@@ -1136,6 +1233,8 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
|
|||||||
if(!nfc_device_load_mifare_classic_data(file, dev)) break;
|
if(!nfc_device_load_mifare_classic_data(file, dev)) break;
|
||||||
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
||||||
if(!nfc_device_load_mifare_df_data(file, dev)) break;
|
if(!nfc_device_load_mifare_df_data(file, dev)) break;
|
||||||
|
} else if(dev->format == NfcDeviceSaveFormatSlixL) {
|
||||||
|
if(!nfc_device_load_slix_l_data(file, dev)) break;
|
||||||
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
|
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
|
||||||
if(!nfc_device_load_bank_card_data(file, dev)) break;
|
if(!nfc_device_load_bank_card_data(file, dev)) break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <lib/nfc/protocols/mifare_ultralight.h>
|
#include <lib/nfc/protocols/mifare_ultralight.h>
|
||||||
#include <lib/nfc/protocols/mifare_classic.h>
|
#include <lib/nfc/protocols/mifare_classic.h>
|
||||||
#include <lib/nfc/protocols/mifare_desfire.h>
|
#include <lib/nfc/protocols/mifare_desfire.h>
|
||||||
|
#include <lib/nfc/protocols/nfcv.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -32,6 +33,7 @@ typedef enum {
|
|||||||
NfcDeviceProtocolMifareUl,
|
NfcDeviceProtocolMifareUl,
|
||||||
NfcDeviceProtocolMifareClassic,
|
NfcDeviceProtocolMifareClassic,
|
||||||
NfcDeviceProtocolMifareDesfire,
|
NfcDeviceProtocolMifareDesfire,
|
||||||
|
NfcDeviceProtocolSlixL,
|
||||||
} NfcProtocol;
|
} NfcProtocol;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -40,6 +42,7 @@ typedef enum {
|
|||||||
NfcDeviceSaveFormatMifareUl,
|
NfcDeviceSaveFormatMifareUl,
|
||||||
NfcDeviceSaveFormatMifareClassic,
|
NfcDeviceSaveFormatMifareClassic,
|
||||||
NfcDeviceSaveFormatMifareDesfire,
|
NfcDeviceSaveFormatMifareDesfire,
|
||||||
|
NfcDeviceSaveFormatSlixL,
|
||||||
} NfcDeviceSaveFormat;
|
} NfcDeviceSaveFormat;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -63,6 +66,7 @@ typedef struct {
|
|||||||
MfUltralightData mf_ul_data;
|
MfUltralightData mf_ul_data;
|
||||||
MfClassicData mf_classic_data;
|
MfClassicData mf_classic_data;
|
||||||
MifareDesfireData mf_df_data;
|
MifareDesfireData mf_df_data;
|
||||||
|
NfcVData nfcv_data;
|
||||||
};
|
};
|
||||||
FuriString* parsed_data;
|
FuriString* parsed_data;
|
||||||
} NfcDeviceData;
|
} NfcDeviceData;
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ int32_t nfc_worker_task(void* context) {
|
|||||||
nfc_worker_mf_classic_dict_attack(nfc_worker);
|
nfc_worker_mf_classic_dict_attack(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateAnalyzeReader) {
|
} else if(nfc_worker->state == NfcWorkerStateAnalyzeReader) {
|
||||||
nfc_worker_analyze_reader(nfc_worker);
|
nfc_worker_analyze_reader(nfc_worker);
|
||||||
|
} else if(nfc_worker->state == NfcWorkerStateNfcVReadAuth) {
|
||||||
|
nfc_worker_nfcv_unlock(nfc_worker);
|
||||||
}
|
}
|
||||||
furi_hal_nfc_sleep();
|
furi_hal_nfc_sleep();
|
||||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
||||||
@@ -116,6 +118,145 @@ int32_t nfc_worker_task(void* context) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
||||||
|
furi_assert(nfc_worker);
|
||||||
|
furi_assert(nfc_worker->callback);
|
||||||
|
|
||||||
|
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
|
||||||
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
|
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true);
|
||||||
|
reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
|
||||||
|
while(nfc_worker->state == NfcWorkerStateNfcVReadAuth) {
|
||||||
|
|
||||||
|
furi_hal_nfc_exit_sleep();
|
||||||
|
furi_hal_nfc_ll_txrx_on();
|
||||||
|
furi_hal_nfc_ll_poll();
|
||||||
|
if(furi_hal_nfc_ll_set_mode(FuriHalNfcModePollNfcv, FuriHalNfcBitrate26p48, FuriHalNfcBitrate26p48) != FuriHalNfcReturnOk) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_NFCV_POLLER);
|
||||||
|
furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_NFCV_POLLER);
|
||||||
|
furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc);
|
||||||
|
furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCV);
|
||||||
|
|
||||||
|
uint8_t rand[2];
|
||||||
|
|
||||||
|
furi_hal_console_printf("Detect presence\r\n");
|
||||||
|
ReturnCode ret = slix_l_get_random(rand);
|
||||||
|
|
||||||
|
if(ret == ERR_NONE) {
|
||||||
|
/* there is some chip, responding with a RAND */
|
||||||
|
furi_hal_console_printf(" Chip detected. In privacy?\r\n");
|
||||||
|
ret = nfcv_inventory(NULL);
|
||||||
|
|
||||||
|
if(ret == ERR_NONE) {
|
||||||
|
/* chip is also visible, so no action required */
|
||||||
|
furi_hal_console_printf(" => chip is already visible, wait for chip to disappear.\r\n");
|
||||||
|
nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context);
|
||||||
|
while(slix_l_get_random(NULL) == ERR_NONE) {
|
||||||
|
furi_delay_ms(100);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* chip is invisible, try to unlock */
|
||||||
|
furi_hal_console_printf(" chip is invisible, unlocking\r\n");
|
||||||
|
|
||||||
|
if(nfcv_data->auth_method == NfcVAuthMethodManual) {
|
||||||
|
uint32_t key = 0;
|
||||||
|
|
||||||
|
key |= nfc_worker->dev_data->nfcv_data.key_privacy[0] << 24;
|
||||||
|
key |= nfc_worker->dev_data->nfcv_data.key_privacy[1] << 16;
|
||||||
|
key |= nfc_worker->dev_data->nfcv_data.key_privacy[2] << 8;
|
||||||
|
key |= nfc_worker->dev_data->nfcv_data.key_privacy[3] << 0;
|
||||||
|
ret = slix_l_unlock(4, rand, key);
|
||||||
|
} else {
|
||||||
|
ret = slix_l_unlock(4, rand, 0x7FFD6E5B);
|
||||||
|
if(ret != ERR_NONE) {
|
||||||
|
/* main key failed, trying second one */
|
||||||
|
furi_hal_console_printf(" trying second key after resetting\r\n");
|
||||||
|
|
||||||
|
/* reset chip */
|
||||||
|
furi_hal_nfc_ll_txrx_off();
|
||||||
|
furi_delay_ms(20);
|
||||||
|
furi_hal_nfc_ll_txrx_on();
|
||||||
|
|
||||||
|
if(slix_l_get_random(rand) != ERR_NONE) {
|
||||||
|
furi_hal_console_printf(" reset failed\r\n");
|
||||||
|
}
|
||||||
|
ret = slix_l_unlock(4, rand, 0x0F0F0F0F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ret == ERR_NONE) {
|
||||||
|
/* unlock succesful */
|
||||||
|
furi_hal_console_printf(" => success, wait for chip to disappear.\r\n");
|
||||||
|
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
|
||||||
|
|
||||||
|
while(slix_l_get_random(NULL) == ERR_NONE) {
|
||||||
|
furi_delay_ms(100);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* unlock failed */
|
||||||
|
furi_hal_console_printf(" => failed, wait for chip to disappear.\r\n");
|
||||||
|
snprintf(nfcv_data->error, sizeof(nfcv_data->error), "Passwords not\naccepted");
|
||||||
|
nfc_worker->callback(NfcWorkerEventWrongCardDetected, nfc_worker->context);
|
||||||
|
|
||||||
|
/* reset chip */
|
||||||
|
furi_hal_nfc_ll_txrx_off();
|
||||||
|
furi_delay_ms(20);
|
||||||
|
furi_hal_nfc_ll_txrx_on();
|
||||||
|
|
||||||
|
/* wait for disappearing */
|
||||||
|
while(slix_l_get_random(NULL) == ERR_NONE) {
|
||||||
|
furi_delay_ms(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_hal_nfc_ll_txrx_off();
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
furi_delay_ms(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
reader_analyzer_stop(nfc_worker->reader_analyzer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_worker_read_slix_l(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
bool read_success = false;
|
||||||
|
NfcVReader reader = {};
|
||||||
|
NfcVData data = {};
|
||||||
|
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false);
|
||||||
|
reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break;
|
||||||
|
if(!slix_l_read_card(&reader, &data)) break;
|
||||||
|
// Copy data
|
||||||
|
nfc_worker->dev_data->nfcv_data = data;
|
||||||
|
read_success = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
reader_analyzer_stop(nfc_worker->reader_analyzer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_success;
|
||||||
|
}
|
||||||
|
|
||||||
static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
bool read_success = false;
|
bool read_success = false;
|
||||||
MfUltralightReader reader = {};
|
MfUltralightReader reader = {};
|
||||||
@@ -329,6 +470,27 @@ static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* t
|
|||||||
return card_read;
|
return card_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool nfc_worker_read_nfcv(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
furi_assert(nfc_worker);
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
|
||||||
|
bool card_read = false;
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
if(slix_l_check_card_type(nfc_data->uid[7], nfc_data->uid[6], nfc_data->uid[5])) {
|
||||||
|
FURI_LOG_I(TAG, "NXP SLIX-L detected");
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolSlixL;
|
||||||
|
card_read = nfc_worker_read_slix_l(nfc_worker, tx_rx);
|
||||||
|
} else {
|
||||||
|
FURI_LOG_I(TAG, "unknown detected");
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown;
|
||||||
|
card_read = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return card_read;
|
||||||
|
}
|
||||||
|
|
||||||
void nfc_worker_read(NfcWorker* nfc_worker) {
|
void nfc_worker_read(NfcWorker* nfc_worker) {
|
||||||
furi_assert(nfc_worker);
|
furi_assert(nfc_worker);
|
||||||
furi_assert(nfc_worker->callback);
|
furi_assert(nfc_worker->callback);
|
||||||
@@ -376,6 +538,14 @@ void nfc_worker_read(NfcWorker* nfc_worker) {
|
|||||||
event = NfcWorkerEventReadUidNfcF;
|
event = NfcWorkerEventReadUidNfcF;
|
||||||
break;
|
break;
|
||||||
} else if(nfc_data->type == FuriHalNfcTypeV) {
|
} else if(nfc_data->type == FuriHalNfcTypeV) {
|
||||||
|
FURI_LOG_I(TAG, "NfcV detected");
|
||||||
|
if(nfc_worker_read_nfcv(nfc_worker, &tx_rx)) {
|
||||||
|
FURI_LOG_I(TAG, "nfc_worker_read_nfcv success");
|
||||||
|
if(dev_data->protocol == NfcDeviceProtocolSlixL) {
|
||||||
|
event = NfcWorkerEventReadNfcV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
event = NfcWorkerEventReadUidNfcV;
|
event = NfcWorkerEventReadUidNfcV;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ typedef enum {
|
|||||||
NfcWorkerStateReadMfUltralightReadAuth,
|
NfcWorkerStateReadMfUltralightReadAuth,
|
||||||
NfcWorkerStateMfClassicDictAttack,
|
NfcWorkerStateMfClassicDictAttack,
|
||||||
NfcWorkerStateAnalyzeReader,
|
NfcWorkerStateAnalyzeReader,
|
||||||
|
NfcWorkerStateNfcVReadAuth,
|
||||||
// Debug
|
// Debug
|
||||||
NfcWorkerStateEmulateApdu,
|
NfcWorkerStateEmulateApdu,
|
||||||
NfcWorkerStateField,
|
NfcWorkerStateField,
|
||||||
@@ -40,6 +41,7 @@ typedef enum {
|
|||||||
NfcWorkerEventReadMfClassicDone,
|
NfcWorkerEventReadMfClassicDone,
|
||||||
NfcWorkerEventReadMfClassicLoadKeyCache,
|
NfcWorkerEventReadMfClassicLoadKeyCache,
|
||||||
NfcWorkerEventReadMfClassicDictAttackRequired,
|
NfcWorkerEventReadMfClassicDictAttackRequired,
|
||||||
|
NfcWorkerEventReadNfcV,
|
||||||
NfcWorkerEventReadBankCard,
|
NfcWorkerEventReadBankCard,
|
||||||
|
|
||||||
// Nfc worker common events
|
// Nfc worker common events
|
||||||
@@ -67,6 +69,7 @@ typedef enum {
|
|||||||
|
|
||||||
// Mifare Ultralight events
|
// Mifare Ultralight events
|
||||||
NfcWorkerEventMfUltralightPassKey,
|
NfcWorkerEventMfUltralightPassKey,
|
||||||
|
NfcWorkerEventNfcVPassKey, // NFC worker requesting manual key
|
||||||
|
|
||||||
} NfcWorkerEvent;
|
} NfcWorkerEvent;
|
||||||
|
|
||||||
@@ -86,3 +89,5 @@ void nfc_worker_start(
|
|||||||
void* context);
|
void* context);
|
||||||
|
|
||||||
void nfc_worker_stop(NfcWorker* nfc_worker);
|
void nfc_worker_stop(NfcWorker* nfc_worker);
|
||||||
|
void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
#include <lib/nfc/protocols/mifare_classic.h>
|
#include <lib/nfc/protocols/mifare_classic.h>
|
||||||
#include <lib/nfc/protocols/mifare_desfire.h>
|
#include <lib/nfc/protocols/mifare_desfire.h>
|
||||||
#include <lib/nfc/protocols/nfca.h>
|
#include <lib/nfc/protocols/nfca.h>
|
||||||
|
#include <lib/nfc/protocols/nfcv.h>
|
||||||
|
#include <lib/nfc/protocols/slix_l.h>
|
||||||
#include <lib/nfc/helpers/reader_analyzer.h>
|
#include <lib/nfc/helpers/reader_analyzer.h>
|
||||||
|
|
||||||
struct NfcWorker {
|
struct NfcWorker {
|
||||||
|
|||||||
79
lib/nfc/protocols/nfcv.c
Normal file
79
lib/nfc/protocols/nfcv.c
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#include <limits.h>
|
||||||
|
#include "nfcv.h"
|
||||||
|
#include "nfc_util.h"
|
||||||
|
#include <furi.h>
|
||||||
|
#include "furi_hal_nfc.h"
|
||||||
|
|
||||||
|
#define TAG "NfcV"
|
||||||
|
|
||||||
|
ReturnCode nfcv_inventory(uint8_t* uid) {
|
||||||
|
uint16_t received = 0;
|
||||||
|
rfalNfcvInventoryRes res;
|
||||||
|
|
||||||
|
/* TODO: needs proper abstraction via fury_hal(_ll)_* */
|
||||||
|
ReturnCode ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &res, &received);
|
||||||
|
|
||||||
|
if(ret == ERR_NONE) {
|
||||||
|
if(uid != NULL) {
|
||||||
|
memcpy(uid, res.UID, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnCode nfcv_read_blocks(
|
||||||
|
NfcVReader* reader,
|
||||||
|
NfcVData* data) {
|
||||||
|
|
||||||
|
reader->blocks_read = 0;
|
||||||
|
|
||||||
|
uint16_t received = 0;
|
||||||
|
for(size_t block = 0; block < data->block_num; block++) {
|
||||||
|
uint8_t rxBuf[32];
|
||||||
|
FURI_LOG_D(TAG, "Reading block %d", block);
|
||||||
|
|
||||||
|
ReturnCode ret = rfalNfcvPollerReadSingleBlock(
|
||||||
|
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block,
|
||||||
|
rxBuf, sizeof(rxBuf), &received);
|
||||||
|
|
||||||
|
if(ret != ERR_NONE) {
|
||||||
|
FURI_LOG_D(TAG, "failed to read: %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
memcpy(&(data->data[block * data->block_size]), &rxBuf[1], data->block_size);
|
||||||
|
FURI_LOG_D(TAG, " %02X %02X %02X %02X",
|
||||||
|
data->data[block * data->block_size + 0], data->data[block * data->block_size + 1],
|
||||||
|
data->data[block * data->block_size + 2], data->data[block * data->block_size + 3]);
|
||||||
|
|
||||||
|
reader->blocks_read++;
|
||||||
|
}
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Read %d blocks", reader->blocks_read);
|
||||||
|
|
||||||
|
return ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnCode nfcv_read_sysinfo(NfcVData* data) {
|
||||||
|
uint8_t rxBuf[32];
|
||||||
|
uint16_t received = 0;
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Read SystemInformation...");
|
||||||
|
|
||||||
|
ReturnCode ret = rfalNfcvPollerGetSystemInformation(
|
||||||
|
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL,
|
||||||
|
rxBuf, sizeof(rxBuf), &received);
|
||||||
|
|
||||||
|
if(ret == ERR_NONE) {
|
||||||
|
data->dsfid = rxBuf[10];
|
||||||
|
data->afi = rxBuf[11];
|
||||||
|
data->block_num = rxBuf[12] + 1;
|
||||||
|
data->block_size = rxBuf[13] + 1;
|
||||||
|
data->ic_ref = rxBuf[14];
|
||||||
|
FURI_LOG_D(TAG, " DSFID %d, AFI %d, Blocks %d, Size %d, IC Ref %d", data->dsfid, data->afi, data->block_num, data->block_size, data->ic_ref);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
FURI_LOG_D(TAG, "Failed: %d", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
54
lib/nfc/protocols/nfcv.h
Normal file
54
lib/nfc/protocols/nfcv.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <lib/digital_signal/digital_signal.h>
|
||||||
|
#include "nfc_util.h"
|
||||||
|
#include <furi_hal_nfc.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define NFCV_TOTAL_BLOCKS_MAX 32
|
||||||
|
#define NFCV_BLOCK_SIZE 4
|
||||||
|
#define NFCV_MAX_DUMP_SIZE (NFCV_BLOCK_SIZE*NFCV_TOTAL_BLOCKS_MAX)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcVAuthMethodManual,
|
||||||
|
NfcVAuthMethodTonieBox,
|
||||||
|
} NfcVAuthMethod;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcVTypeSlix,
|
||||||
|
NfcVTypeSlixS,
|
||||||
|
NfcVTypeSlixL,
|
||||||
|
NfcVTypeSlix2,
|
||||||
|
} NfcVType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NfcVType type;
|
||||||
|
NfcVAuthMethod auth_method;
|
||||||
|
bool auth_success;
|
||||||
|
|
||||||
|
uint8_t key_privacy[4];
|
||||||
|
uint8_t key_destroy[4];
|
||||||
|
uint8_t key_eas[4];
|
||||||
|
|
||||||
|
uint8_t dsfid;
|
||||||
|
uint8_t afi;
|
||||||
|
uint8_t ic_ref;
|
||||||
|
uint8_t block_num;
|
||||||
|
uint8_t block_size;
|
||||||
|
uint8_t data[NFCV_MAX_DUMP_SIZE];
|
||||||
|
|
||||||
|
char error[32];
|
||||||
|
} NfcVData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t blocks_to_read;
|
||||||
|
int16_t blocks_read;
|
||||||
|
} NfcVReader;
|
||||||
|
|
||||||
|
ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data);
|
||||||
|
ReturnCode nfcv_read_sysinfo(NfcVData* data);
|
||||||
|
ReturnCode nfcv_inventory(uint8_t* uid);
|
||||||
|
|
||||||
83
lib/nfc/protocols/slix_l.c
Normal file
83
lib/nfc/protocols/slix_l.c
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include "nfcv.h"
|
||||||
|
#include "slix_l.h"
|
||||||
|
#include "nfc_util.h"
|
||||||
|
#include <furi.h>
|
||||||
|
#include "furi_hal_nfc.h"
|
||||||
|
|
||||||
|
|
||||||
|
bool slix_l_check_card_type(uint8_t UID0, uint8_t UID1, uint8_t UID2) {
|
||||||
|
if((UID0 == 0xE0) && (UID1 == 0x04) && (UID2 == 0x03)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_l_read_card(
|
||||||
|
NfcVReader* reader,
|
||||||
|
NfcVData* data) {
|
||||||
|
furi_assert(reader);
|
||||||
|
furi_assert(data);
|
||||||
|
|
||||||
|
if(nfcv_read_sysinfo(data) != ERR_NONE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
reader->blocks_to_read = data->block_num;
|
||||||
|
return (nfcv_read_blocks(reader, data) == ERR_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnCode slix_l_get_random(uint8_t* rand) {
|
||||||
|
uint16_t received = 0;
|
||||||
|
uint8_t rxBuf[32];
|
||||||
|
|
||||||
|
ReturnCode ret = rfalNfcvPollerTransceiveReq(
|
||||||
|
ISO15693_CMD_NXP_GET_RANDOM_NUMBER,
|
||||||
|
RFAL_NFCV_REQ_FLAG_DEFAULT,
|
||||||
|
ISO15693_MANUFACTURER_NXP,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
rxBuf,
|
||||||
|
sizeof(rxBuf),
|
||||||
|
&received);
|
||||||
|
|
||||||
|
if(ret == ERR_NONE) {
|
||||||
|
if(received != 3) {
|
||||||
|
return ERR_PROTO;
|
||||||
|
}
|
||||||
|
if(rand != NULL) {
|
||||||
|
memcpy(rand, &rxBuf[1], 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnCode slix_l_unlock(uint32_t id, uint8_t* rand, uint32_t password) {
|
||||||
|
furi_assert(rand);
|
||||||
|
|
||||||
|
uint16_t received = 0;
|
||||||
|
uint8_t rxBuf[32];
|
||||||
|
uint8_t cmd_set_pass[] = {
|
||||||
|
id,
|
||||||
|
rand[0] ^ ((password>>0) & 0xFF),
|
||||||
|
rand[1] ^ ((password>>8) & 0xFF),
|
||||||
|
rand[0] ^ ((password>>16) & 0xFF),
|
||||||
|
rand[1] ^ ((password>>24) & 0xFF)
|
||||||
|
};
|
||||||
|
|
||||||
|
ReturnCode ret = rfalNfcvPollerTransceiveReq(
|
||||||
|
ISO15693_CMD_NXP_SET_PASSWORD,
|
||||||
|
RFAL_NFCV_REQ_FLAG_DATA_RATE,
|
||||||
|
ISO15693_MANUFACTURER_NXP,
|
||||||
|
NULL,
|
||||||
|
cmd_set_pass,
|
||||||
|
sizeof(cmd_set_pass),
|
||||||
|
rxBuf,
|
||||||
|
sizeof(rxBuf),
|
||||||
|
&received);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
18
lib/nfc/protocols/slix_l.h
Normal file
18
lib/nfc/protocols/slix_l.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "nfc_util.h"
|
||||||
|
#include <furi_hal_nfc.h>
|
||||||
|
|
||||||
|
#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2
|
||||||
|
#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3
|
||||||
|
#define ISO15693_MANUFACTURER_NXP 0x04
|
||||||
|
|
||||||
|
|
||||||
|
bool slix_l_check_card_type(uint8_t UID0, uint8_t UID1, uint8_t UID2);
|
||||||
|
bool slix_l_read_card(NfcVReader* reader, NfcVData* data);
|
||||||
|
|
||||||
|
ReturnCode slix_l_get_random(uint8_t* rand);
|
||||||
|
ReturnCode slix_l_unlock(uint32_t id, uint8_t* rand, uint32_t password);
|
||||||
|
|
||||||
Reference in New Issue
Block a user