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) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
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) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
} else {

View File

@@ -286,8 +286,11 @@ static void nfc_cli_st25r_trans(Cli* cli, FuriString* args) {
.block_num = 8,
.block_size = 4,
.ic_ref = 3,
.key_privacy = { 0x0F, 0x0F, 0x0F, 0x0F },
.privacy = false
.type = NfcVTypeSlixL,
.sub_data.slix_l = {
.key_privacy = { 0x0F, 0x0F, 0x0F, 0x0F },
.privacy = false
}
};
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;
uint8_t text_scroll_height = 0;
if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl)
|| (protocol == NfcDeviceProtocolSlixL) || (protocol == NfcDeviceProtocolNfcV)) {
|| (protocol == NfcDeviceProtocolNfcV)) {
widget_add_button_element(
widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc);
text_scroll_height = 52;
@@ -42,15 +42,33 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n");
} else if(protocol == NfcDeviceProtocolNfcV) {
furi_string_cat_printf(temp_str, "\e#ISO15693\n");
} else if(protocol == NfcDeviceProtocolSlixL) {
furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-L\n");
switch (dev_data->nfcv_data.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 {
furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n");
}
// Set tag iso data
if((protocol == NfcDeviceProtocolSlixL) || (protocol == NfcDeviceProtocolNfcV)) {
if(protocol == NfcDeviceProtocolNfcV) {
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
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) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData);
consumed = true;
} else if(protocol == NfcDeviceProtocolSlixL) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu);
consumed = true;
} else if(protocol == NfcDeviceProtocolNfcV) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu);
consumed = true;

View File

