mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-01 22:08:55 -07:00
cleaned up SLIX code
fixed byte order mixup read larger cards
This commit is contained in:
@@ -276,7 +276,7 @@ static void nfc_cli_st25r_trans(Cli* cli, FuriString* args) {
|
||||
printf("ISO15693 emulator...\r\nPress Ctrl+C to abort\r\n");
|
||||
|
||||
FuriHalNfcDevData nfc_data = {
|
||||
.uid = { 0x36, 0x78, 0x45, 0x0E, 0x50, 0x03, 0x04, 0xE0 },
|
||||
.uid = { 0xE0, 0x04, 0x45, 0x03, 0x50, 0x0E, 0x78, 0x36 },
|
||||
.uid_len = 8,
|
||||
.type = FuriHalNfcTypeV,
|
||||
};
|
||||
@@ -295,7 +295,7 @@ static void nfc_cli_st25r_trans(Cli* cli, FuriString* args) {
|
||||
|
||||
memset(nfcv_data.data, 0xAE, 4 * 8);
|
||||
|
||||
nfcv_emu_init();
|
||||
nfcv_emu_init(&nfc_data, &nfcv_data);
|
||||
while(!cli_cmd_interrupt_received(cli)) {
|
||||
if(nfcv_emu_loop(&nfc_data, &nfcv_data, 1000)) {
|
||||
printf("[NfcV-Emu] %s\r\n", nfcv_data.last_command);
|
||||
|
||||
@@ -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) {
|
||||
Nfc* nfc = context;
|
||||
Widget* widget = nfc->widget;
|
||||
@@ -85,13 +96,59 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
|
||||
|
||||
furi_string_cat_printf(temp_str, "Data (%d byte)\n", nfcv_data->block_num * nfcv_data->block_size);
|
||||
|
||||
for(int block = 0; block < nfcv_data->block_num; block++) {
|
||||
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++) {
|
||||
for(int pos = 0; pos < nfcv_data->block_size; pos++) {
|
||||
furi_string_cat_printf(temp_str, " %02X", nfcv_data->data[block * nfcv_data->block_size + pos]);
|
||||
}
|
||||
furi_string_cat_printf(temp_str, "\n");
|
||||
}
|
||||
furi_string_cat_printf(temp_str, "\n");
|
||||
|
||||
switch (dev_data->nfcv_data.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_s.key_read));
|
||||
furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_write));
|
||||
furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_privacy));
|
||||
furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_destroy));
|
||||
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.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_l.key_privacy));
|
||||
furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_l.key_destroy));
|
||||
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_l.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.slix2.key_read));
|
||||
furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_write));
|
||||
furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_privacy));
|
||||
furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_destroy));
|
||||
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.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';
|
||||
furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type);
|
||||
|
||||
+13
-7
@@ -807,23 +807,26 @@ bool nfc_device_load_slix2_data(FlipperFormat* file, NfcDevice* dev) {
|
||||
|
||||
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 {
|
||||
uint32_t temp_uint32 = 0;
|
||||
uint8_t temp_uint8 = 0;
|
||||
|
||||
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;
|
||||
temp_uint32 = data->block_num;
|
||||
if(!flipper_format_write_uint32(file, "Block Count", &temp_uint32, 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;
|
||||
temp_uint8 = (uint8_t)data->type;
|
||||
if(!flipper_format_write_hex(file, "Subtype", &temp_uint8, 1)) break;
|
||||
|
||||
switch(data->type) {
|
||||
case NfcVTypePlain:
|
||||
if(!flipper_format_write_comment_cstr(file, "End of ISO15693 parameters")) break;
|
||||
saved = true;
|
||||
break;
|
||||
case NfcVTypeSlix:
|
||||
@@ -846,16 +849,19 @@ static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) {
|
||||
|
||||
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 {
|
||||
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_hex(file, "Block Count", &(data->block_num), 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))
|
||||
|
||||
+60
-57
@@ -6,6 +6,7 @@
|
||||
|
||||
#define TAG "NfcWorker"
|
||||
|
||||
|
||||
/***************************** NFC Worker API *******************************/
|
||||
|
||||
NfcWorker* nfc_worker_alloc() {
|
||||
@@ -122,6 +123,31 @@ int32_t nfc_worker_task(void* context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool nfc_worker_read_nfcv_content(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;
|
||||
|
||||
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_unlock(NfcWorker* nfc_worker) {
|
||||
furi_assert(nfc_worker);
|
||||
@@ -129,6 +155,8 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
||||
|
||||
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
|
||||
FuriHalNfcTxRxContext tx_rx = {};
|
||||
uint8_t *key_data = nfcv_data->sub_data.slix_l.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);
|
||||
@@ -153,21 +181,20 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
||||
furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc);
|
||||
furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCV);
|
||||
|
||||
uint8_t rand[2];
|
||||
|
||||
furi_hal_console_printf("Detect presence\r\n");
|
||||
ReturnCode ret = slix_l_get_random(rand);
|
||||
ReturnCode ret = slix_l_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;
|
||||
|
||||
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");
|
||||
@@ -190,21 +217,32 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
||||
while(slix_l_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) {
|
||||
uint32_t key = 0;
|
||||
uint8_t *key_data = nfc_worker->dev_data->nfcv_data.sub_data.slix_l.key_privacy;
|
||||
|
||||
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);
|
||||
|
||||
ret = slix_l_unlock(nfcv_data, 4);
|
||||
} else {
|
||||
ret = slix_l_unlock(4, rand, 0x7FFD6E5B);
|
||||
key = 0x7FFD6E5B;
|
||||
key_data[0] = key >> 24;
|
||||
key_data[1] = key >> 16;
|
||||
key_data[2] = key >> 8;
|
||||
key_data[3] = key >> 0;
|
||||
ret = slix_l_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");
|
||||
@@ -214,10 +252,16 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
||||
furi_delay_ms(20);
|
||||
furi_hal_nfc_ll_txrx_on();
|
||||
|
||||
if(slix_l_get_random(rand) != ERR_NONE) {
|
||||
if(slix_l_get_random(nfcv_data) != ERR_NONE) {
|
||||
furi_hal_console_printf(" reset failed\r\n");
|
||||
}
|
||||
ret = slix_l_unlock(4, rand, 0x0F0F0F0F);
|
||||
|
||||
key = 0x0F0F0F0F;
|
||||
key_data[0] = key >> 24;
|
||||
key_data[1] = key >> 16;
|
||||
key_data[2] = key >> 8;
|
||||
key_data[3] = key >> 0;
|
||||
ret = slix_l_unlock(nfcv_data, 4);
|
||||
}
|
||||
}
|
||||
if(ret != ERR_NONE) {
|
||||
@@ -251,27 +295,6 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool nfc_worker_read_nfcv_content(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||
bool read_success = false;
|
||||
NfcVReader reader = {};
|
||||
|
||||
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_worker->dev_data->nfc_data, &nfc_worker->dev_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;
|
||||
}
|
||||
|
||||
|
||||
static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||
@@ -491,9 +514,6 @@ static bool nfc_worker_read_nfcv(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* t
|
||||
furi_assert(nfc_worker);
|
||||
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();
|
||||
|
||||
@@ -501,24 +521,6 @@ static bool nfc_worker_read_nfcv(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* t
|
||||
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");
|
||||
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 {
|
||||
nfcv_data->type = NfcVTypePlain;
|
||||
}
|
||||
|
||||
return card_read;
|
||||
}
|
||||
|
||||
@@ -570,12 +572,13 @@ void nfc_worker_read(NfcWorker* nfc_worker) {
|
||||
break;
|
||||
} else if(nfc_data->type == FuriHalNfcTypeV) {
|
||||
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;
|
||||
//event = NfcWorkerEventReadNfcV;
|
||||
//break;
|
||||
}
|
||||
event = NfcWorkerEventReadUidNfcV;
|
||||
event = NfcWorkerEventReadNfcV;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -622,7 +625,7 @@ void nfc_worker_emulate_nfcv(NfcWorker* nfc_worker) {
|
||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
|
||||
|
||||
nfcv_emu_init();
|
||||
nfcv_emu_init(nfc_data, nfcv_data);
|
||||
while(nfc_worker->state == NfcWorkerStateNfcVEmulate) {
|
||||
if(nfcv_emu_loop(nfc_data, nfcv_data, 1000)) {
|
||||
if(nfc_worker->callback) {
|
||||
|
||||
+100
-27
@@ -15,15 +15,24 @@
|
||||
|
||||
#include "nfcv.h"
|
||||
#include "nfc_util.h"
|
||||
#include "slix.h"
|
||||
|
||||
#define TAG "NfcV"
|
||||
|
||||
ReturnCode nfcv_inventory(uint8_t* uid) {
|
||||
uint16_t received = 0;
|
||||
rfalNfcvInventoryRes res;
|
||||
ReturnCode ret = ERR_NONE;
|
||||
|
||||
/* TODO: needs proper abstraction via fury_hal(_ll)_* */
|
||||
ReturnCode ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &res, &received);
|
||||
for(int tries = 0; tries < 5; tries++) {
|
||||
/* TODO: needs proper abstraction via fury_hal(_ll)_* */
|
||||
ret = rfalNfcvPollerInventory(
|
||||
RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &res, &received);
|
||||
|
||||
if(ret == ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ret == ERR_NONE) {
|
||||
if(uid != NULL) {
|
||||
@@ -37,18 +46,24 @@ ReturnCode nfcv_inventory(uint8_t* uid) {
|
||||
ReturnCode nfcv_read_blocks(
|
||||
NfcVReader* reader,
|
||||
NfcVData* data) {
|
||||
|
||||
reader->blocks_read = 0;
|
||||
|
||||
UNUSED(reader);
|
||||
|
||||
uint16_t received = 0;
|
||||
for(size_t block = 0; block < data->block_num; block++) {
|
||||
uint8_t rxBuf[32];
|
||||
FURI_LOG_D(TAG, "Reading block %d", block);
|
||||
FURI_LOG_D(TAG, "Reading block %d/%d", block, (data->block_num - 1));
|
||||
|
||||
ReturnCode ret = rfalNfcvPollerReadSingleBlock(
|
||||
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block,
|
||||
rxBuf, sizeof(rxBuf), &received);
|
||||
ReturnCode ret = ERR_NONE;
|
||||
for(int tries = 0; tries < 5; tries++) {
|
||||
ret = rfalNfcvPollerReadSingleBlock(
|
||||
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block,
|
||||
rxBuf, sizeof(rxBuf), &received);
|
||||
|
||||
if(ret == ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ret != ERR_NONE) {
|
||||
FURI_LOG_D(TAG, "failed to read: %d", ret);
|
||||
return ret;
|
||||
@@ -57,24 +72,27 @@ ReturnCode nfcv_read_blocks(
|
||||
FURI_LOG_D(TAG, " %02X %02X %02X %02X",
|
||||
data->data[block * data->block_size + 0], data->data[block * data->block_size + 1],
|
||||
data->data[block * data->block_size + 2], data->data[block * data->block_size + 3]);
|
||||
|
||||
reader->blocks_read++;
|
||||
}
|
||||
|
||||
FURI_LOG_D(TAG, "Read %d blocks", reader->blocks_read);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data) {
|
||||
uint8_t rxBuf[32];
|
||||
uint16_t received = 0;
|
||||
ReturnCode ret = ERR_NONE;
|
||||
|
||||
FURI_LOG_D(TAG, "Read SystemInformation...");
|
||||
FURI_LOG_D(TAG, "Read SYSTEM INFORMATION...");
|
||||
|
||||
ReturnCode ret = rfalNfcvPollerGetSystemInformation(
|
||||
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL,
|
||||
rxBuf, sizeof(rxBuf), &received);
|
||||
for(int tries = 0; tries < 5; tries++) {
|
||||
/* TODO: needs proper abstraction via fury_hal(_ll)_* */
|
||||
ret = rfalNfcvPollerGetSystemInformation(
|
||||
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, rxBuf, sizeof(rxBuf), &received);
|
||||
|
||||
if(ret == ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ret == ERR_NONE) {
|
||||
nfc_data->type = FuriHalNfcTypeV;
|
||||
@@ -88,6 +106,9 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data) {
|
||||
data->block_num = rxBuf[12] + 1;
|
||||
data->block_size = rxBuf[13] + 1;
|
||||
data->ic_ref = rxBuf[14];
|
||||
FURI_LOG_D(TAG, " UID: %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]);
|
||||
FURI_LOG_D(TAG, " DSFID %d, AFI %d, Blocks %d, Size %d, IC Ref %d", data->dsfid, data->afi, data->block_num, data->block_size, data->ic_ref);
|
||||
return ret;
|
||||
}
|
||||
@@ -101,14 +122,34 @@ bool nfcv_read_card(
|
||||
FuriHalNfcDevData* nfc_data,
|
||||
NfcVData* nfcv_data) {
|
||||
furi_assert(reader);
|
||||
furi_assert(nfc_data);
|
||||
furi_assert(nfcv_data);
|
||||
|
||||
if(nfcv_read_sysinfo(nfc_data, nfcv_data) != ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
reader->blocks_to_read = nfcv_data->block_num;
|
||||
return (nfcv_read_blocks(reader, nfcv_data) == ERR_NONE);
|
||||
if(nfcv_read_blocks(reader, nfcv_data) != ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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-S detected");
|
||||
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 {
|
||||
nfcv_data->type = NfcVTypePlain;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* emulation part */
|
||||
@@ -296,7 +337,26 @@ int nfcv_uidcmp(uint8_t *dst, uint8_t *src) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t nfcv_read_le(uint8_t *data, uint32_t length) {
|
||||
uint32_t value = 0;
|
||||
|
||||
for(uint32_t pos = 0; pos < length; pos++) {
|
||||
value |= data[pos] << ((int)pos * 8);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t nfcv_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;
|
||||
}
|
||||
|
||||
void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint8_t* payload, uint32_t payload_length) {
|
||||
|
||||
@@ -307,7 +367,7 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
|
||||
uint8_t flags = payload[0];
|
||||
uint8_t command = payload[1];
|
||||
bool addressed = !(flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && (flags & RFAL_NFCV_REQ_FLAG_ADDRESS);
|
||||
bool advanced = addressed && (command >= 0xA0);
|
||||
bool advanced = (command >= 0xA0);
|
||||
uint8_t address_offset = 2 + (advanced ? 1 : 0);
|
||||
uint8_t payload_offset = address_offset + (addressed ? 8 : 0);
|
||||
uint8_t *address = &payload[address_offset];
|
||||
@@ -315,7 +375,7 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
|
||||
if(addressed && nfcv_uidcmp(address, nfc_data->uid)) {
|
||||
printf("addressed packet, but not for us:\r\n");
|
||||
printf(" destination: %02X%02X%02X%02X%02X%02X%02X%02X\r\n", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]);
|
||||
printf(" our UID: %02X%02X%02X%02X%02X%02X%02X%02X\r\n", 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]);
|
||||
printf(" our UID: %02X%02X%02X%02X%02X%02X%02X%02X\r\n", 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]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -326,7 +386,9 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
|
||||
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)");
|
||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "command 0x%02X ignored, privacy mode", command);
|
||||
FURI_LOG_D(TAG, "%s", nfcv_data->last_command);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -434,8 +496,8 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
|
||||
nfcv_data->sub_data.slix_l.rand[1] = 0x00;
|
||||
|
||||
response_buffer[0] = ISO15693_NOERROR;
|
||||
response_buffer[1] = nfcv_data->sub_data.slix_l.rand[0];
|
||||
response_buffer[2] = nfcv_data->sub_data.slix_l.rand[1];
|
||||
response_buffer[1] = nfcv_data->sub_data.slix_l.rand[1];
|
||||
response_buffer[2] = nfcv_data->sub_data.slix_l.rand[0];
|
||||
|
||||
nfcv_emu_send(response_buffer, 3);
|
||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "GET_RANDOM_NUMBER");
|
||||
@@ -466,14 +528,16 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
|
||||
}
|
||||
|
||||
for(int pos = 0; pos < 4; pos++) {
|
||||
password_rcv[pos] = password_xored[pos] ^ rand[pos % 2];
|
||||
password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2];
|
||||
}
|
||||
uint32_t pass_expect = nfcv_read_be(password, 4);
|
||||
uint32_t pass_received = nfcv_read_be(password_rcv, 4);
|
||||
|
||||
if(!memcmp(password, password_rcv, 4)) {
|
||||
if(pass_expect == pass_received) {
|
||||
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);
|
||||
FURI_LOG_D(TAG, "Password #%d mismatch. Expected 0x%08lX, got 0x%08lX", password_id, pass_expect, pass_received);
|
||||
}
|
||||
|
||||
response_buffer[0] = status;
|
||||
@@ -505,7 +569,7 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui
|
||||
uint32_t nfcv_timer_buffer_src[32];
|
||||
uint32_t nfcv_timer_buffer[1024];
|
||||
|
||||
void nfcv_emu_init() {
|
||||
void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
|
||||
nfcv_emu_alloc();
|
||||
rfal_platform_spi_acquire();
|
||||
|
||||
@@ -516,6 +580,15 @@ void nfcv_emu_init() {
|
||||
|
||||
furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc);
|
||||
|
||||
|
||||
FURI_LOG_D(TAG, "Starting NfcV emulation");
|
||||
FURI_LOG_D(TAG, " UID: %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]);
|
||||
FURI_LOG_D(TAG, " Card type: %d", nfcv_data->type);
|
||||
FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", nfcv_read_be(nfcv_data->sub_data.slix_l.key_privacy, 4));
|
||||
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix_l.privacy ? "ON" : "OFF");
|
||||
|
||||
#if 0
|
||||
memset(nfcv_timer_buffer_src, 0xEE, sizeof(nfcv_timer_buffer_src));
|
||||
memset(nfcv_timer_buffer, 0xFA, sizeof(nfcv_timer_buffer));
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#define DIGITAL_SIGNAL_UNIT_S (100000000000.0f)
|
||||
#define DIGITAL_SIGNAL_UNIT_US (100000.0f)
|
||||
|
||||
#define NFCV_TOTAL_BLOCKS_MAX 32
|
||||
#define NFCV_TOTAL_BLOCKS_MAX 256
|
||||
#define NFCV_BLOCK_SIZE 4
|
||||
#define NFCV_MAX_DUMP_SIZE (NFCV_BLOCK_SIZE*NFCV_TOTAL_BLOCKS_MAX)
|
||||
|
||||
@@ -133,7 +133,7 @@ typedef struct {
|
||||
uint8_t dsfid;
|
||||
uint8_t afi;
|
||||
uint8_t ic_ref;
|
||||
uint8_t block_num;
|
||||
uint16_t block_num;
|
||||
uint8_t block_size;
|
||||
uint8_t data[NFCV_MAX_DUMP_SIZE];
|
||||
|
||||
@@ -158,6 +158,6 @@ 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();
|
||||
void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data);
|
||||
void nfcv_emu_deinit();
|
||||
bool nfcv_emu_loop(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms);
|
||||
|
||||
@@ -46,7 +46,7 @@ bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data) {
|
||||
}
|
||||
|
||||
|
||||
ReturnCode slix_l_get_random(uint8_t* rand) {
|
||||
ReturnCode slix_l_get_random(NfcVData* data) {
|
||||
uint16_t received = 0;
|
||||
uint8_t rxBuf[32];
|
||||
|
||||
@@ -65,26 +65,50 @@ ReturnCode slix_l_get_random(uint8_t* rand) {
|
||||
if(received != 3) {
|
||||
return ERR_PROTO;
|
||||
}
|
||||
if(rand != NULL) {
|
||||
memcpy(rand, &rxBuf[1], 2);
|
||||
if(data != NULL) {
|
||||
data->sub_data.slix_l.rand[0] = rxBuf[2];
|
||||
data->sub_data.slix_l.rand[1] = rxBuf[1];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ReturnCode slix_l_unlock(uint32_t id, uint8_t* rand, uint32_t password) {
|
||||
ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id) {
|
||||
furi_assert(rand);
|
||||
|
||||
uint16_t received = 0;
|
||||
uint8_t rxBuf[32];
|
||||
uint8_t cmd_set_pass[] = {
|
||||
id,
|
||||
rand[0] ^ ((password >> 0) & 0xFF),
|
||||
rand[1] ^ ((password >> 8) & 0xFF),
|
||||
rand[0] ^ ((password >> 16) & 0xFF),
|
||||
rand[1] ^ ((password >> 24) & 0xFF)
|
||||
password_id,
|
||||
data->sub_data.slix_l.rand[1],
|
||||
data->sub_data.slix_l.rand[0],
|
||||
data->sub_data.slix_l.rand[1],
|
||||
data->sub_data.slix_l.rand[0]
|
||||
};
|
||||
uint8_t *password = NULL;
|
||||
|
||||
switch(password_id) {
|
||||
case 4:
|
||||
password = data->sub_data.slix_l.key_privacy;
|
||||
break;
|
||||
case 8:
|
||||
password = data->sub_data.slix_l.key_destroy;
|
||||
break;
|
||||
case 10:
|
||||
password = data->sub_data.slix_l.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,
|
||||
|
||||
@@ -14,6 +14,6 @@ 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);
|
||||
ReturnCode slix_l_get_random(NfcVData* data);
|
||||
ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user