mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-26 05:54:46 -07:00
Merge branch 'ISO15693' of https://github.com/g3gg0/flipperzero-firmware into xfw-dev
This commit is contained in:
@@ -12,4 +12,6 @@ enum NfcCustomEvent {
|
|||||||
NfcCustomEventDictAttackSkip,
|
NfcCustomEventDictAttackSkip,
|
||||||
NfcCustomEventRpcLoad,
|
NfcCustomEventRpcLoad,
|
||||||
NfcCustomEventRpcSessionClose,
|
NfcCustomEventRpcSessionClose,
|
||||||
|
NfcCustomEventUpdateLog,
|
||||||
|
NfcCustomEventSaveShadow,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -290,6 +290,11 @@ int32_t nfc_app(void* p) {
|
|||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||||
|
} else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate);
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||||
|
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ 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_unlock, NfcVUnlock)
|
||||||
|
ADD_SCENE(nfc, nfcv_emulate, NfcVEmulate)
|
||||||
|
ADD_SCENE(nfc, nfcv_sniff, NfcVSniff)
|
||||||
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)
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ void nfc_scene_delete_on_enter(void* context) {
|
|||||||
nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
|
nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
|
||||||
|
|
||||||
NfcProtocol protocol = nfc->dev->dev_data.protocol;
|
NfcProtocol protocol = nfc->dev->dev_data.protocol;
|
||||||
|
const char* nfc_type = "NFC-A";
|
||||||
|
|
||||||
if(protocol == NfcDeviceProtocolEMV) {
|
if(protocol == NfcDeviceProtocolEMV) {
|
||||||
furi_string_set(temp_str, "EMV bank card");
|
furi_string_set(temp_str, "EMV bank card");
|
||||||
} else if(protocol == NfcDeviceProtocolMifareUl) {
|
} else if(protocol == NfcDeviceProtocolMifareUl) {
|
||||||
@@ -39,12 +41,15 @@ void nfc_scene_delete_on_enter(void* context) {
|
|||||||
furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type));
|
furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type));
|
||||||
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
|
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
furi_string_set(temp_str, "MIFARE DESFire");
|
furi_string_set(temp_str, "MIFARE DESFire");
|
||||||
|
} else if(protocol == NfcDeviceProtocolNfcV) {
|
||||||
|
furi_string_set(temp_str, "ISO15693 tag");
|
||||||
|
nfc_type = "NFC-V";
|
||||||
} else {
|
} else {
|
||||||
furi_string_set(temp_str, "Unknown ISO tag");
|
furi_string_set(temp_str, "Unknown ISO tag");
|
||||||
}
|
}
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
|
nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
|
||||||
widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A");
|
widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, nfc_type);
|
||||||
furi_string_free(temp_str);
|
furi_string_free(temp_str);
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ enum SubmenuIndex {
|
|||||||
SubmenuIndexReadCardType,
|
SubmenuIndexReadCardType,
|
||||||
SubmenuIndexMfClassicKeys,
|
SubmenuIndexMfClassicKeys,
|
||||||
SubmenuIndexMfUltralightUnlock,
|
SubmenuIndexMfUltralightUnlock,
|
||||||
|
SubmenuIndexNfcVUnlock,
|
||||||
|
SubmenuIndexNfcVSniff,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
|
||||||
@@ -34,6 +36,18 @@ 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);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Listen NfcV Reader",
|
||||||
|
SubmenuIndexNfcVSniff,
|
||||||
|
nfc_scene_extra_actions_submenu_callback,
|
||||||
|
nfc);
|
||||||
submenu_set_selected_item(
|
submenu_set_selected_item(
|
||||||
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions));
|
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions));
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
@@ -58,6 +72,12 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexNfcVUnlock) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlockMenu);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexNfcVSniff) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVSniff);
|
||||||
|
consumed = true;
|
||||||
}
|
}
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,17 @@ void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType typ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t nfc_scene_nfc_data_info_get_key(uint8_t* data) {
|
||||||
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
for(uint32_t pos = 0; pos < 4; pos++) {
|
||||||
|
value <<= 8;
|
||||||
|
value |= data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
void nfc_scene_nfc_data_info_on_enter(void* context) {
|
void nfc_scene_nfc_data_info_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
Widget* widget = nfc->widget;
|
Widget* widget = nfc->widget;
|
||||||
@@ -15,7 +26,8 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
|
|||||||
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 == NfcDeviceProtocolMifareClassic)) {
|
(protocol == NfcDeviceProtocolMifareClassic) ||
|
||||||
|
(protocol == NfcDeviceProtocolNfcV)) {
|
||||||
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;
|
||||||
@@ -41,19 +53,165 @@ 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 == NfcDeviceProtocolNfcV) {
|
||||||
|
switch(dev_data->nfcv_data.sub_type) {
|
||||||
|
case NfcVTypePlain:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixS:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-S\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixL:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-L\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix2:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX2\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
} 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
|
||||||
|
if(protocol == NfcDeviceProtocolNfcV) {
|
||||||
|
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
|
||||||
|
|
||||||
|
furi_string_cat_printf(temp_str, "UID:\n");
|
||||||
|
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 %s\n",
|
||||||
|
nfcv_data->dsfid,
|
||||||
|
(nfcv_data->security_status[0] & NfcVLockBitDsfid) ? "(locked)" : "");
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
"AFI: %02X %s\n",
|
||||||
|
nfcv_data->afi,
|
||||||
|
(nfcv_data->security_status[0] & NfcVLockBitAfi) ? "(locked)" : "");
|
||||||
|
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);
|
||||||
|
|
||||||
|
int maxBlocks = nfcv_data->block_num;
|
||||||
|
if(maxBlocks > 32) {
|
||||||
|
maxBlocks = 32;
|
||||||
|
furi_string_cat_printf(temp_str, "(truncated to %d blocks)\n", maxBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int block = 0; block < maxBlocks; block++) {
|
||||||
|
const char* status = (nfcv_data->security_status[block] & 0x01) ? "(lck)" : "";
|
||||||
|
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, " %s\n", status);
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(temp_str, "\n");
|
||||||
|
|
||||||
|
switch(dev_data->nfcv_data.sub_type) {
|
||||||
|
case NfcVTypePlain:
|
||||||
|
furi_string_cat_printf(temp_str, "Type: Plain\n");
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix:
|
||||||
|
furi_string_cat_printf(temp_str, "Type: SLIX\n");
|
||||||
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" EAS %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixS:
|
||||||
|
furi_string_cat_printf(temp_str, "Type: SLIX-S\n");
|
||||||
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Read %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Write %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Privacy %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Destroy %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" EAS %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixL:
|
||||||
|
furi_string_cat_printf(temp_str, "Type: SLIX-L\n");
|
||||||
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Privacy %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Destroy %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" EAS %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix2:
|
||||||
|
furi_string_cat_printf(temp_str, "Type: SLIX2\n");
|
||||||
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Read %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Write %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Privacy %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" Destroy %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
|
||||||
|
furi_string_cat_printf(
|
||||||
|
temp_str,
|
||||||
|
" EAS %08lX\n",
|
||||||
|
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3';
|
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, "ISO 14443-%c (NFC-A)\n", iso_type);
|
||||||
furi_string_cat_printf(temp_str, "UID:");
|
furi_string_cat_printf(temp_str, "UID:");
|
||||||
for(size_t i = 0; i < nfc_data->uid_len; 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, " %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, "\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, " SAK: %02X", nfc_data->sak);
|
||||||
|
}
|
||||||
|
|
||||||
// Set application specific data
|
// Set application specific data
|
||||||
if(protocol == NfcDeviceProtocolMifareDesfire) {
|
if(protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
@@ -140,6 +298,9 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else if(protocol == NfcDeviceProtocolMifareClassic) {
|
} else if(protocol == NfcDeviceProtocolMifareClassic) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
} else if(protocol == NfcDeviceProtocolNfcV) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu);
|
||||||
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
164
applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c
Normal file
164
applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (200)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NfcSceneNfcVEmulateStateWidget,
|
||||||
|
NfcSceneNfcVEmulateStateTextBox,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_emulate_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
|
UNUSED(event);
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
switch(event) {
|
||||||
|
case NfcWorkerEventNfcVCommandExecuted:
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventUpdateLog);
|
||||||
|
break;
|
||||||
|
case NfcWorkerEventNfcVContentChanged:
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventSaveShadow);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_emulate_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_emulate_textbox_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfc_scene_nfcv_emulate_widget_config(Nfc* nfc, bool data_received) {
|
||||||
|
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||||
|
Widget* widget = nfc->widget;
|
||||||
|
widget_reset(widget);
|
||||||
|
FuriString* info_str;
|
||||||
|
info_str = furi_string_alloc();
|
||||||
|
|
||||||
|
widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Emulating NfcV");
|
||||||
|
if(strcmp(nfc->dev->dev_name, "")) {
|
||||||
|
furi_string_printf(info_str, "%s", nfc->dev->dev_name);
|
||||||
|
} else {
|
||||||
|
for(uint8_t i = 0; i < data->uid_len; i++) {
|
||||||
|
furi_string_cat_printf(info_str, "%02X ", data->uid[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
furi_string_trim(info_str);
|
||||||
|
widget_add_text_box_element(
|
||||||
|
widget, 56, 43, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true);
|
||||||
|
furi_string_free(info_str);
|
||||||
|
if(data_received) {
|
||||||
|
widget_add_button_element(
|
||||||
|
widget, GuiButtonTypeCenter, "Log", nfc_scene_nfcv_emulate_widget_callback, nfc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_emulate_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Setup Widget
|
||||||
|
nfc_scene_nfcv_emulate_widget_config(nfc, false);
|
||||||
|
// Setup TextBox
|
||||||
|
TextBox* text_box = nfc->text_box;
|
||||||
|
text_box_set_font(text_box, TextBoxFontHex);
|
||||||
|
text_box_set_focus(text_box, TextBoxFocusEnd);
|
||||||
|
text_box_set_text(text_box, "");
|
||||||
|
furi_string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
|
// Set Widget state and view
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
// Start worker
|
||||||
|
memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker,
|
||||||
|
NfcWorkerStateNfcVEmulate,
|
||||||
|
&nfc->dev->dev_data,
|
||||||
|
nfc_scene_nfcv_emulate_worker_callback,
|
||||||
|
nfc);
|
||||||
|
|
||||||
|
nfc_blink_emulate_start(nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
|
||||||
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVEmulate);
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcCustomEventUpdateLog) {
|
||||||
|
// Add data button to widget if data is received for the first time
|
||||||
|
if(strlen(nfcv_data->last_command) > 0) {
|
||||||
|
if(!furi_string_size(nfc->text_box_store)) {
|
||||||
|
nfc_scene_nfcv_emulate_widget_config(nfc, true);
|
||||||
|
}
|
||||||
|
/* use the last n bytes from the log so there's enough space for the new log entry */
|
||||||
|
size_t maxSize =
|
||||||
|
NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1);
|
||||||
|
if(furi_string_size(nfc->text_box_store) >= maxSize) {
|
||||||
|
furi_string_right(nfc->text_box_store, (strlen(nfcv_data->last_command) + 1));
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(nfc->text_box_store, "%s", nfcv_data->last_command);
|
||||||
|
furi_string_push_back(nfc->text_box_store, '\n');
|
||||||
|
text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store));
|
||||||
|
|
||||||
|
/* clear previously logged command */
|
||||||
|
strcpy(nfcv_data->last_command, "");
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventSaveShadow) {
|
||||||
|
if(furi_string_size(nfc->dev->load_path)) {
|
||||||
|
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcVEmulateStateWidget) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateTextBox);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcVEmulateStateTextBox) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
if(state == NfcSceneNfcVEmulateStateTextBox) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_emulate_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
widget_reset(nfc->widget);
|
||||||
|
text_box_reset(nfc->text_box);
|
||||||
|
furi_string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
|
nfc_blink_stop(nfc);
|
||||||
|
}
|
||||||
48
applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c
Normal file
48
applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_key_input_byte_input_callback(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
|
memcpy(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, NfcSceneNfcVUnlock);
|
||||||
|
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, "");
|
||||||
|
}
|
||||||
63
applications/main/nfc/scenes/nfc_scene_nfcv_menu.c
Normal file
63
applications/main/nfc/scenes/nfc_scene_nfcv_menu.c
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexSave,
|
||||||
|
SubmenuIndexEmulate,
|
||||||
|
};
|
||||||
|
|
||||||
|
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, "Emulate", SubmenuIndexEmulate, nfc_scene_nfcv_menu_submenu_callback, nfc);
|
||||||
|
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 = NfcDeviceSaveFormatNfcV;
|
||||||
|
// Clear device name
|
||||||
|
nfc_device_set_name(nfc->dev, "");
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexEmulate) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate);
|
||||||
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcAddEmulate);
|
||||||
|
} else {
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
155
applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c
Normal file
155
applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (800)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NfcSceneNfcVSniffStateWidget,
|
||||||
|
NfcSceneNfcVSniffStateTextBox,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_sniff_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
|
UNUSED(event);
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
switch(event) {
|
||||||
|
case NfcWorkerEventNfcVCommandExecuted:
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventUpdateLog);
|
||||||
|
break;
|
||||||
|
case NfcWorkerEventNfcVContentChanged:
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventSaveShadow);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_sniff_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_sniff_textbox_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfc_scene_nfcv_sniff_widget_config(Nfc* nfc, bool data_received) {
|
||||||
|
Widget* widget = nfc->widget;
|
||||||
|
widget_reset(widget);
|
||||||
|
FuriString* info_str;
|
||||||
|
info_str = furi_string_alloc();
|
||||||
|
|
||||||
|
widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||||
|
widget_add_string_element(widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Listen NfcV");
|
||||||
|
furi_string_trim(info_str);
|
||||||
|
widget_add_text_box_element(
|
||||||
|
widget, 56, 43, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true);
|
||||||
|
furi_string_free(info_str);
|
||||||
|
if(data_received) {
|
||||||
|
widget_add_button_element(
|
||||||
|
widget, GuiButtonTypeCenter, "Log", nfc_scene_nfcv_sniff_widget_callback, nfc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_sniff_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Setup Widget
|
||||||
|
nfc_scene_nfcv_sniff_widget_config(nfc, false);
|
||||||
|
// Setup TextBox
|
||||||
|
TextBox* text_box = nfc->text_box;
|
||||||
|
text_box_set_font(text_box, TextBoxFontHex);
|
||||||
|
text_box_set_focus(text_box, TextBoxFocusEnd);
|
||||||
|
text_box_set_text(text_box, "");
|
||||||
|
furi_string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
|
// Set Widget state and view
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
// Start worker
|
||||||
|
memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker,
|
||||||
|
NfcWorkerStateNfcVSniff,
|
||||||
|
&nfc->dev->dev_data,
|
||||||
|
nfc_scene_nfcv_sniff_worker_callback,
|
||||||
|
nfc);
|
||||||
|
|
||||||
|
nfc_blink_emulate_start(nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_sniff_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
|
||||||
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVSniff);
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcCustomEventUpdateLog) {
|
||||||
|
// Add data button to widget if data is received for the first time
|
||||||
|
if(strlen(nfcv_data->last_command) > 0) {
|
||||||
|
if(!furi_string_size(nfc->text_box_store)) {
|
||||||
|
nfc_scene_nfcv_sniff_widget_config(nfc, true);
|
||||||
|
}
|
||||||
|
/* use the last n bytes from the log so there's enough space for the new log entry */
|
||||||
|
size_t maxSize =
|
||||||
|
NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1);
|
||||||
|
if(furi_string_size(nfc->text_box_store) >= maxSize) {
|
||||||
|
furi_string_right(nfc->text_box_store, (strlen(nfcv_data->last_command) + 1));
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(nfc->text_box_store, "%s", nfcv_data->last_command);
|
||||||
|
furi_string_push_back(nfc->text_box_store, '\n');
|
||||||
|
text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store));
|
||||||
|
|
||||||
|
/* clear previously logged command */
|
||||||
|
strcpy(nfcv_data->last_command, "");
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventSaveShadow) {
|
||||||
|
if(furi_string_size(nfc->dev->load_path)) {
|
||||||
|
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcVSniffStateWidget) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateTextBox);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcVSniffStateTextBox) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
if(state == NfcSceneNfcVSniffStateTextBox) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_sniff_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
widget_reset(nfc->widget);
|
||||||
|
text_box_reset(nfc->text_box);
|
||||||
|
furi_string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
|
nfc_blink_stop(nfc);
|
||||||
|
}
|
||||||
154
applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c
Normal file
154
applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcSceneNfcVUnlockStateIdle,
|
||||||
|
NfcSceneNfcVUnlockStateDetecting,
|
||||||
|
NfcSceneNfcVUnlockStateUnlocked,
|
||||||
|
NfcSceneNfcVUnlockStateAlreadyUnlocked,
|
||||||
|
NfcSceneNfcVUnlockStateNotSupportedCard,
|
||||||
|
} NfcSceneNfcVUnlockState;
|
||||||
|
|
||||||
|
static bool nfc_scene_nfcv_unlock_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
|
if(event == NfcWorkerEventNfcVPassKey) {
|
||||||
|
memcpy(data->key_privacy, nfc->byte_input_store, 4);
|
||||||
|
} else {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_popup_callback(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_set_state(Nfc* nfc, NfcSceneNfcVUnlockState state) {
|
||||||
|
FuriHalNfcDevData* nfc_data = &(nfc->dev->dev_data.nfc_data);
|
||||||
|
NfcVData* nfcv_data = &(nfc->dev->dev_data.nfcv_data);
|
||||||
|
|
||||||
|
uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVUnlock);
|
||||||
|
if(curr_state != state) {
|
||||||
|
Popup* popup = nfc->popup;
|
||||||
|
if(state == NfcSceneNfcVUnlockStateDetecting) {
|
||||||
|
popup_reset(popup);
|
||||||
|
popup_set_text(
|
||||||
|
popup, "Put figurine on\nFlipper's back", 97, 24, AlignCenter, AlignTop);
|
||||||
|
popup_set_icon(popup, 0, 8, &I_NFC_manual_60x50);
|
||||||
|
} else if(state == NfcSceneNfcVUnlockStateUnlocked) {
|
||||||
|
popup_reset(popup);
|
||||||
|
|
||||||
|
if(nfc_worker_get_state(nfc->worker) == NfcWorkerStateNfcVUnlockAndSave) {
|
||||||
|
snprintf(
|
||||||
|
nfc->dev->dev_name,
|
||||||
|
sizeof(nfc->dev->dev_name),
|
||||||
|
"SLIX_%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||||
|
nfc_data->uid[0],
|
||||||
|
nfc_data->uid[1],
|
||||||
|
nfc_data->uid[2],
|
||||||
|
nfc_data->uid[3],
|
||||||
|
nfc_data->uid[4],
|
||||||
|
nfc_data->uid[5],
|
||||||
|
nfc_data->uid[6],
|
||||||
|
nfc_data->uid[7]);
|
||||||
|
|
||||||
|
nfc->dev->format = NfcDeviceSaveFormatNfcV;
|
||||||
|
|
||||||
|
if(nfc_save_file(nfc)) {
|
||||||
|
popup_set_header(popup, "Successfully\nsaved", 94, 3, AlignCenter, AlignTop);
|
||||||
|
} else {
|
||||||
|
popup_set_header(
|
||||||
|
popup, "Unlocked but\nsave failed!", 94, 3, AlignCenter, AlignTop);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
popup_set_header(popup, "Successfully\nunlocked", 94, 3, AlignCenter, AlignTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
notification_message(nfc->notifications, &sequence_single_vibro);
|
||||||
|
//notification_message(nfc->notifications, &sequence_success);
|
||||||
|
|
||||||
|
popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57);
|
||||||
|
popup_set_context(popup, nfc);
|
||||||
|
popup_set_callback(popup, nfc_scene_nfcv_unlock_popup_callback);
|
||||||
|
popup_set_timeout(popup, 1500);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
|
} else if(state == NfcSceneNfcVUnlockStateAlreadyUnlocked) {
|
||||||
|
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_unlock_popup_callback);
|
||||||
|
popup_set_timeout(popup, 1500);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
} else if(state == NfcSceneNfcVUnlockStateNotSupportedCard) {
|
||||||
|
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, NfcSceneNfcVUnlock, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
nfc_device_clear(nfc->dev);
|
||||||
|
// Setup view
|
||||||
|
nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateDetecting);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
|
||||||
|
// Start worker
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker,
|
||||||
|
NfcWorkerStateNfcVUnlockAndSave,
|
||||||
|
&nfc->dev->dev_data,
|
||||||
|
nfc_scene_nfcv_unlock_worker_callback,
|
||||||
|
nfc);
|
||||||
|
|
||||||
|
nfc_blink_read_start(nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_nfcv_unlock_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcWorkerEventCardDetected) {
|
||||||
|
nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateUnlocked);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventAborted) {
|
||||||
|
nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateAlreadyUnlocked);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventNoCardDetected) {
|
||||||
|
nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateDetecting);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventWrongCardDetected) {
|
||||||
|
nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateNotSupportedCard);
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneNfcVUnlockMenu);
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_nfcv_unlock_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, NfcSceneNfcVUnlock, NfcSceneNfcVUnlockStateIdle);
|
||||||
|
}
|
||||||
60
applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c
Normal file
60
applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#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, NfcSceneNfcVUnlock);
|
||||||
|
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);
|
||||||
// Set unlock password input to 0xFFFFFFFF only on fresh read
|
// Set unlock password input to 0xFFFFFFFF only on fresh read
|
||||||
|
|||||||
@@ -56,6 +56,13 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
|||||||
&nfc->dev->dev_data,
|
&nfc->dev->dev_data,
|
||||||
nfc_scene_rpc_emulate_callback,
|
nfc_scene_rpc_emulate_callback,
|
||||||
nfc);
|
nfc);
|
||||||
|
} else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) {
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker,
|
||||||
|
NfcWorkerStateNfcVEmulate,
|
||||||
|
&nfc->dev->dev_data,
|
||||||
|
nfc_scene_rpc_emulate_callback,
|
||||||
|
nfc);
|
||||||
} else {
|
} else {
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc);
|
nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc);
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
} else if(
|
} else if(
|
||||||
nfc->dev->format == NfcDeviceSaveFormatMifareUl ||
|
nfc->dev->format == NfcDeviceSaveFormatMifareUl ||
|
||||||
|
nfc->dev->format == NfcDeviceSaveFormatNfcV ||
|
||||||
nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc);
|
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc);
|
||||||
@@ -117,6 +118,8 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||||
|
} else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2147,12 +2147,25 @@ 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,"const 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_parity,void,"const uint8_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_emu_deinit,void,NfcVData*
|
||||||
|
Function,+,nfcv_emu_init,void,"FuriHalNfcDevData*, NfcVData*"
|
||||||
|
Function,+,nfcv_emu_loop,_Bool,"FuriHalNfcTxRxContext*, FuriHalNfcDevData*, NfcVData*, uint32_t"
|
||||||
|
Function,+,nfcv_emu_send,void,"FuriHalNfcTxRxContext*, NfcVData*, uint8_t*, uint8_t, NfcVSendFlags, uint32_t"
|
||||||
|
Function,-,nfcv_inventory,ReturnCode,uint8_t*
|
||||||
|
Function,-,nfcv_read_blocks,ReturnCode,"NfcVReader*, NfcVData*"
|
||||||
|
Function,-,nfcv_read_card,_Bool,"NfcVReader*, FuriHalNfcDevData*, NfcVData*"
|
||||||
|
Function,-,nfcv_read_sysinfo,ReturnCode,"FuriHalNfcDevData*, NfcVData*"
|
||||||
Function,-,nice_flors_get_custom_btn,uint8_t,
|
Function,-,nice_flors_get_custom_btn,uint8_t,
|
||||||
Function,-,nice_flors_get_original_btn,uint8_t,
|
Function,-,nice_flors_get_original_btn,uint8_t,
|
||||||
Function,+,nice_flors_reset_original_btn,void,
|
Function,+,nice_flors_reset_original_btn,void,
|
||||||
|
|||||||
|
@@ -58,6 +58,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 == NfcDeviceSaveFormatNfcV) {
|
||||||
|
furi_string_set(format_string, "ISO15693");
|
||||||
} else {
|
} else {
|
||||||
furi_string_set(format_string, "Unknown");
|
furi_string_set(format_string, "Unknown");
|
||||||
}
|
}
|
||||||
@@ -93,6 +95,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, "ISO15693")) {
|
||||||
|
dev->format = NfcDeviceSaveFormatNfcV;
|
||||||
|
dev->dev_data.protocol = NfcDeviceProtocolNfcV;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,6 +657,298 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
|
|||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool nfc_device_save_slix_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool saved = false;
|
||||||
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "SLIX specific data")) break;
|
||||||
|
if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas)))
|
||||||
|
break;
|
||||||
|
saved = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_device_load_slix_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool parsed = false;
|
||||||
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
memset(data, 0, sizeof(NfcVSlixData));
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!flipper_format_read_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
parsed = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool saved = false;
|
||||||
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "SLIX-S specific data")) break;
|
||||||
|
if(!flipper_format_write_hex(file, "Password Read", data->key_read, sizeof(data->key_read)))
|
||||||
|
break;
|
||||||
|
if(!flipper_format_write_hex(
|
||||||
|
file, "Password Write", data->key_write, sizeof(data->key_write)))
|
||||||
|
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_bool(file, "Privacy Mode", &data->privacy, 1)) break;
|
||||||
|
saved = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool parsed = false;
|
||||||
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
memset(data, 0, sizeof(NfcVSlixData));
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!flipper_format_read_hex(file, "Password Read", data->key_read, sizeof(data->key_read)))
|
||||||
|
break;
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
file, "Password Write", data->key_write, sizeof(data->key_write)))
|
||||||
|
break;
|
||||||
|
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_bool(file, "Privacy Mode", &data->privacy, 1)) break;
|
||||||
|
|
||||||
|
parsed = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool saved = false;
|
||||||
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
|
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_bool(file, "Privacy Mode", &data->privacy, 1)) break;
|
||||||
|
saved = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool parsed = false;
|
||||||
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
memset(data, 0, sizeof(NfcVSlixData));
|
||||||
|
|
||||||
|
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_bool(file, "Privacy Mode", &data->privacy, 1)) break;
|
||||||
|
|
||||||
|
parsed = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool saved = false;
|
||||||
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "SLIX2 specific data")) break;
|
||||||
|
if(!flipper_format_write_hex(file, "Password Read", data->key_read, sizeof(data->key_read)))
|
||||||
|
break;
|
||||||
|
if(!flipper_format_write_hex(
|
||||||
|
file, "Password Write", data->key_write, sizeof(data->key_write)))
|
||||||
|
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_bool(file, "Privacy Mode", &data->privacy, 1)) break;
|
||||||
|
saved = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_device_load_slix2_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool parsed = false;
|
||||||
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
memset(data, 0, sizeof(NfcVSlixData));
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!flipper_format_read_hex(file, "Password Read", data->key_read, sizeof(data->key_read)))
|
||||||
|
break;
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
file, "Password Write", data->key_write, sizeof(data->key_write)))
|
||||||
|
break;
|
||||||
|
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_bool(file, "Privacy Mode", &data->privacy, 1)) break;
|
||||||
|
|
||||||
|
parsed = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool saved = false;
|
||||||
|
NfcVData* data = &dev->dev_data.nfcv_data;
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint32_t temp_uint32 = 0;
|
||||||
|
uint8_t temp_uint8 = 0;
|
||||||
|
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "Data Storage Format Identifier")) break;
|
||||||
|
if(!flipper_format_write_hex(file, "DSFID", &(data->dsfid), 1)) break;
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "Application Family Identifier")) 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;
|
||||||
|
temp_uint32 = data->block_num;
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "Number of memory blocks, usually 0 to 256"))
|
||||||
|
break;
|
||||||
|
if(!flipper_format_write_uint32(file, "Block Count", &temp_uint32, 1)) break;
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "Size of a single memory block, usually 4"))
|
||||||
|
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;
|
||||||
|
if(!flipper_format_write_comment_cstr(
|
||||||
|
file, "First byte: DSFID (0x01) / AFI (0x02) lock info, others: block lock info"))
|
||||||
|
break;
|
||||||
|
if(!flipper_format_write_hex(
|
||||||
|
file, "Security Status", data->security_status, 1 + data->block_num))
|
||||||
|
break;
|
||||||
|
if(!flipper_format_write_comment_cstr(
|
||||||
|
file,
|
||||||
|
"Subtype of this card (0 = ISO15693, 1 = SLIX, 2 = SLIX-S, 3 = SLIX-L, 4 = SLIX2)"))
|
||||||
|
break;
|
||||||
|
temp_uint8 = (uint8_t)data->sub_type;
|
||||||
|
if(!flipper_format_write_hex(file, "Subtype", &temp_uint8, 1)) break;
|
||||||
|
|
||||||
|
switch(data->sub_type) {
|
||||||
|
case NfcVTypePlain:
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "End of ISO15693 parameters")) break;
|
||||||
|
saved = true;
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix:
|
||||||
|
saved = nfc_device_save_slix_data(file, dev);
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixS:
|
||||||
|
saved = nfc_device_save_slix_s_data(file, dev);
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixL:
|
||||||
|
saved = nfc_device_save_slix_l_data(file, dev);
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix2:
|
||||||
|
saved = nfc_device_save_slix2_data(file, dev);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
|
bool parsed = false;
|
||||||
|
NfcVData* data = &dev->dev_data.nfcv_data;
|
||||||
|
|
||||||
|
memset(data, 0x00, sizeof(NfcVData));
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint32_t temp_uint32 = 0;
|
||||||
|
uint8_t temp_value = 0;
|
||||||
|
|
||||||
|
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_uint32(file, "Block Count", &temp_uint32, 1)) break;
|
||||||
|
data->block_num = temp_uint32;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* optional, as added later */
|
||||||
|
if(flipper_format_key_exist(file, "Security Status")) {
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
file, "Security Status", data->security_status, 1 + data->block_num))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!flipper_format_read_hex(file, "Subtype", &temp_value, 1)) break;
|
||||||
|
data->sub_type = temp_value;
|
||||||
|
|
||||||
|
switch(data->sub_type) {
|
||||||
|
case NfcVTypePlain:
|
||||||
|
parsed = true;
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix:
|
||||||
|
parsed = nfc_device_load_slix_data(file, dev);
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixS:
|
||||||
|
parsed = nfc_device_load_slix_s_data(file, dev);
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlixL:
|
||||||
|
parsed = nfc_device_load_slix_l_data(file, dev);
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix2:
|
||||||
|
parsed = nfc_device_load_slix2_data(file, dev);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool saved = false;
|
bool saved = false;
|
||||||
EmvData* data = &dev->dev_data.emv_data;
|
EmvData* data = &dev->dev_data.emv_data;
|
||||||
@@ -1097,7 +1396,7 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
|
|||||||
if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break;
|
if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break;
|
||||||
// Write nfc device type
|
// Write nfc device type
|
||||||
if(!flipper_format_write_comment_cstr(
|
if(!flipper_format_write_comment_cstr(
|
||||||
file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic, Bank card"))
|
file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic, Bank card or ISO15693"))
|
||||||
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;
|
||||||
@@ -1105,15 +1404,23 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
|
|||||||
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"))
|
||||||
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(dev->format != NfcDeviceSaveFormatNfcV) {
|
||||||
|
// Write ATQA, SAK
|
||||||
|
if(!flipper_format_write_comment_cstr(file, "ISO14443 specific fields")) break;
|
||||||
// Save ATQA in MSB order for correct companion apps display
|
// Save ATQA in MSB order for correct companion apps display
|
||||||
uint8_t atqa[2] = {data->atqa[1], data->atqa[0]};
|
uint8_t atqa[2] = {data->atqa[1], data->atqa[0]};
|
||||||
if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break;
|
if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break;
|
||||||
if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) 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 == NfcDeviceSaveFormatNfcV) {
|
||||||
|
if(!nfc_device_save_nfcv_data(file, dev)) break;
|
||||||
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
|
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
|
||||||
if(!nfc_device_save_bank_card_data(file, dev)) break;
|
if(!nfc_device_save_bank_card_data(file, dev)) break;
|
||||||
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
|
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
@@ -1190,9 +1497,10 @@ 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(dev->format != NfcDeviceSaveFormatNfcV) {
|
||||||
if(version == version_with_lsb_atqa) {
|
if(version == version_with_lsb_atqa) {
|
||||||
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
|
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
|
||||||
} else {
|
} else {
|
||||||
@@ -1202,6 +1510,7 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
|
|||||||
data->atqa[1] = atqa[0];
|
data->atqa[1] = atqa[0];
|
||||||
}
|
}
|
||||||
if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) 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) {
|
||||||
@@ -1216,6 +1525,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 == NfcDeviceSaveFormatNfcV) {
|
||||||
|
if(!nfc_device_load_nfcv_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" {
|
||||||
@@ -31,6 +32,7 @@ typedef enum {
|
|||||||
NfcDeviceProtocolMifareUl,
|
NfcDeviceProtocolMifareUl,
|
||||||
NfcDeviceProtocolMifareClassic,
|
NfcDeviceProtocolMifareClassic,
|
||||||
NfcDeviceProtocolMifareDesfire,
|
NfcDeviceProtocolMifareDesfire,
|
||||||
|
NfcDeviceProtocolNfcV
|
||||||
} NfcProtocol;
|
} NfcProtocol;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -39,6 +41,7 @@ typedef enum {
|
|||||||
NfcDeviceSaveFormatMifareUl,
|
NfcDeviceSaveFormatMifareUl,
|
||||||
NfcDeviceSaveFormatMifareClassic,
|
NfcDeviceSaveFormatMifareClassic,
|
||||||
NfcDeviceSaveFormatMifareDesfire,
|
NfcDeviceSaveFormatMifareDesfire,
|
||||||
|
NfcDeviceSaveFormatNfcV,
|
||||||
} NfcDeviceSaveFormat;
|
} NfcDeviceSaveFormat;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -74,6 +77,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;
|
||||||
|
|||||||
@@ -111,6 +111,14 @@ 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 == NfcWorkerStateNfcVEmulate) {
|
||||||
|
nfc_worker_nfcv_emulate(nfc_worker);
|
||||||
|
} else if(nfc_worker->state == NfcWorkerStateNfcVSniff) {
|
||||||
|
nfc_worker_nfcv_sniff(nfc_worker);
|
||||||
|
} else if(nfc_worker->state == NfcWorkerStateNfcVUnlock) {
|
||||||
|
nfc_worker_nfcv_unlock(nfc_worker);
|
||||||
|
} else if(nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave) {
|
||||||
|
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);
|
||||||
@@ -118,6 +126,239 @@ int32_t nfc_worker_task(void* context) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool nfc_worker_read_nfcv(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
bool read_success = false;
|
||||||
|
NfcVReader reader = {};
|
||||||
|
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
|
||||||
|
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
|
||||||
|
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(!nfcv_read_card(&reader, nfc_data, nfcv_data)) break;
|
||||||
|
|
||||||
|
read_success = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
reader_analyzer_stop(nfc_worker->reader_analyzer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker) {
|
||||||
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfcv_emu_init(nfc_data, nfcv_data);
|
||||||
|
while(nfc_worker->state == NfcWorkerStateNfcVEmulate) {
|
||||||
|
if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 100)) {
|
||||||
|
if(nfc_worker->callback) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventNfcVCommandExecuted, nfc_worker->context);
|
||||||
|
if(nfcv_data->modified) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventNfcVContentChanged, nfc_worker->context);
|
||||||
|
nfcv_data->modified = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
furi_delay_ms(10);
|
||||||
|
}
|
||||||
|
nfcv_emu_deinit(nfcv_data);
|
||||||
|
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
reader_analyzer_stop(nfc_worker->reader_analyzer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_nfcv_sniff(NfcWorker* nfc_worker) {
|
||||||
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfcv_data->sub_type = NfcVTypeSniff;
|
||||||
|
nfcv_emu_init(nfc_data, nfcv_data);
|
||||||
|
|
||||||
|
while(nfc_worker->state == NfcWorkerStateNfcVSniff) {
|
||||||
|
if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 100)) {
|
||||||
|
if(nfc_worker->callback) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventNfcVCommandExecuted, nfc_worker->context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
furi_delay_ms(10);
|
||||||
|
}
|
||||||
|
nfcv_emu_deinit(nfcv_data);
|
||||||
|
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
reader_analyzer_stop(nfc_worker->reader_analyzer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = {};
|
||||||
|
uint8_t* key_data = nfcv_data->sub_data.slix.key_privacy;
|
||||||
|
uint32_t key = 0;
|
||||||
|
|
||||||
|
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 == NfcWorkerStateNfcVUnlock) ||
|
||||||
|
(nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave)) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
furi_hal_console_printf("Detect presence\r\n");
|
||||||
|
ReturnCode ret = slix_get_random(nfcv_data);
|
||||||
|
|
||||||
|
if(ret == ERR_NONE) {
|
||||||
|
/* there is some chip, responding with a RAND */
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV;
|
||||||
|
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, just save */
|
||||||
|
if(nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave) {
|
||||||
|
NfcVReader reader = {};
|
||||||
|
|
||||||
|
if(!nfcv_read_card(&reader, &nfc_worker->dev_data->nfc_data, nfcv_data)) {
|
||||||
|
furi_hal_console_printf(" => failed, wait for chip to disappear.\r\n");
|
||||||
|
snprintf(nfcv_data->error, sizeof(nfcv_data->error), "Read card\nfailed");
|
||||||
|
nfc_worker->callback(NfcWorkerEventWrongCardDetected, nfc_worker->context);
|
||||||
|
} else {
|
||||||
|
furi_hal_console_printf(" => success, wait for chip to disappear.\r\n");
|
||||||
|
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
furi_hal_console_printf(" => success, wait for chip to disappear.\r\n");
|
||||||
|
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(slix_get_random(NULL) == ERR_NONE) {
|
||||||
|
furi_delay_ms(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_hal_console_printf(
|
||||||
|
" => chip is already visible, wait for chip to disappear.\r\n");
|
||||||
|
nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context);
|
||||||
|
while(slix_get_random(NULL) == ERR_NONE) {
|
||||||
|
furi_delay_ms(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
key_data[0] = 0;
|
||||||
|
key_data[1] = 0;
|
||||||
|
key_data[2] = 0;
|
||||||
|
key_data[3] = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* chip is invisible, try to unlock */
|
||||||
|
furi_hal_console_printf(" chip is invisible, unlocking\r\n");
|
||||||
|
|
||||||
|
if(nfcv_data->auth_method == NfcVAuthMethodManual) {
|
||||||
|
key |= key_data[0] << 24;
|
||||||
|
key |= key_data[1] << 16;
|
||||||
|
key |= key_data[2] << 8;
|
||||||
|
key |= key_data[3] << 0;
|
||||||
|
|
||||||
|
ret = slix_unlock(nfcv_data, 4);
|
||||||
|
} else {
|
||||||
|
key = 0x7FFD6E5B;
|
||||||
|
key_data[0] = key >> 24;
|
||||||
|
key_data[1] = key >> 16;
|
||||||
|
key_data[2] = key >> 8;
|
||||||
|
key_data[3] = key >> 0;
|
||||||
|
ret = slix_unlock(nfcv_data, 4);
|
||||||
|
|
||||||
|
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_get_random(nfcv_data) != ERR_NONE) {
|
||||||
|
furi_hal_console_printf(" reset failed\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
key = 0x0F0F0F0F;
|
||||||
|
key_data[0] = key >> 24;
|
||||||
|
key_data[1] = key >> 16;
|
||||||
|
key_data[2] = key >> 8;
|
||||||
|
key_data[3] = key >> 0;
|
||||||
|
ret = slix_unlock(nfcv_data, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ret != ERR_NONE) {
|
||||||
|
/* 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_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_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 = {};
|
||||||
@@ -378,7 +619,12 @@ 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) {
|
||||||
event = NfcWorkerEventReadUidNfcV;
|
FURI_LOG_I(TAG, "NfcV detected");
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV;
|
||||||
|
if(nfc_worker_read_nfcv(nfc_worker, &tx_rx)) {
|
||||||
|
FURI_LOG_I(TAG, "nfc_worker_read_nfcv success");
|
||||||
|
}
|
||||||
|
event = NfcWorkerEventReadNfcV;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ typedef enum {
|
|||||||
NfcWorkerStateReadMfUltralightReadAuth,
|
NfcWorkerStateReadMfUltralightReadAuth,
|
||||||
NfcWorkerStateMfClassicDictAttack,
|
NfcWorkerStateMfClassicDictAttack,
|
||||||
NfcWorkerStateAnalyzeReader,
|
NfcWorkerStateAnalyzeReader,
|
||||||
|
NfcWorkerStateNfcVEmulate,
|
||||||
|
NfcWorkerStateNfcVUnlock,
|
||||||
|
NfcWorkerStateNfcVUnlockAndSave,
|
||||||
|
NfcWorkerStateNfcVSniff,
|
||||||
// Debug
|
// Debug
|
||||||
NfcWorkerStateEmulateApdu,
|
NfcWorkerStateEmulateApdu,
|
||||||
NfcWorkerStateField,
|
NfcWorkerStateField,
|
||||||
@@ -39,6 +43,7 @@ typedef enum {
|
|||||||
NfcWorkerEventReadMfClassicDone,
|
NfcWorkerEventReadMfClassicDone,
|
||||||
NfcWorkerEventReadMfClassicLoadKeyCache,
|
NfcWorkerEventReadMfClassicLoadKeyCache,
|
||||||
NfcWorkerEventReadMfClassicDictAttackRequired,
|
NfcWorkerEventReadMfClassicDictAttackRequired,
|
||||||
|
NfcWorkerEventReadNfcV,
|
||||||
NfcWorkerEventReadBankCard,
|
NfcWorkerEventReadBankCard,
|
||||||
|
|
||||||
// Nfc worker common events
|
// Nfc worker common events
|
||||||
@@ -70,6 +75,9 @@ typedef enum {
|
|||||||
// Mifare Ultralight events
|
// Mifare Ultralight events
|
||||||
NfcWorkerEventMfUltralightPassKey, // NFC worker requesting manual key
|
NfcWorkerEventMfUltralightPassKey, // NFC worker requesting manual key
|
||||||
NfcWorkerEventMfUltralightPwdAuth, // Reader sent auth command
|
NfcWorkerEventMfUltralightPwdAuth, // Reader sent auth command
|
||||||
|
NfcWorkerEventNfcVPassKey, // NFC worker requesting manual key
|
||||||
|
NfcWorkerEventNfcVCommandExecuted,
|
||||||
|
NfcWorkerEventNfcVContentChanged,
|
||||||
} NfcWorkerEvent;
|
} NfcWorkerEvent;
|
||||||
|
|
||||||
typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context);
|
typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context);
|
||||||
@@ -88,3 +96,6 @@ 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);
|
||||||
|
void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker);
|
||||||
|
void nfc_worker_nfcv_sniff(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.h>
|
||||||
#include <lib/nfc/helpers/reader_analyzer.h>
|
#include <lib/nfc/helpers/reader_analyzer.h>
|
||||||
|
|
||||||
struct NfcWorker {
|
struct NfcWorker {
|
||||||
|
|||||||
1348
lib/nfc/protocols/nfcv.c
Normal file
1348
lib/nfc/protocols/nfcv.c
Normal file
File diff suppressed because it is too large
Load Diff
241
lib/nfc/protocols/nfcv.h
Normal file
241
lib/nfc/protocols/nfcv.h
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <lib/digital_signal/digital_signal.h>
|
||||||
|
#include <lib/pulse_reader/pulse_reader.h>
|
||||||
|
#include "nfc_util.h"
|
||||||
|
#include <furi_hal_nfc.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NFCV_FC (13560000.0f / 0.9998f) /* MHz */
|
||||||
|
#define NFCV_RESP_SUBC1_PULSE_32 (1.0f / (NFCV_FC / 32) / 2.0f) /* 1.1799 µs */
|
||||||
|
#define NFCV_RESP_SUBC1_UNMOD_256 (256.0f / NFCV_FC) /* 18.8791 µs */
|
||||||
|
|
||||||
|
#define PULSE_DURATION_NS (128.0f * 1000000000.0f / NFCV_FC)
|
||||||
|
|
||||||
|
#define DIGITAL_SIGNAL_UNIT_S (100000000000.0f)
|
||||||
|
#define DIGITAL_SIGNAL_UNIT_US (100000.0f)
|
||||||
|
|
||||||
|
/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum number of blocks is defined as 256 */
|
||||||
|
#define NFCV_BLOCKS_MAX 256
|
||||||
|
/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum size of blocks is defined as 32 */
|
||||||
|
#define NFCV_BLOCKSIZE_MAX 32
|
||||||
|
/* the resulting memory size a card can have */
|
||||||
|
#define NFCV_MEMSIZE_MAX (NFCV_BLOCKS_MAX * NFCV_BLOCKSIZE_MAX)
|
||||||
|
/* ISO/IEC 15693-3:2019(E) 7.1b: standard allows up to 8192, the maxium frame length that we are expected to receive/send is less */
|
||||||
|
#define NFCV_FRAMESIZE_MAX (1 + NFCV_MEMSIZE_MAX + NFCV_BLOCKS_MAX)
|
||||||
|
|
||||||
|
#define NFCV_LOG_STR_LEN 128
|
||||||
|
|
||||||
|
// #define NFCV_DIAGNOSTIC_DUMPS
|
||||||
|
// #define NFCV_DIAGNOSTIC_DUMP_SIZE 128
|
||||||
|
|
||||||
|
/* helpers to calculate the send time based on DWT->CYCCNT */
|
||||||
|
#define NFCV_FDT_USEC(usec) (usec * 64)
|
||||||
|
#define NFCV_FDT_FC(ticks) ((ticks)*6400 / 1356)
|
||||||
|
|
||||||
|
#define NFCV_FRAME_STATE_SOF1 0
|
||||||
|
#define NFCV_FRAME_STATE_SOF2 1
|
||||||
|
#define NFCV_FRAME_STATE_CODING_4 2
|
||||||
|
#define NFCV_FRAME_STATE_CODING_256 3
|
||||||
|
#define NFCV_FRAME_STATE_EOF 4
|
||||||
|
#define NFCV_FRAME_STATE_RESET 5
|
||||||
|
|
||||||
|
/* sequences for every section of a frame */
|
||||||
|
#define NFCV_SIG_SOF 0
|
||||||
|
#define NFCV_SIG_BIT0 1
|
||||||
|
#define NFCV_SIG_BIT1 2
|
||||||
|
#define NFCV_SIG_EOF 3
|
||||||
|
#define NFCV_SIG_LOW_SOF 4
|
||||||
|
#define NFCV_SIG_LOW_BIT0 5
|
||||||
|
#define NFCV_SIG_LOW_BIT1 6
|
||||||
|
#define NFCV_SIG_LOW_EOF 7
|
||||||
|
|
||||||
|
/* ISO15693 command codes */
|
||||||
|
#define ISO15693_INVENTORY 0x01
|
||||||
|
#define ISO15693_STAYQUIET 0x02
|
||||||
|
#define ISO15693_READBLOCK 0x20
|
||||||
|
#define ISO15693_WRITEBLOCK 0x21
|
||||||
|
#define ISO15693_LOCKBLOCK 0x22
|
||||||
|
#define ISO15693_READ_MULTI_BLOCK 0x23
|
||||||
|
#define ISO15693_WRITE_MULTI_BLOCK 0x24
|
||||||
|
#define ISO15693_SELECT 0x25
|
||||||
|
#define ISO15693_RESET_TO_READY 0x26
|
||||||
|
#define ISO15693_WRITE_AFI 0x27
|
||||||
|
#define ISO15693_LOCK_AFI 0x28
|
||||||
|
#define ISO15693_WRITE_DSFID 0x29
|
||||||
|
#define ISO15693_LOCK_DSFID 0x2A
|
||||||
|
#define ISO15693_GET_SYSTEM_INFO 0x2B
|
||||||
|
#define ISO15693_READ_MULTI_SECSTATUS 0x2C
|
||||||
|
|
||||||
|
#define ISO15693_CUST_ECHO_MODE 0xDE
|
||||||
|
#define ISO15693_CUST_ECHO_DATA 0xDF
|
||||||
|
|
||||||
|
/* ISO15693 RESPONSE ERROR CODES */
|
||||||
|
#define ISO15693_NOERROR 0x00
|
||||||
|
#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported
|
||||||
|
#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error)
|
||||||
|
#define ISO15693_ERROR_CMD_OPTION 0x03 // Command option not supported
|
||||||
|
#define ISO15693_ERROR_GENERIC 0x0F // No additional Info about this error
|
||||||
|
#define ISO15693_ERROR_BLOCK_UNAVAILABLE 0x10
|
||||||
|
#define ISO15693_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again
|
||||||
|
#define ISO15693_ERROR_BLOCK_LOCKED 0x12 // cannot be changed
|
||||||
|
#define ISO15693_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful
|
||||||
|
#define ISO15693_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcVLockBitDsfid = 1,
|
||||||
|
NfcVLockBitAfi = 2,
|
||||||
|
} NfcVLockBits;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcVAuthMethodManual,
|
||||||
|
NfcVAuthMethodTonieBox,
|
||||||
|
} NfcVAuthMethod;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcVTypePlain = 0,
|
||||||
|
NfcVTypeSlix = 1,
|
||||||
|
NfcVTypeSlixS = 2,
|
||||||
|
NfcVTypeSlixL = 3,
|
||||||
|
NfcVTypeSlix2 = 4,
|
||||||
|
NfcVTypeSniff = 255,
|
||||||
|
} NfcVSubtype;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcVSendFlagsNormal = 0,
|
||||||
|
NfcVSendFlagsSof = 1 << 0,
|
||||||
|
NfcVSendFlagsCrc = 1 << 1,
|
||||||
|
NfcVSendFlagsEof = 1 << 2,
|
||||||
|
NfcVSendFlagsOneSubcarrier = 0,
|
||||||
|
NfcVSendFlagsTwoSubcarrier = 1 << 3,
|
||||||
|
NfcVSendFlagsLowRate = 0,
|
||||||
|
NfcVSendFlagsHighRate = 1 << 4
|
||||||
|
} NfcVSendFlags;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t key_read[4];
|
||||||
|
uint8_t key_write[4];
|
||||||
|
uint8_t key_privacy[4];
|
||||||
|
uint8_t key_destroy[4];
|
||||||
|
uint8_t key_eas[4];
|
||||||
|
uint8_t rand[2];
|
||||||
|
bool privacy;
|
||||||
|
} NfcVSlixData;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
NfcVSlixData slix;
|
||||||
|
} NfcVSubtypeData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
DigitalSignal* nfcv_resp_sof;
|
||||||
|
DigitalSignal* nfcv_resp_one;
|
||||||
|
DigitalSignal* nfcv_resp_zero;
|
||||||
|
DigitalSignal* nfcv_resp_eof;
|
||||||
|
} NfcVEmuAirSignals;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PulseReader* reader_signal;
|
||||||
|
DigitalSignal* nfcv_resp_pulse; /* pulse length, fc/32 */
|
||||||
|
DigitalSignal* nfcv_resp_half_pulse; /* half pulse length, fc/32 */
|
||||||
|
DigitalSignal* nfcv_resp_unmod; /* unmodulated length 256/fc */
|
||||||
|
NfcVEmuAirSignals signals_high;
|
||||||
|
NfcVEmuAirSignals signals_low;
|
||||||
|
DigitalSequence* nfcv_signal;
|
||||||
|
} NfcVEmuAir;
|
||||||
|
|
||||||
|
typedef void (*NfcVEmuProtocolHandler)(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
FuriHalNfcDevData* nfc_data,
|
||||||
|
void* nfcv_data);
|
||||||
|
typedef bool (*NfcVEmuProtocolFilter)(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
FuriHalNfcDevData* nfc_data,
|
||||||
|
void* nfcv_data);
|
||||||
|
|
||||||
|
/* the default ISO15693 handler context */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t flags; /* ISO15693-3 flags of the header as specified */
|
||||||
|
uint8_t command; /* ISO15693-3 command at offset 1 as specified */
|
||||||
|
bool selected; /* ISO15693-3 flags: selected frame */
|
||||||
|
bool addressed; /* ISO15693-3 flags: addressed frame */
|
||||||
|
bool advanced; /* ISO15693-3 command: advanced command */
|
||||||
|
uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */
|
||||||
|
uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */
|
||||||
|
|
||||||
|
uint8_t response_buffer[NFCV_FRAMESIZE_MAX]; /* pre-allocated response buffer */
|
||||||
|
NfcVSendFlags response_flags; /* flags to use when sending response */
|
||||||
|
uint32_t send_time; /* timestamp when to send the response */
|
||||||
|
|
||||||
|
NfcVEmuProtocolFilter emu_protocol_filter;
|
||||||
|
} NfcVEmuProtocolCtx;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* common ISO15693 fields, being specified in ISO15693-3 */
|
||||||
|
uint8_t dsfid;
|
||||||
|
uint8_t afi;
|
||||||
|
uint8_t ic_ref;
|
||||||
|
uint16_t block_num;
|
||||||
|
uint8_t block_size;
|
||||||
|
uint8_t data[NFCV_MEMSIZE_MAX];
|
||||||
|
uint8_t security_status[1 + NFCV_BLOCKS_MAX];
|
||||||
|
bool selected;
|
||||||
|
bool quiet;
|
||||||
|
|
||||||
|
bool modified;
|
||||||
|
bool ready;
|
||||||
|
bool echo_mode;
|
||||||
|
|
||||||
|
/* specfic variant infos */
|
||||||
|
NfcVSubtype sub_type;
|
||||||
|
NfcVSubtypeData sub_data;
|
||||||
|
NfcVAuthMethod auth_method;
|
||||||
|
|
||||||
|
/* precalced air level data */
|
||||||
|
NfcVEmuAir emu_air;
|
||||||
|
|
||||||
|
uint8_t* frame; /* [NFCV_FRAMESIZE_MAX] ISO15693-2 incoming raw data from air layer */
|
||||||
|
uint8_t frame_length; /* ISO15693-2 length of incoming data */
|
||||||
|
uint32_t eof_timestamp; /* ISO15693-2 EOF timestamp, read from DWT->CYCCNT */
|
||||||
|
|
||||||
|
/* handler for the protocol layer as specified in ISO15693-3 */
|
||||||
|
NfcVEmuProtocolHandler emu_protocol_handler;
|
||||||
|
void* emu_protocol_ctx;
|
||||||
|
/* runtime data */
|
||||||
|
char last_command[NFCV_LOG_STR_LEN];
|
||||||
|
char error[NFCV_LOG_STR_LEN];
|
||||||
|
} 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(FuriHalNfcDevData* nfc_data, NfcVData* data);
|
||||||
|
ReturnCode nfcv_inventory(uint8_t* uid);
|
||||||
|
bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* data);
|
||||||
|
|
||||||
|
void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data);
|
||||||
|
void nfcv_emu_deinit(NfcVData* nfcv_data);
|
||||||
|
bool nfcv_emu_loop(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
FuriHalNfcDevData* nfc_data,
|
||||||
|
NfcVData* nfcv_data,
|
||||||
|
uint32_t timeout_ms);
|
||||||
|
void nfcv_emu_send(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
NfcVData* nfcv,
|
||||||
|
uint8_t* data,
|
||||||
|
uint8_t length,
|
||||||
|
NfcVSendFlags flags,
|
||||||
|
uint32_t send_time);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
412
lib/nfc/protocols/slix.c
Normal file
412
lib/nfc/protocols/slix.c
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include "nfcv.h"
|
||||||
|
#include "slix.h"
|
||||||
|
#include "nfc_util.h"
|
||||||
|
#include <furi.h>
|
||||||
|
#include "furi_hal_nfc.h"
|
||||||
|
#include <furi_hal_random.h>
|
||||||
|
|
||||||
|
#define TAG "SLIX"
|
||||||
|
|
||||||
|
static uint32_t slix_read_be(uint8_t* data, uint32_t length) {
|
||||||
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
for(uint32_t pos = 0; pos < length; pos++) {
|
||||||
|
value <<= 8;
|
||||||
|
value |= data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t slix_get_ti(FuriHalNfcDevData* nfc_data) {
|
||||||
|
return (nfc_data->uid[3] >> 3) & 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_check_card_type(FuriHalNfcDevData* nfc_data) {
|
||||||
|
if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x01) &&
|
||||||
|
slix_get_ti(nfc_data) == 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix2_check_card_type(FuriHalNfcDevData* nfc_data) {
|
||||||
|
if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x01) &&
|
||||||
|
slix_get_ti(nfc_data) == 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data) {
|
||||||
|
if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x02)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data) {
|
||||||
|
if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x03)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnCode slix_get_random(NfcVData* data) {
|
||||||
|
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(data != NULL) {
|
||||||
|
data->sub_data.slix.rand[0] = rxBuf[2];
|
||||||
|
data->sub_data.slix.rand[1] = rxBuf[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) {
|
||||||
|
furi_assert(rand);
|
||||||
|
|
||||||
|
uint16_t received = 0;
|
||||||
|
uint8_t rxBuf[32];
|
||||||
|
uint8_t cmd_set_pass[] = {
|
||||||
|
password_id,
|
||||||
|
data->sub_data.slix.rand[1],
|
||||||
|
data->sub_data.slix.rand[0],
|
||||||
|
data->sub_data.slix.rand[1],
|
||||||
|
data->sub_data.slix.rand[0]};
|
||||||
|
uint8_t* password = NULL;
|
||||||
|
|
||||||
|
switch(password_id) {
|
||||||
|
case SLIX_PASS_READ:
|
||||||
|
password = data->sub_data.slix.key_read;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_WRITE:
|
||||||
|
password = data->sub_data.slix.key_write;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_PRIVACY:
|
||||||
|
password = data->sub_data.slix.key_privacy;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_DESTROY:
|
||||||
|
password = data->sub_data.slix.key_destroy;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_EASAFI:
|
||||||
|
password = data->sub_data.slix.key_eas;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!password) {
|
||||||
|
return ERR_NOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int pos = 0; pos < 4; pos++) {
|
||||||
|
cmd_set_pass[1 + pos] ^= password[3 - pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_generic_protocol_filter(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
FuriHalNfcDevData* nfc_data,
|
||||||
|
void* nfcv_data_in,
|
||||||
|
uint32_t password_supported) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(nfc_data);
|
||||||
|
furi_assert(nfcv_data_in);
|
||||||
|
|
||||||
|
NfcVData* nfcv_data = (NfcVData*)nfcv_data_in;
|
||||||
|
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
|
||||||
|
NfcVSlixData* slix = &nfcv_data->sub_data.slix;
|
||||||
|
|
||||||
|
if(slix->privacy && ctx->command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER &&
|
||||||
|
ctx->command != ISO15693_CMD_NXP_SET_PASSWORD) {
|
||||||
|
snprintf(
|
||||||
|
nfcv_data->last_command,
|
||||||
|
sizeof(nfcv_data->last_command),
|
||||||
|
"command 0x%02X ignored, privacy mode",
|
||||||
|
ctx->command);
|
||||||
|
FURI_LOG_D(TAG, "%s", nfcv_data->last_command);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
switch(ctx->command) {
|
||||||
|
case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: {
|
||||||
|
slix->rand[0] = furi_hal_random_get();
|
||||||
|
slix->rand[1] = furi_hal_random_get();
|
||||||
|
|
||||||
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
|
ctx->response_buffer[1] = slix->rand[1];
|
||||||
|
ctx->response_buffer[2] = slix->rand[0];
|
||||||
|
|
||||||
|
nfcv_emu_send(
|
||||||
|
tx_rx, nfcv_data, ctx->response_buffer, 3, ctx->response_flags, ctx->send_time);
|
||||||
|
snprintf(
|
||||||
|
nfcv_data->last_command,
|
||||||
|
sizeof(nfcv_data->last_command),
|
||||||
|
"GET_RANDOM_NUMBER -> 0x%02X%02X",
|
||||||
|
slix->rand[0],
|
||||||
|
slix->rand[1]);
|
||||||
|
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ISO15693_CMD_NXP_SET_PASSWORD: {
|
||||||
|
uint8_t password_id = nfcv_data->frame[ctx->payload_offset];
|
||||||
|
|
||||||
|
if(!(password_id & password_supported)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* password_xored = &nfcv_data->frame[ctx->payload_offset + 1];
|
||||||
|
uint8_t* rand = slix->rand;
|
||||||
|
uint8_t* password = NULL;
|
||||||
|
uint8_t password_rcv[4];
|
||||||
|
|
||||||
|
switch(password_id) {
|
||||||
|
case SLIX_PASS_READ:
|
||||||
|
password = slix->key_read;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_WRITE:
|
||||||
|
password = slix->key_write;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_PRIVACY:
|
||||||
|
password = slix->key_privacy;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_DESTROY:
|
||||||
|
password = slix->key_destroy;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_EASAFI:
|
||||||
|
password = slix->key_eas;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!password) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int pos = 0; pos < 4; pos++) {
|
||||||
|
password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2];
|
||||||
|
}
|
||||||
|
uint32_t pass_expect = slix_read_be(password, 4);
|
||||||
|
uint32_t pass_received = slix_read_be(password_rcv, 4);
|
||||||
|
|
||||||
|
/* if the password is all-zeroes, just accept any password*/
|
||||||
|
if(!pass_expect || pass_expect == pass_received) {
|
||||||
|
switch(password_id) {
|
||||||
|
case SLIX_PASS_READ:
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_WRITE:
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_PRIVACY:
|
||||||
|
slix->privacy = false;
|
||||||
|
nfcv_data->modified = true;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_DESTROY:
|
||||||
|
FURI_LOG_D(TAG, "Pooof! Got destroyed");
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_EASAFI:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
|
nfcv_emu_send(
|
||||||
|
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||||
|
snprintf(
|
||||||
|
nfcv_data->last_command,
|
||||||
|
sizeof(nfcv_data->last_command),
|
||||||
|
"SET_PASSWORD #%02X 0x%08lX OK",
|
||||||
|
password_id,
|
||||||
|
pass_received);
|
||||||
|
} else {
|
||||||
|
snprintf(
|
||||||
|
nfcv_data->last_command,
|
||||||
|
sizeof(nfcv_data->last_command),
|
||||||
|
"SET_PASSWORD #%02X 0x%08lX/%08lX FAIL",
|
||||||
|
password_id,
|
||||||
|
pass_received,
|
||||||
|
pass_expect);
|
||||||
|
}
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ISO15693_CMD_NXP_ENABLE_PRIVACY: {
|
||||||
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
|
|
||||||
|
nfcv_emu_send(
|
||||||
|
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||||
|
snprintf(
|
||||||
|
nfcv_data->last_command,
|
||||||
|
sizeof(nfcv_data->last_command),
|
||||||
|
"ISO15693_CMD_NXP_ENABLE_PRIVACY");
|
||||||
|
|
||||||
|
slix->privacy = true;
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_l_protocol_filter(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
FuriHalNfcDevData* nfc_data,
|
||||||
|
void* nfcv_data_in) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(nfc_data);
|
||||||
|
furi_assert(nfcv_data_in);
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
/* many SLIX share some of the functions, place that in a generic handler */
|
||||||
|
if(slix_generic_protocol_filter(
|
||||||
|
tx_rx,
|
||||||
|
nfc_data,
|
||||||
|
nfcv_data_in,
|
||||||
|
SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slix_l_prepare(NfcVData* nfcv_data) {
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
|
||||||
|
|
||||||
|
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
|
||||||
|
ctx->emu_protocol_filter = &slix_l_protocol_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_s_protocol_filter(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
FuriHalNfcDevData* nfc_data,
|
||||||
|
void* nfcv_data_in) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(nfc_data);
|
||||||
|
furi_assert(nfcv_data_in);
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
/* many SLIX share some of the functions, place that in a generic handler */
|
||||||
|
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slix_s_prepare(NfcVData* nfcv_data) {
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
|
||||||
|
|
||||||
|
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
|
||||||
|
ctx->emu_protocol_filter = &slix_s_protocol_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_protocol_filter(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
FuriHalNfcDevData* nfc_data,
|
||||||
|
void* nfcv_data_in) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(nfc_data);
|
||||||
|
furi_assert(nfcv_data_in);
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
/* many SLIX share some of the functions, place that in a generic handler */
|
||||||
|
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_EASAFI)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slix_prepare(NfcVData* nfcv_data) {
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
|
||||||
|
|
||||||
|
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
|
||||||
|
ctx->emu_protocol_filter = &slix_protocol_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix2_protocol_filter(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
FuriHalNfcDevData* nfc_data,
|
||||||
|
void* nfcv_data_in) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(nfc_data);
|
||||||
|
furi_assert(nfcv_data_in);
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
/* many SLIX share some of the functions, place that in a generic handler */
|
||||||
|
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slix2_prepare(NfcVData* nfcv_data) {
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
|
||||||
|
|
||||||
|
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
|
||||||
|
ctx->emu_protocol_filter = &slix2_protocol_filter;
|
||||||
|
}
|
||||||
46
lib/nfc/protocols/slix.h
Normal file
46
lib/nfc/protocols/slix.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "nfc_util.h"
|
||||||
|
#include <furi_hal_nfc.h>
|
||||||
|
|
||||||
|
#define ISO15693_MANUFACTURER_NXP 0x04
|
||||||
|
|
||||||
|
/* ISO15693-3 CUSTOM NXP COMMANDS */
|
||||||
|
#define ISO15693_CMD_NXP_SET_EAS 0xA2
|
||||||
|
#define ISO15693_CMD_NXP_RESET_EAS 0xA3
|
||||||
|
#define ISO15693_CMD_NXP_LOCK_EAS 0xA4
|
||||||
|
#define ISO15693_CMD_NXP_EAS_ALARM 0xA5
|
||||||
|
#define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6
|
||||||
|
#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7
|
||||||
|
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0
|
||||||
|
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1
|
||||||
|
#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2
|
||||||
|
#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3
|
||||||
|
#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4
|
||||||
|
#define ISO15693_CMD_NXP_DESTROY 0xB9
|
||||||
|
#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA
|
||||||
|
|
||||||
|
/* available passwords */
|
||||||
|
#define SLIX_PASS_READ 0x01
|
||||||
|
#define SLIX_PASS_WRITE 0x02
|
||||||
|
#define SLIX_PASS_PRIVACY 0x04
|
||||||
|
#define SLIX_PASS_DESTROY 0x08
|
||||||
|
#define SLIX_PASS_EASAFI 0x10
|
||||||
|
|
||||||
|
#define SLIX_PASS_ALL \
|
||||||
|
(SLIX_PASS_READ | SLIX_PASS_WRITE | SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)
|
||||||
|
|
||||||
|
bool slix_check_card_type(FuriHalNfcDevData* nfc_data);
|
||||||
|
bool slix2_check_card_type(FuriHalNfcDevData* nfc_data);
|
||||||
|
bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data);
|
||||||
|
bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data);
|
||||||
|
|
||||||
|
ReturnCode slix_get_random(NfcVData* data);
|
||||||
|
ReturnCode slix_unlock(NfcVData* data, uint32_t password_id);
|
||||||
|
|
||||||
|
void slix_prepare(NfcVData* nfcv_data);
|
||||||
|
void slix_s_prepare(NfcVData* nfcv_data);
|
||||||
|
void slix_l_prepare(NfcVData* nfcv_data);
|
||||||
|
void slix2_prepare(NfcVData* nfcv_data);
|
||||||
Reference in New Issue
Block a user