@@ -3,8 +3,9 @@
void nfc_scene_nfcv_key_input_byte_input_callback(void* 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 File

@@ -33,7 +33,7 @@ bool nfc_scene_nfcv_menu_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSave) {
nfc->dev->format = NfcDeviceSaveFormatSlixL;
nfc->dev->format = NfcDeviceSaveFormatNfcV;
// Clear device name
nfc_device_set_name(nfc->dev, "");
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) {
Nfc* nfc = context;
NfcVSlixLData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix_l;
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 {
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
}
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) {
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) {
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[3], nfc_data->uid[2], nfc_data->uid[1], nfc_data->uid[0]);
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 = NfcDeviceSaveFormatSlixL;
nfc->dev->format = NfcDeviceSaveFormatNfcV;
if(nfc_device_save(nfc->dev, nfc->text_store)) {
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_scene_rpc_emulate_callback,
nfc);
} else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) {
nfc_worker_start(
nfc->worker,
NfcWorkerStateNfcVEmulate,
&nfc->dev->dev_data,
nfc_scene_rpc_emulate_callback,
nfc);
} else {
nfc_worker_start(
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);
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
} else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateNfcV);
} else {
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");
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
furi_string_set(format_string, "Mifare DESFire");
} else if(dev->format == NfcDeviceSaveFormatSlixL) {
furi_string_set(format_string, "NXP SLIX-L");
} else if(dev->format == NfcDeviceSaveFormatNfcV) {
furi_string_set(format_string, "ISO15693");
} else {
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;
return true;
}
if(furi_string_start_with_str(format_string, "NXP SLIX-L")) {
dev->format = NfcDeviceSaveFormatSlixL;
dev->dev_data.protocol = NfcDeviceProtocolSlixL;
if(furi_string_start_with_str(format_string, "ISO15693")) {
dev->format = NfcDeviceSaveFormatNfcV;
dev->dev_data.protocol = NfcDeviceProtocolNfcV;
return true;
}
return false;
@@ -643,21 +643,92 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
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) {
bool saved = false;
NfcVData* data = &dev->dev_data.nfcv_data;
NfcVSlixLData* data = &dev->dev_data.nfcv_data.sub_data.slix_l;
do {
if(!flipper_format_write_comment_cstr(file, "SLIX-L specific data")) break;
if(!flipper_format_write_hex(file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) break;
if(!flipper_format_write_hex(file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) break;
if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) break;
if(!flipper_format_write_hex(file, "DSFID", &(data->dsfid), 1)) break;
if(!flipper_format_write_hex(file, "AFI", &(data->afi), 1)) break;
if(!flipper_format_write_hex(file, "IC Reference", &(data->ic_ref), 1)) break;
if(!flipper_format_write_hex(file, "Block Count", &(data->block_num), 1)) break;
if(!flipper_format_write_hex(file, "Block Size", &(data->block_size), 1)) break;
if(!flipper_format_write_hex(file, "Data Content", data->data, data->block_num * data->block_size)) break;
if(!flipper_format_write_bool(file, "Privacy Mode", &data->privacy, 1)) break;
saved = true;
} 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 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));
do {
@@ -679,7 +750,108 @@ bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
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;
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, "AFI", &(data->afi), 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(
file, "Data Content", data->data, data->block_num * data->block_size))
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);
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;
// Write nfc device type
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;
nfc_device_prepare_format_string(dev, temp_str);
if(!flipper_format_write_string(file, "Device type", temp_str)) break;
// 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;
if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
if(dev->format != NfcDeviceSaveFormatSlixL) {
if(dev->format != NfcDeviceSaveFormatNfcV) {
// 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, "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;
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
if(!nfc_device_save_mifare_df_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatSlixL) {
if(!nfc_device_save_slix_l_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatNfcV) {
if(!nfc_device_save_nfcv_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
if(!nfc_device_save_bank_card_data(file, dev)) break;
} 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;
data->uid_len = data_cnt;
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, "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;
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
if(!nfc_device_load_mifare_df_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatSlixL) {
if(!nfc_device_load_slix_l_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatNfcV) {
if(!nfc_device_load_nfcv_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
if(!nfc_device_load_bank_card_data(file, dev)) break;
}

View File

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

View File

@@ -176,11 +176,12 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
if(nfcv_data->auth_method == NfcVAuthMethodManual) {
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 |= nfc_worker->dev_data->nfcv_data.key_privacy[1] << 16;
key |= nfc_worker->dev_data->nfcv_data.key_privacy[2] << 8;
key |= nfc_worker->dev_data->nfcv_data.key_privacy[3] << 0;
key |= key_data[0] << 24;
key |= key_data[1] << 16;
key |= key_data[2] << 8;
key |= key_data[3] << 0;
ret = slix_l_unlock(4, rand, key);
} else {
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);
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
bool card_read = false;
furi_hal_nfc_sleep();
if(slix_l_check_card_type(nfc_data->uid[7], nfc_data->uid[6], nfc_data->uid[5])) {
/* 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");
nfc_worker->dev_data->protocol = NfcDeviceProtocolSlixL;
card_read = nfc_worker_read_nfcv_content(nfc_worker, tx_rx);
nfcv_data->type = NfcVTypeSlixS;
} else if(slix_l_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX-L detected");
nfcv_data->type = NfcVTypeSlixL;
} else {
FURI_LOG_I(TAG, "unknown detected");
nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV;
card_read = nfc_worker_read_nfcv_content(nfc_worker, tx_rx);
nfcv_data->type = NfcVTypePlain;
}
return card_read;

View File

@@ -13,7 +13,7 @@
#include <lib/nfc/protocols/mifare_desfire.h>
#include <lib/nfc/protocols/nfca.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>
struct NfcWorker {

View File

@@ -8,6 +8,10 @@
#include <furi_hal_resources.h>
#include <st25r3916.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 "nfc_util.h"
@@ -75,7 +79,7 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data) {
if(ret == ERR_NONE) {
nfc_data->type = FuriHalNfcTypeV;
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++) {
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];
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) {
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:
{
if(nfcv_data->privacy) {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY (ignored, privacy)");
} else {
response_buffer[0] = ISO15693_NOERROR;
response_buffer[1] = nfcv_data->dsfid; /* DSFID */
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);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY");
}
nfcv_emu_send(response_buffer, 10);
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;
}
@@ -386,11 +411,31 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
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:
{
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[1] = 0x00; /* set number to 0x0000 so we get the key in plaintext */
response_buffer[2] = 0x00;
response_buffer[1] = nfcv_data->sub_data.slix_l.rand[0];
response_buffer[2] = nfcv_data->sub_data.slix_l.rand[1];
nfcv_emu_send(response_buffer, 3);
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:
{
uint32_t pass = (payload[payload_offset + 1] << 24)
| (payload[payload_offset + 2] << 16)
| (payload[payload_offset + 3] << 8)
| (payload[payload_offset + 4] << 0);
uint8_t password_id = payload[payload_offset];
uint8_t *password_xored = &payload[payload_offset + 1];
uint8_t *rand = nfcv_data->sub_data.slix_l.rand;
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);
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;
}
@@ -420,7 +491,7 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
nfcv_emu_send(response_buffer, 1);
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;
}
@@ -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() {
nfcv_emu_alloc();
rfal_platform_spi_acquire();
@@ -440,6 +515,53 @@ void nfcv_emu_init() {
st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE);
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() {
@@ -469,6 +591,7 @@ bool nfcv_emu_loop(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t ti
bool in_critical = false;
FURI_CRITICAL_DEFINE();
while(true) {
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) {
break;
}
/* might exit early on overflows. guess thats okay. */
if(cur_time > next_sleep) {
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);
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;
}

View File

@@ -81,31 +81,71 @@ typedef enum {
} NfcVAuthMethod;
typedef enum {
NfcVTypeSlix,
NfcVTypeSlixS,
NfcVTypeSlixL,
NfcVTypeSlix2,
NfcVTypePlain = 0,
NfcVTypeSlix = 1,
NfcVTypeSlixS = 2,
NfcVTypeSlixL = 3,
NfcVTypeSlix2 = 4,
} NfcVType;
typedef struct {
NfcVType type;
NfcVAuthMethod auth_method;
bool auth_success;
uint8_t key_eas[4];
uint8_t rand[2];
} NfcVSlixData;
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;
} 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 afi;
uint8_t ic_ref;
uint8_t block_num;
uint8_t block_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 error[32];
NfcVAuthMethod auth_method;
bool auth_success;
} NfcVData;
typedef struct {

View File

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

View File

@@ -10,8 +10,10 @@
#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_unlock(uint32_t id, uint8_t* rand, uint32_t password);