diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 180c7ba8f..80d8c6984 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -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); diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index bee3cc36d..a7ffccdb8 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -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); diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 886944fb1..9ff19bc1e 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -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)) diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 6533cc94c..805a34e0d 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -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) { diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index 1f94211fc..9a06e133f 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -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)); diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index e8188cb3f..be5b090f4 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -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); diff --git a/lib/nfc/protocols/slix.c b/lib/nfc/protocols/slix.c index e7dfe44be..ca3ebcd67 100644 --- a/lib/nfc/protocols/slix.c +++ b/lib/nfc/protocols/slix.c @@ -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, diff --git a/lib/nfc/protocols/slix.h b/lib/nfc/protocols/slix.h index 0bcfe702a..b95a27abd 100644 --- a/lib/nfc/protocols/slix.h +++ b/lib/nfc/protocols/slix.h @@ -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);