separate ISO15693 basic and SLIX extensions a bit more

changed save format to reflect this
executing emulation from browser now also works
This commit is contained in:
g3gg0
2022-11-17 01:35:39 +01:00
parent bcd33ca125
commit 75f5e6604b
16 changed files with 555 additions and 151 deletions

View File

@@ -280,6 +280,9 @@ 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, NfcSceneEmulateNfcV);
DOLPHIN_DEED(DolphinDeedNfcEmulate);
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
} else { } else {

View File

@@ -286,8 +286,11 @@ static void nfc_cli_st25r_trans(Cli* cli, FuriString* args) {
.block_num = 8, .block_num = 8,
.block_size = 4, .block_size = 4,
.ic_ref = 3, .ic_ref = 3,
.key_privacy = { 0x0F, 0x0F, 0x0F, 0x0F }, .type = NfcVTypeSlixL,
.privacy = false .sub_data.slix_l = {
.key_privacy = { 0x0F, 0x0F, 0x0F, 0x0F },
.privacy = false
}
}; };
memset(nfcv_data.data, 0xAE, 4 * 8); memset(nfcv_data.data, 0xAE, 4 * 8);

View File

@@ -15,7 +15,7 @@ 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 == NfcDeviceProtocolSlixL) || (protocol == NfcDeviceProtocolNfcV)) { || (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;
@@ -42,15 +42,33 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
} 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) { } else if(protocol == NfcDeviceProtocolNfcV) {
furi_string_cat_printf(temp_str, "\e#ISO15693\n"); switch (dev_data->nfcv_data.type)
} else if(protocol == NfcDeviceProtocolSlixL) { {
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-L\n"); 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 == NfcDeviceProtocolSlixL) || (protocol == NfcDeviceProtocolNfcV)) { if(protocol == NfcDeviceProtocolNfcV) {
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
furi_string_cat_printf(temp_str, "UID:\n"); furi_string_cat_printf(temp_str, "UID:\n");
@@ -151,9 +169,6 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) {
} else if(protocol == NfcDeviceProtocolMifareUl) { } else if(protocol == NfcDeviceProtocolMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData);
consumed = true; consumed = true;
} else if(protocol == NfcDeviceProtocolSlixL) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu);
consumed = true;
} else if(protocol == NfcDeviceProtocolNfcV) { } else if(protocol == NfcDeviceProtocolNfcV) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu);
consumed = true; consumed = true;

View File

@@ -3,8 +3,9 @@
void nfc_scene_nfcv_key_input_byte_input_callback(void* context) { void nfc_scene_nfcv_key_input_byte_input_callback(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
NfcVSlixLData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix_l;
memcpy(nfc->dev->dev_data.nfcv_data.key_privacy, nfc->byte_input_store, 4); memcpy(data->key_privacy, nfc->byte_input_store, 4);
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
} }

View File

@@ -33,7 +33,7 @@ bool nfc_scene_nfcv_menu_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSave) { if(event.event == SubmenuIndexSave) {
nfc->dev->format = NfcDeviceSaveFormatSlixL; nfc->dev->format = NfcDeviceSaveFormatNfcV;
// Clear device name // Clear device name
nfc_device_set_name(nfc->dev, ""); nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);

View File

@@ -11,53 +11,15 @@ typedef enum {
static bool nfc_scene_nfcv_unlock_worker_callback(NfcWorkerEvent event, void* context) { static bool nfc_scene_nfcv_unlock_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = context; Nfc* nfc = context;
NfcVSlixLData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix_l;
if(event == NfcWorkerEventNfcVPassKey) { if(event == NfcWorkerEventNfcVPassKey) {
memcpy(nfc->dev->dev_data.nfcv_data.key_privacy, nfc->byte_input_store, 4); memcpy(data->key_privacy, nfc->byte_input_store, 4);
} else { } else {
view_dispatcher_send_custom_event(nfc->view_dispatcher, event); view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
} }
return true; return true;
} }
/*
static void nfc_scene_nfcv_unlock_button_callback(GuiButtonType event, InputType type, void* context) {
furi_assert(context);
furi_assert(type);
Nfc* nfc = context;
if(event == GuiButtonTypeCenter) {
if(nfc_worker_get_state(nfc->worker) == NfcWorkerStateNfcVUnlockAndSave) {
nfc_worker_stop(nfc->worker);
nfc_worker_start(
nfc->worker,
NfcWorkerStateNfcVUnlock,
&nfc->dev->dev_data,
nfc_scene_nfcv_unlock_worker_callback,
nfc);
widget_add_button_element(
nfc->widget,
GuiButtonTypeCenter,
"Autosave",
nfc_scene_nfcv_unlock_button_callback,
nfc);
} else {
nfc_worker_stop(nfc->worker);
nfc_worker_start(
nfc->worker,
NfcWorkerStateNfcVUnlockAndSave,
&nfc->dev->dev_data,
nfc_scene_nfcv_unlock_worker_callback,
nfc);
widget_add_button_element(
nfc->widget,
GuiButtonTypeCenter,
"Unlock",
nfc_scene_nfcv_unlock_button_callback,
nfc);
}
notification_message(nfc->notifications, &sequence_single_vibro);
}
}*/
void nfc_scene_nfcv_unlock_popup_callback(void* context) { void nfc_scene_nfcv_unlock_popup_callback(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
@@ -82,10 +44,10 @@ void nfc_scene_nfcv_unlock_set_state(Nfc* nfc, NfcSceneNfcVUnlockState state) {
if(nfc_worker_get_state(nfc->worker) == NfcWorkerStateNfcVUnlockAndSave) { if(nfc_worker_get_state(nfc->worker) == NfcWorkerStateNfcVUnlockAndSave) {
nfc_text_store_set(nfc, "SLIX-L_%02X%02X%02X%02X%02X%02X%02X%02X", nfc_text_store_set(nfc, "SLIX-L_%02X%02X%02X%02X%02X%02X%02X%02X",
nfc_data->uid[7], nfc_data->uid[6], nfc_data->uid[5], nfc_data->uid[4], nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3],
nfc_data->uid[3], nfc_data->uid[2], nfc_data->uid[1], nfc_data->uid[0]); nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]);
nfc->dev->format = NfcDeviceSaveFormatSlixL; nfc->dev->format = NfcDeviceSaveFormatNfcV;
if(nfc_device_save(nfc->dev, nfc->text_store)) { if(nfc_device_save(nfc->dev, nfc->text_store)) {
popup_set_header(popup, "Successfully\nsaved", 94, 3, AlignCenter, AlignTop); popup_set_header(popup, "Successfully\nsaved", 94, 3, AlignCenter, AlignTop);

View File

@@ -55,6 +55,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);

View File

@@ -99,6 +99,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, NfcSceneEmulateNfcV);
} else { } else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
} }

View File

@@ -50,8 +50,8 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, FuriString* format_
furi_string_set(format_string, "Mifare Classic"); furi_string_set(format_string, "Mifare Classic");
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
furi_string_set(format_string, "Mifare DESFire"); furi_string_set(format_string, "Mifare DESFire");
} else if(dev->format == NfcDeviceSaveFormatSlixL) { } else if(dev->format == NfcDeviceSaveFormatNfcV) {
furi_string_set(format_string, "NXP SLIX-L"); furi_string_set(format_string, "ISO15693");
} else { } else {
furi_string_set(format_string, "Unknown"); furi_string_set(format_string, "Unknown");
} }
@@ -87,9 +87,9 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, FuriString* format_st
dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire; dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire;
return true; return true;
} }
if(furi_string_start_with_str(format_string, "NXP SLIX-L")) { if(furi_string_start_with_str(format_string, "ISO15693")) {
dev->format = NfcDeviceSaveFormatSlixL; dev->format = NfcDeviceSaveFormatNfcV;
dev->dev_data.protocol = NfcDeviceProtocolSlixL; dev->dev_data.protocol = NfcDeviceProtocolNfcV;
return true; return true;
} }
return false; return false;
@@ -643,21 +643,92 @@ 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(NfcVData));
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;
NfcVSlixSData* data = &dev->dev_data.nfcv_data.sub_data.slix_s;
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;
NfcVSlixSData* data = &dev->dev_data.nfcv_data.sub_data.slix_s;
memset(data, 0, sizeof(NfcVData));
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) { static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
bool saved = false; bool saved = false;
NfcVData* data = &dev->dev_data.nfcv_data; NfcVSlixLData* data = &dev->dev_data.nfcv_data.sub_data.slix_l;
do { do {
if(!flipper_format_write_comment_cstr(file, "SLIX-L specific data")) break; 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 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 Destroy", data->key_destroy, sizeof(data->key_destroy))) break;
if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) break; if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) break;
if(!flipper_format_write_hex(file, "DSFID", &(data->dsfid), 1)) break; if(!flipper_format_write_bool(file, "Privacy Mode", &data->privacy, 1)) break;
if(!flipper_format_write_hex(file, "AFI", &(data->afi), 1)) break;
if(!flipper_format_write_hex(file, "IC Reference", &(data->ic_ref), 1)) break;
if(!flipper_format_write_hex(file, "Block Count", &(data->block_num), 1)) break;
if(!flipper_format_write_hex(file, "Block Size", &(data->block_size), 1)) break;
if(!flipper_format_write_hex(file, "Data Content", data->data, data->block_num * data->block_size)) break;
saved = true; saved = true;
} while(false); } while(false);
@@ -666,7 +737,7 @@ static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) { bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
bool parsed = false; bool parsed = false;
NfcVData* data = &dev->dev_data.nfcv_data; NfcVSlixLData* data = &dev->dev_data.nfcv_data.sub_data.slix_l;
memset(data, 0, sizeof(NfcVData)); memset(data, 0, sizeof(NfcVData));
do { do {
@@ -679,7 +750,108 @@ bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
if(!flipper_format_read_hex( if(!flipper_format_read_hex(
file, "Password EAS", data->key_eas, sizeof(data->key_eas))) file, "Password EAS", data->key_eas, sizeof(data->key_eas)))
break; 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;
NfcVSlix2Data* data = &dev->dev_data.nfcv_data.sub_data.slix2;
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;
NfcVSlix2Data* data = &dev->dev_data.nfcv_data.sub_data.slix2;
memset(data, 0, sizeof(NfcVData));
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;
uint8_t temp_value = 0;
NfcVData* data = &dev->dev_data.nfcv_data;
do {
if(!flipper_format_write_hex(file, "DSFID", &(data->dsfid), 1)) break;
if(!flipper_format_write_hex(file, "AFI", &(data->afi), 1)) break;
if(!flipper_format_write_hex(file, "IC Reference", &(data->ic_ref), 1)) break;
if(!flipper_format_write_hex(file, "Block Count", &(data->block_num), 1)) break;
if(!flipper_format_write_hex(file, "Block Size", &(data->block_size), 1)) break;
if(!flipper_format_write_hex(file, "Data Content", data->data, data->block_num * data->block_size)) break;
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_value = data->type;
if(!flipper_format_write_hex(file, "Subtype", &temp_value, 1)) break;
switch(data->type) {
case NfcVTypePlain:
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;
}
} while(false);
return saved;
}
bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) {
bool parsed = false;
uint8_t temp_value = 0;
NfcVData* data = &dev->dev_data.nfcv_data;
memset(data, 0, sizeof(NfcVData));
do {
if(!flipper_format_read_hex(file, "DSFID", &(data->dsfid), 1)) break; if(!flipper_format_read_hex(file, "DSFID", &(data->dsfid), 1)) break;
if(!flipper_format_read_hex(file, "AFI", &(data->afi), 1)) break; if(!flipper_format_read_hex(file, "AFI", &(data->afi), 1)) break;
if(!flipper_format_read_hex(file, "IC Reference", &(data->ic_ref), 1)) break; if(!flipper_format_read_hex(file, "IC Reference", &(data->ic_ref), 1)) break;
@@ -688,8 +860,26 @@ bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
if(!flipper_format_read_hex( if(!flipper_format_read_hex(
file, "Data Content", data->data, data->block_num * data->block_size)) file, "Data Content", data->data, data->block_num * data->block_size))
break; break;
if(!flipper_format_read_hex(file, "Subtype", &temp_value, 1)) break;
data->type = temp_value;
parsed = true; switch(data->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;
}
} while(false); } while(false);
return parsed; return parsed;
@@ -1127,17 +1317,19 @@ static bool nfc_device_save_file(
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")) file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic 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;
// Write UID // Write UID
if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats except ISO15693")) if(!flipper_format_write_comment_cstr(file, "UID is 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 != NfcDeviceSaveFormatSlixL) { if(dev->format != NfcDeviceSaveFormatNfcV) {
// Write ATQA, SAK // Write ATQA, SAK
if(!flipper_format_write_comment_cstr(file, "ISO14443 specific fields"))
break;
if(!flipper_format_write_hex(file, "ATQA", data->atqa, 2)) break; if(!flipper_format_write_hex(file, "ATQA", data->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;
} }
@@ -1146,8 +1338,8 @@ static bool nfc_device_save_file(
if(!nfc_device_save_mifare_ul_data(file, dev)) break; if(!nfc_device_save_mifare_ul_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
if(!nfc_device_save_mifare_df_data(file, dev)) break; if(!nfc_device_save_mifare_df_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatSlixL) { } else if(dev->format == NfcDeviceSaveFormatNfcV) {
if(!nfc_device_save_slix_l_data(file, dev)) break; 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) {
@@ -1215,7 +1407,7 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
if(!(data_cnt == 4 || data_cnt == 7 || data_cnt == 8)) 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 != NfcDeviceSaveFormatSlixL) { if(dev->format != NfcDeviceSaveFormatNfcV) {
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break; if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break;
} }
@@ -1233,8 +1425,8 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
if(!nfc_device_load_mifare_classic_data(file, dev)) break; if(!nfc_device_load_mifare_classic_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
if(!nfc_device_load_mifare_df_data(file, dev)) break; if(!nfc_device_load_mifare_df_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatSlixL) { } else if(dev->format == NfcDeviceSaveFormatNfcV) {
if(!nfc_device_load_slix_l_data(file, dev)) break; 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;
} }

View File

@@ -33,8 +33,7 @@ typedef enum {
NfcDeviceProtocolMifareUl, NfcDeviceProtocolMifareUl,
NfcDeviceProtocolMifareClassic, NfcDeviceProtocolMifareClassic,
NfcDeviceProtocolMifareDesfire, NfcDeviceProtocolMifareDesfire,
NfcDeviceProtocolNfcV, NfcDeviceProtocolNfcV
NfcDeviceProtocolSlixL,
} NfcProtocol; } NfcProtocol;
typedef enum { typedef enum {
@@ -43,7 +42,7 @@ typedef enum {
NfcDeviceSaveFormatMifareUl, NfcDeviceSaveFormatMifareUl,
NfcDeviceSaveFormatMifareClassic, NfcDeviceSaveFormatMifareClassic,
NfcDeviceSaveFormatMifareDesfire, NfcDeviceSaveFormatMifareDesfire,
NfcDeviceSaveFormatSlixL, NfcDeviceSaveFormatNfcV,
} NfcDeviceSaveFormat; } NfcDeviceSaveFormat;
typedef struct { typedef struct {

View File

@@ -176,11 +176,12 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
if(nfcv_data->auth_method == NfcVAuthMethodManual) { if(nfcv_data->auth_method == NfcVAuthMethodManual) {
uint32_t key = 0; uint32_t key = 0;
uint8_t *key_data = nfc_worker->dev_data->nfcv_data.sub_data.slix_l.key_privacy;
key |= nfc_worker->dev_data->nfcv_data.key_privacy[0] << 24; key |= key_data[0] << 24;
key |= nfc_worker->dev_data->nfcv_data.key_privacy[1] << 16; key |= key_data[1] << 16;
key |= nfc_worker->dev_data->nfcv_data.key_privacy[2] << 8; key |= key_data[2] << 8;
key |= nfc_worker->dev_data->nfcv_data.key_privacy[3] << 0; key |= key_data[3] << 0;
ret = slix_l_unlock(4, rand, key); ret = slix_l_unlock(4, rand, key);
} else { } else {
ret = slix_l_unlock(4, rand, 0x7FFD6E5B); ret = slix_l_unlock(4, rand, 0x7FFD6E5B);
@@ -493,17 +494,31 @@ static bool nfc_worker_read_nfcv(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* t
furi_assert(tx_rx); furi_assert(tx_rx);
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
bool card_read = false; bool card_read = false;
furi_hal_nfc_sleep(); furi_hal_nfc_sleep();
if(slix_l_check_card_type(nfc_data->uid[7], nfc_data->uid[6], nfc_data->uid[5])) {
/* until here the UID field is reversed from the reader IC.
we will read it here again and it will get placed in the right order. */
card_read = nfc_worker_read_nfcv_content(nfc_worker, tx_rx);
nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV;
if(slix_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX detected");
nfcv_data->type = NfcVTypeSlix;
} else if(slix2_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX2 detected");
nfcv_data->type = NfcVTypeSlix2;
} else if(slix_s_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX-L detected"); FURI_LOG_I(TAG, "NXP SLIX-L detected");
nfc_worker->dev_data->protocol = NfcDeviceProtocolSlixL; nfcv_data->type = NfcVTypeSlixS;
card_read = nfc_worker_read_nfcv_content(nfc_worker, tx_rx); } else if(slix_l_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX-L detected");
nfcv_data->type = NfcVTypeSlixL;
} else { } else {
FURI_LOG_I(TAG, "unknown detected"); nfcv_data->type = NfcVTypePlain;
nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV;
card_read = nfc_worker_read_nfcv_content(nfc_worker, tx_rx);
} }
return card_read; return card_read;

View File

@@ -13,7 +13,7 @@
#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/nfcv.h>
#include <lib/nfc/protocols/slix_l.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 {

View File

@@ -8,6 +8,10 @@
#include <furi_hal_resources.h> #include <furi_hal_resources.h>
#include <st25r3916.h> #include <st25r3916.h>
#include <st25r3916_irq.h> #include <st25r3916_irq.h>
#include <stm32wbxx_ll_dma.h>
#include <stm32wbxx_ll_dmamux.h>
#include <stm32wbxx_ll_tim.h>
#include <stm32wbxx_ll_exti.h>
#include "nfcv.h" #include "nfcv.h"
#include "nfc_util.h" #include "nfc_util.h"
@@ -75,7 +79,7 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data) {
if(ret == ERR_NONE) { if(ret == ERR_NONE) {
nfc_data->type = FuriHalNfcTypeV; nfc_data->type = FuriHalNfcTypeV;
nfc_data->uid_len = 8; nfc_data->uid_len = 8;
/* UID is stored reversed in this structure */ /* UID is stored reversed in this response */
for(int pos = 0; pos < nfc_data->uid_len; pos++) { for(int pos = 0; pos < nfc_data->uid_len; pos++) {
nfc_data->uid[pos] = rxBuf[2 + (7 - pos)]; nfc_data->uid[pos] = rxBuf[2 + (7 - pos)];
} }
@@ -316,41 +320,62 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
} }
uint8_t response_buffer[32]; uint8_t response_buffer[32];
switch(nfcv_data->type) {
case NfcVTypeSlixL:
if(nfcv_data->sub_data.slix_l.privacy &&
command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER &&
command != ISO15693_CMD_NXP_SET_PASSWORD) {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "(command ignored, privacy)");
}
break;
default:
break;
}
switch(command) { switch(command) {
case ISO15693_GET_SYSTEM_INFO:
{
if(nfcv_data->privacy) {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO (ignored, privacy)");
} else {
response_buffer[0] = ISO15693_NOERROR;
response_buffer[1] = 0x0F;
nfcv_uidcpy(&response_buffer[2], nfc_data->uid);
response_buffer[10] = nfcv_data->dsfid; /* DSFID */
response_buffer[11] = nfcv_data->afi; /* AFI */
response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */
response_buffer[13] = nfcv_data->block_size - 1; /* block size */
response_buffer[14] = nfcv_data->ic_ref; /* IC reference */
nfcv_emu_send(response_buffer, 15);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO");
}
break;
}
case ISO15693_INVENTORY: case ISO15693_INVENTORY:
{ {
if(nfcv_data->privacy) { response_buffer[0] = ISO15693_NOERROR;
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY (ignored, privacy)"); response_buffer[1] = nfcv_data->dsfid; /* DSFID */
} else { nfcv_uidcpy(&response_buffer[2], nfc_data->uid);
response_buffer[0] = ISO15693_NOERROR;
response_buffer[1] = nfcv_data->dsfid; /* DSFID */
nfcv_uidcpy(&response_buffer[2], nfc_data->uid);
nfcv_emu_send(response_buffer, 10); nfcv_emu_send(response_buffer, 10);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY"); snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY");
} break;
}
case ISO15693_STAYQUIET:
{
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "STAYQUIET");
break;
}
case ISO15693_LOCKBLOCK:
{
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCKBLOCK");
break;
}
case ISO15693_READ_MULTI_BLOCK:
{
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ_MULTI_BLOCK");
break;
}
case ISO15693_WRITE_MULTI_BLOCK:
{
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE_MULTI_BLOCK");
break;
}
case ISO15693_SELECT:
{
response_buffer[0] = ISO15693_NOERROR;
nfcv_emu_send(response_buffer, 1);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT");
break; break;
} }
@@ -386,11 +411,31 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
break; break;
} }
case ISO15693_GET_SYSTEM_INFO:
{
response_buffer[0] = ISO15693_NOERROR;
response_buffer[1] = 0x0F;
nfcv_uidcpy(&response_buffer[2], nfc_data->uid);
response_buffer[10] = nfcv_data->dsfid; /* DSFID */
response_buffer[11] = nfcv_data->afi; /* AFI */
response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */
response_buffer[13] = nfcv_data->block_size - 1; /* block size */
response_buffer[14] = nfcv_data->ic_ref; /* IC reference */
nfcv_emu_send(response_buffer, 15);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO");
break;
}
case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: case ISO15693_CMD_NXP_GET_RANDOM_NUMBER:
{ {
nfcv_data->sub_data.slix_l.rand[0] = 0x00;
nfcv_data->sub_data.slix_l.rand[1] = 0x00;
response_buffer[0] = ISO15693_NOERROR; response_buffer[0] = ISO15693_NOERROR;
response_buffer[1] = 0x00; /* set number to 0x0000 so we get the key in plaintext */ response_buffer[1] = nfcv_data->sub_data.slix_l.rand[0];
response_buffer[2] = 0x00; response_buffer[2] = nfcv_data->sub_data.slix_l.rand[1];
nfcv_emu_send(response_buffer, 3); nfcv_emu_send(response_buffer, 3);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "GET_RANDOM_NUMBER"); snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "GET_RANDOM_NUMBER");
@@ -399,17 +444,43 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
case ISO15693_CMD_NXP_SET_PASSWORD: case ISO15693_CMD_NXP_SET_PASSWORD:
{ {
uint32_t pass = (payload[payload_offset + 1] << 24) uint8_t password_id = payload[payload_offset];
| (payload[payload_offset + 2] << 16) uint8_t *password_xored = &payload[payload_offset + 1];
| (payload[payload_offset + 3] << 8) uint8_t *rand = nfcv_data->sub_data.slix_l.rand;
| (payload[payload_offset + 4] << 0); uint8_t status = ISO15693_ERROR_GENERIC;
uint8_t *password = NULL;
uint8_t password_rcv[4];
response_buffer[0] = ISO15693_NOERROR; switch(password_id) {
case 4:
password = nfcv_data->sub_data.slix_l.key_privacy;
break;
case 8:
password = nfcv_data->sub_data.slix_l.key_destroy;
break;
case 10:
password = nfcv_data->sub_data.slix_l.key_eas;
break;
default:
break;
}
for(int pos = 0; pos < 4; pos++) {
password_rcv[pos] = password_xored[pos] ^ rand[pos % 2];
}
if(!memcmp(password, password_rcv, 4)) {
status = ISO15693_NOERROR;
nfcv_data->sub_data.slix_l.privacy = false;
} else {
printf("pass mismatch: %08lX %08lX %02X", *((uint32_t *)password), *((uint32_t *)password_xored), *rand);
}
response_buffer[0] = status;
nfcv_emu_send(response_buffer, 1); nfcv_emu_send(response_buffer, 1);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SET_PASSWORD #%02X: %08lX", payload[payload_offset + 0], pass); snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SET_PASSWORD #%02X", password_id);
nfcv_data->privacy = false;
break; break;
} }
@@ -420,7 +491,7 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
nfcv_emu_send(response_buffer, 1); nfcv_emu_send(response_buffer, 1);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ISO15693_CMD_NXP_ENABLE_PRIVACY"); snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ISO15693_CMD_NXP_ENABLE_PRIVACY");
nfcv_data->privacy = true; nfcv_data->sub_data.slix_l.privacy = true;
break; break;
} }
@@ -430,6 +501,10 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
} }
} }
#define COUNT(x) ((sizeof(x))/(sizeof(x[0])))
uint32_t nfcv_timer_buffer_src[32];
uint32_t nfcv_timer_buffer[1024];
void nfcv_emu_init() { void nfcv_emu_init() {
nfcv_emu_alloc(); nfcv_emu_alloc();
rfal_platform_spi_acquire(); rfal_platform_spi_acquire();
@@ -440,6 +515,53 @@ void nfcv_emu_init() {
st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE); st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE);
furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc); furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc);
#if 0
memset(nfcv_timer_buffer_src, 0xEE, sizeof(nfcv_timer_buffer_src));
memset(nfcv_timer_buffer, 0xFA, sizeof(nfcv_timer_buffer));
/* configure DMA to read from a timer peripheral */
LL_DMA_InitTypeDef dma_config = {};
dma_config.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
dma_config.PeriphOrM2MSrcAddress = (uint32_t) &(TIM2->CNT);
dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
dma_config.MemoryOrM2MDstAddress = (uint32_t) nfcv_timer_buffer;
dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
dma_config.Mode = LL_DMA_MODE_NORMAL;
dma_config.NbData = 32; /* executes LL_DMA_SetDataLength */
dma_config.PeriphRequest = LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */
dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH;
/* now set up DMA with these settings */
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4);
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_4, &dma_config);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
/* make some noise on the counter */
LL_TIM_DisableCounter(TIM2);
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
LL_TIM_SetPrescaler(TIM2, 0);
LL_TIM_SetAutoReload(TIM2, 0xFFF);
LL_TIM_SetCounter(TIM2, 0);
LL_TIM_EnableCounter(TIM2);
/* make sure request generation is disabled before modifying registers */
LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0);
/* generator 0 gets fed by EXTI_LINE4 */
LL_DMAMUX_SetRequestSignalID(NULL, LL_DMAMUX_REQ_GEN_0, LL_DMAMUX_REQ_GEN_EXTI_LINE4);
/* trigger on any edge - for now. should be only one? */
LL_DMAMUX_SetRequestGenPolarity(NULL, LL_DMAMUX_REQ_GEN_0, LL_DMAMUX_REQ_GEN_POL_RISING);
/* now enable request generation again */
LL_DMAMUX_EnableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0);
/* configure PB4 as source for EXTI_LINE4. shall it rain. */
LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTB, LL_GPIO_PIN_4);
#endif
} }
void nfcv_emu_deinit() { void nfcv_emu_deinit() {
@@ -469,6 +591,7 @@ bool nfcv_emu_loop(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t ti
bool in_critical = false; bool in_critical = false;
FURI_CRITICAL_DEFINE(); FURI_CRITICAL_DEFINE();
while(true) { while(true) {
bool state = furi_hal_gpio_read(&gpio_spi_r_miso); bool state = furi_hal_gpio_read(&gpio_spi_r_miso);
@@ -633,6 +756,7 @@ bool nfcv_emu_loop(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t ti
if(timeout && cur_time > timeout) { if(timeout && cur_time > timeout) {
break; break;
} }
/* might exit early on overflows. guess thats okay. */ /* might exit early on overflows. guess thats okay. */
if(cur_time > next_sleep) { if(cur_time > next_sleep) {
break; break;
@@ -659,8 +783,16 @@ bool nfcv_emu_loop(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t ti
nfcv_emu_handle_packet(nfc_data, nfcv_data, frame_payload, frame_pos); nfcv_emu_handle_packet(nfc_data, nfcv_data, frame_payload, frame_pos);
ret = true; ret = true;
} }
/*
furi_delay_ms(0); printf("nfcv_timer_buffer: %ld", LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_4));
for(uint32_t pos = 0; pos < 64; pos++) {
if((pos % 4) == 0) {
printf("\r\n");
}
printf(" 0x%08lX ", nfcv_timer_buffer[pos]);
}
furi_delay_ms(100);
*/
return ret; return ret;
} }

View File

@@ -81,31 +81,71 @@ typedef enum {
} NfcVAuthMethod; } NfcVAuthMethod;
typedef enum { typedef enum {
NfcVTypeSlix, NfcVTypePlain = 0,
NfcVTypeSlixS, NfcVTypeSlix = 1,
NfcVTypeSlixL, NfcVTypeSlixS = 2,
NfcVTypeSlix2, NfcVTypeSlixL = 3,
NfcVTypeSlix2 = 4,
} NfcVType; } NfcVType;
typedef struct { typedef struct {
NfcVType type; uint8_t key_eas[4];
NfcVAuthMethod auth_method; uint8_t rand[2];
bool auth_success; } NfcVSlixData;
typedef struct {
uint8_t key_read[4];
uint8_t key_write[4];
uint8_t key_privacy[4]; uint8_t key_privacy[4];
uint8_t key_destroy[4]; uint8_t key_destroy[4];
uint8_t key_eas[4]; uint8_t key_eas[4];
uint8_t rand[2];
bool privacy;
} NfcVSlix2Data;
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;
} NfcVSlixSData;
typedef struct {
uint8_t key_privacy[4];
uint8_t key_destroy[4];
uint8_t key_eas[4];
uint8_t rand[2];
bool privacy;
} NfcVSlixLData;
typedef union {
NfcVSlixData slix;
NfcVSlix2Data slix2;
NfcVSlixSData slix_s;
NfcVSlixLData slix_l;
} NfcVSubtypeData;
typedef struct {
/* common ISO15693 fields */
uint8_t dsfid; uint8_t dsfid;
uint8_t afi; uint8_t afi;
uint8_t ic_ref; uint8_t ic_ref;
uint8_t block_num; uint8_t block_num;
uint8_t block_size; uint8_t block_size;
uint8_t data[NFCV_MAX_DUMP_SIZE]; uint8_t data[NFCV_MAX_DUMP_SIZE];
bool privacy;
char error[32]; /* specfic variant infos */
NfcVType type;
NfcVSubtypeData sub_data;
/* runtime data */
char last_command[128]; char last_command[128];
char error[32];
NfcVAuthMethod auth_method;
bool auth_success;
} NfcVData; } NfcVData;
typedef struct { typedef struct {

View File

@@ -1,14 +1,45 @@
#include <limits.h> #include <limits.h>
#include "nfcv.h" #include "nfcv.h"
#include "slix_l.h" #include "slix.h"
#include "nfc_util.h" #include "nfc_util.h"
#include <furi.h> #include <furi.h>
#include "furi_hal_nfc.h" #include "furi_hal_nfc.h"
bool slix_l_check_card_type(uint8_t UID0, uint8_t UID1, uint8_t UID2) { bool slix_check_card_type(FuriHalNfcDevData* nfc_data) {
if((UID0 == 0xE0) && (UID1 == 0x04) && (UID2 == 0x03)) { if((nfc_data->uid[0] == 0xE0)
&& (nfc_data->uid[1] == 0x04)
&& (nfc_data->uid[2] == 0x01)
&& (((nfc_data->uid[3] >> 4) & 3) == 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)
&& (((nfc_data->uid[3] >> 4) & 3) == 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 true;
} }
return false; return false;
@@ -49,10 +80,10 @@ ReturnCode slix_l_unlock(uint32_t id, uint8_t* rand, uint32_t password) {
uint8_t rxBuf[32]; uint8_t rxBuf[32];
uint8_t cmd_set_pass[] = { uint8_t cmd_set_pass[] = {
id, id,
rand[0] ^ ((password>>0) & 0xFF), rand[0] ^ ((password >> 0) & 0xFF),
rand[1] ^ ((password>>8) & 0xFF), rand[1] ^ ((password >> 8) & 0xFF),
rand[0] ^ ((password>>16) & 0xFF), rand[0] ^ ((password >> 16) & 0xFF),
rand[1] ^ ((password>>24) & 0xFF) rand[1] ^ ((password >> 24) & 0xFF)
}; };
ReturnCode ret = rfalNfcvPollerTransceiveReq( ReturnCode ret = rfalNfcvPollerTransceiveReq(

View File

@@ -10,8 +10,10 @@
#define ISO15693_MANUFACTURER_NXP 0x04 #define ISO15693_MANUFACTURER_NXP 0x04
bool slix_l_check_card_type(uint8_t UID0, uint8_t UID1, uint8_t UID2); 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_l_get_random(uint8_t* rand); ReturnCode slix_l_get_random(uint8_t* rand);
ReturnCode slix_l_unlock(uint32_t id, uint8_t* rand, uint32_t password); ReturnCode slix_l_unlock(uint32_t id, uint8_t* rand, uint32_t password);