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 cdc25908f..209933ba8 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -114,39 +114,81 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { 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.key_read)); - furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write)); - furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); - furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); - furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); - break; - case NfcVTypeSlixL: - furi_string_cat_printf(temp_str, "Type: SLIX-L\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); - furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); - furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); - break; - case NfcVTypeSlix2: - furi_string_cat_printf(temp_str, "Type: SLIX2\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf(temp_str, " Read %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read)); - furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write)); - furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); - furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); - furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); - break; + case NfcVTypePlain: + furi_string_cat_printf(temp_str, "Type: Plain\n"); + break; + case NfcVTypeSlix: + furi_string_cat_printf(temp_str, "Type: SLIX\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " EAS %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); + break; + case NfcVTypeSlixS: + furi_string_cat_printf(temp_str, "Type: SLIX-S\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " Read %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read)); + furi_string_cat_printf( + temp_str, + " Write %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write)); + furi_string_cat_printf( + temp_str, + " Privacy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); + furi_string_cat_printf( + temp_str, + " Destroy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); + furi_string_cat_printf( + temp_str, + " EAS %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); + break; + case NfcVTypeSlixL: + furi_string_cat_printf(temp_str, "Type: SLIX-L\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " Privacy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); + furi_string_cat_printf( + temp_str, + " Destroy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); + furi_string_cat_printf( + temp_str, + " EAS %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); + break; + case NfcVTypeSlix2: + furi_string_cat_printf(temp_str, "Type: SLIX2\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " Read %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read)); + furi_string_cat_printf( + temp_str, + " Write %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write)); + furi_string_cat_printf( + temp_str, + " Privacy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); + furi_string_cat_printf( + temp_str, + " Destroy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); + furi_string_cat_printf( + temp_str, + " EAS %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); + break; default: furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); break; diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 3a4ea58db..75452f47a 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -159,7 +159,7 @@ 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.key_privacy; + uint8_t* key_data = nfcv_data->sub_data.slix.key_privacy; uint32_t key = 0; if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index 6d0525ec8..c9927851c 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -22,8 +22,7 @@ ReturnCode nfcv_inventory(uint8_t* uid) { 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); + ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &res, &received); if(ret == ERR_NONE) { break; @@ -39,10 +38,7 @@ ReturnCode nfcv_inventory(uint8_t* uid) { return ret; } -ReturnCode nfcv_read_blocks( - NfcVReader* reader, - NfcVData* data) { - +ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data) { UNUSED(reader); uint16_t received = 0; @@ -53,8 +49,7 @@ ReturnCode nfcv_read_blocks( ReturnCode ret = ERR_NONE; for(int tries = 0; tries < 5; tries++) { ret = rfalNfcvPollerReadSingleBlock( - RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block, - rxBuf, sizeof(rxBuf), &received); + RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block, rxBuf, sizeof(rxBuf), &received); if(ret == ERR_NONE) { break; @@ -65,9 +60,13 @@ ReturnCode nfcv_read_blocks( return ret; } memcpy(&(data->data[block * data->block_size]), &rxBuf[1], data->block_size); - 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]); + 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]); } return ERR_NONE; @@ -102,10 +101,25 @@ 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); + 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; } FURI_LOG_D(TAG, "Failed: %d", ret); @@ -113,10 +127,7 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data) { return ret; } -bool nfcv_read_card( - NfcVReader* reader, - FuriHalNfcDevData* nfc_data, - NfcVData* nfcv_data) { +bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { furi_assert(reader); furi_assert(nfc_data); furi_assert(nfcv_data); @@ -148,15 +159,13 @@ bool nfcv_read_card( return true; } - - void nfcv_crc(uint8_t* data, uint32_t length) { uint32_t reg = 0xFFFF; - for (size_t i = 0; i < length; i++) { + for(size_t i = 0; i < length; i++) { reg = reg ^ ((uint32_t)data[i]); - for (size_t j = 0; j < 8; j++) { - if (reg & 0x0001) { + for(size_t j = 0; j < 8; j++) { + if(reg & 0x0001) { reg = (reg >> 1) ^ 0x8408; } else { reg = (reg >> 1); @@ -198,15 +207,18 @@ void nfcv_emu_alloc(NfcVData* data) { /* unmodulated 256/fc signal as building block */ data->emu_air.nfcv_resp_unmod_256 = digital_signal_alloc(4); data->emu_air.nfcv_resp_unmod_256->start_level = false; - data->emu_air.nfcv_resp_unmod_256->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S); + data->emu_air.nfcv_resp_unmod_256->edge_timings[0] = + (uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S); data->emu_air.nfcv_resp_unmod_256->edge_cnt = 1; } if(!data->emu_air.nfcv_resp_pulse_32) { /* modulated fc/32 pulse as building block */ data->emu_air.nfcv_resp_pulse_32 = digital_signal_alloc(4); data->emu_air.nfcv_resp_pulse_32->start_level = true; - data->emu_air.nfcv_resp_pulse_32->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); - data->emu_air.nfcv_resp_pulse_32->edge_timings[1] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + data->emu_air.nfcv_resp_pulse_32->edge_timings[0] = + (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + data->emu_air.nfcv_resp_pulse_32->edge_timings[1] = + (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); data->emu_air.nfcv_resp_pulse_32->edge_cnt = 2; } if(!data->emu_air.nfcv_resp_one) { @@ -250,16 +262,26 @@ void nfcv_emu_alloc(NfcVData* data) { digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_unmod_256); } - digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_SOF, data->emu_air.nfcv_resp_sof); - digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_BIT0, data->emu_air.nfcv_resp_zero); - digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_BIT1, data->emu_air.nfcv_resp_one); - digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_EOF, data->emu_air.nfcv_resp_eof); + digital_sequence_set_signal( + data->emu_air.nfcv_signal, NFCV_SIG_SOF, data->emu_air.nfcv_resp_sof); + digital_sequence_set_signal( + data->emu_air.nfcv_signal, NFCV_SIG_BIT0, data->emu_air.nfcv_resp_zero); + digital_sequence_set_signal( + data->emu_air.nfcv_signal, NFCV_SIG_BIT1, data->emu_air.nfcv_resp_one); + digital_sequence_set_signal( + data->emu_air.nfcv_signal, NFCV_SIG_EOF, data->emu_air.nfcv_resp_eof); } -void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, uint8_t length, NfcVSendFlags flags) { +void nfcv_emu_send( + FuriHalNfcTxRxContext* tx_rx, + NfcVData* nfcv, + uint8_t* data, + uint8_t length, + NfcVSendFlags flags) { /* picked default value (0) to match the most common format */ if(!flags) { - flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof | NfcVSendFlagsOneSubcarrier | NfcVSendFlagsHighRate; + flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof | + NfcVSendFlagsOneSubcarrier | NfcVSendFlagsHighRate; } if(flags & NfcVSendFlagsCrc) { @@ -278,7 +300,8 @@ void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, uint32_t bit_pos = bit_total % 8; uint8_t bit_val = 0x01 << bit_pos; - digital_sequence_add(nfcv->emu_air.nfcv_signal, (data[byte_pos] & bit_val) ? NFCV_SIG_BIT1 : NFCV_SIG_BIT0); + digital_sequence_add( + nfcv->emu_air.nfcv_signal, (data[byte_pos] & bit_val) ? NFCV_SIG_BIT1 : NFCV_SIG_BIT0); } if(flags & NfcVSendFlagsEof) { @@ -295,35 +318,40 @@ void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, } } -static void nfcv_uidcpy(uint8_t *dst, uint8_t *src) { +static void nfcv_uidcpy(uint8_t* dst, uint8_t* src) { for(int pos = 0; pos < 8; pos++) { - dst[pos] = src[7-pos]; + dst[pos] = src[7 - pos]; } } -static int nfcv_uidcmp(uint8_t *dst, uint8_t *src) { +static int nfcv_uidcmp(uint8_t* dst, uint8_t* src) { for(int pos = 0; pos < 8; pos++) { - if(dst[pos] != src[7-pos]) { + if(dst[pos] != src[7 - pos]) { return 1; } } return 0; } -void nfcv_emu_handle_packet(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in, uint8_t* payload, uint32_t payload_length) { - +void nfcv_emu_handle_packet( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in, + uint8_t* payload, + uint32_t payload_length) { if(!payload_length) { return; } NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; NfcVEmuProtocolCtx* ctx = &nfcv_data->emu_protocol_ctx; - + ctx->frame = payload; ctx->frame_length = payload_length; ctx->flags = ctx->frame[0]; ctx->command = ctx->frame[1]; - ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && (ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS); + ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && + (ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS); ctx->advanced = (ctx->command >= 0xA0); ctx->address_offset = 2 + (ctx->advanced ? 1 : 0); ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0); @@ -340,116 +368,165 @@ void nfcv_emu_handle_packet(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc uint8_t* address = &ctx->frame[ctx->address_offset]; if(nfcv_uidcmp(address, nfc_data->uid)) { FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", ctx->command); - FURI_LOG_D(TAG, " dest: %02X%02X%02X%02X%02X%02X%02X%02X", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]); - FURI_LOG_D(TAG, " our 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, + " dest: %02X%02X%02X%02X%02X%02X%02X%02X", + address[7], + address[6], + address[5], + address[4], + address[3], + address[2], + address[1], + address[0]); + FURI_LOG_D( + TAG, + " our 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]); return; } } - + /* unfortunately our response is quicker than the original NFC tag which causes frame misses */ furi_delay_us(270); switch(ctx->command) { - case ISO15693_INVENTORY: { - ctx->response_buffer[0] = ISO15693_NOERROR; - ctx->response_buffer[1] = nfcv_data->dsfid; - nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid); + case ISO15693_INVENTORY: { + ctx->response_buffer[0] = ISO15693_NOERROR; + ctx->response_buffer[1] = nfcv_data->dsfid; + nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid); - nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 10, ctx->response_flags); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY"); - break; + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 10, ctx->response_flags); + 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_SELECT: { + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT"); + break; + } + + case ISO15693_READ_MULTI_BLOCK: + case ISO15693_READBLOCK: { + uint8_t block = ctx->frame[ctx->payload_offset]; + uint8_t blocks = 1; + + if(ctx->command == ISO15693_READ_MULTI_BLOCK) { + blocks = ctx->frame[ctx->payload_offset + 1] + 1; } - 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_SELECT: { - ctx->response_buffer[0] = ISO15693_NOERROR; + if(block + blocks > nfcv_data->block_num) { + ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT"); - break; + } else { + ctx->response_buffer[0] = ISO15693_NOERROR; + memcpy( + &ctx->response_buffer[1], + &nfcv_data->data[nfcv_data->block_size * block], + nfcv_data->block_size * blocks); + nfcv_emu_send( + tx_rx, + nfcv_data, + ctx->response_buffer, + 1 + nfcv_data->block_size * blocks, + ctx->response_flags); + } + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block); + break; + } + + case ISO15693_WRITE_MULTI_BLOCK: + case ISO15693_WRITEBLOCK: { + uint8_t block = ctx->frame[ctx->payload_offset]; + uint8_t blocks = 1; + uint8_t data_pos = 1; + + if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { + blocks = ctx->frame[ctx->payload_offset + 1] + 1; + data_pos++; } - case ISO15693_READ_MULTI_BLOCK: - case ISO15693_READBLOCK: { - uint8_t block = ctx->frame[ctx->payload_offset]; - uint8_t blocks = 1; + uint8_t* data = &ctx->frame[ctx->payload_offset + data_pos]; + uint32_t data_len = nfcv_data->block_size * blocks; - if(ctx->command == ISO15693_READ_MULTI_BLOCK) { - blocks = ctx->frame[ctx->payload_offset + 1] + 1; - } - - if(block + blocks > nfcv_data->block_num) { - ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; - nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); - } else { - ctx->response_buffer[0] = ISO15693_NOERROR; - memcpy(&ctx->response_buffer[1], &nfcv_data->data[nfcv_data->block_size * block], nfcv_data->block_size * blocks); - nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1 + nfcv_data->block_size * blocks, ctx->response_flags); - } - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block); - break; + if(block + blocks > nfcv_data->block_num || + ctx->payload_offset + data_len + 2 > payload_length) { + ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; + } else { + ctx->response_buffer[0] = ISO15693_NOERROR; + memcpy( + &nfcv_data->data[nfcv_data->block_size * block], + &ctx->frame[ctx->payload_offset + data_pos], + data_len); } + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); - case ISO15693_WRITE_MULTI_BLOCK: - case ISO15693_WRITEBLOCK: { - uint8_t block = ctx->frame[ctx->payload_offset]; - uint8_t blocks = 1; - uint8_t data_pos = 1; - - if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { - blocks = ctx->frame[ctx->payload_offset + 1] + 1; - data_pos++; - } - - uint8_t *data = &ctx->frame[ctx->payload_offset + data_pos]; - uint32_t data_len = nfcv_data->block_size * blocks; - - if(block + blocks > nfcv_data->block_num || ctx->payload_offset + data_len + 2 > payload_length) { - ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; - } else { - ctx->response_buffer[0] = ISO15693_NOERROR; - memcpy(&nfcv_data->data[nfcv_data->block_size * block], &ctx->frame[ctx->payload_offset + data_pos], data_len); - } - nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); - - if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE MULTI BLOCK %d, %d blocks", block, blocks); - } else { - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE BLOCK %d <- %02X %02X %02X %02X", block, data[0], data[1], data[2], data[3]); - } - break; + if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "WRITE MULTI BLOCK %d, %d blocks", + block, + blocks); + } else { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "WRITE BLOCK %d <- %02X %02X %02X %02X", + block, + data[0], + data[1], + data[2], + data[3]); } + break; + } - case ISO15693_GET_SYSTEM_INFO: { - ctx->response_buffer[0] = ISO15693_NOERROR; - ctx->response_buffer[1] = 0x0F; - nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid); - ctx->response_buffer[10] = nfcv_data->dsfid; /* DSFID */ - ctx->response_buffer[11] = nfcv_data->afi; /* AFI */ - ctx->response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */ - ctx->response_buffer[13] = nfcv_data->block_size - 1; /* block size */ - ctx->response_buffer[14] = nfcv_data->ic_ref; /* IC reference */ + case ISO15693_GET_SYSTEM_INFO: { + ctx->response_buffer[0] = ISO15693_NOERROR; + ctx->response_buffer[1] = 0x0F; + nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid); + ctx->response_buffer[10] = nfcv_data->dsfid; /* DSFID */ + ctx->response_buffer[11] = nfcv_data->afi; /* AFI */ + ctx->response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */ + ctx->response_buffer[13] = nfcv_data->block_size - 1; /* block size */ + ctx->response_buffer[14] = nfcv_data->ic_ref; /* IC reference */ - nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 15, ctx->response_flags); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO"); - break; - } + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 15, ctx->response_flags); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO"); + break; + } - default: - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "unsupported: %02X", ctx->command); - break; + default: + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "unsupported: %02X", + ctx->command); + break; } if(strlen(nfcv_data->last_command) > 0) { - FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command); + FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command); } } @@ -467,30 +544,38 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { nfcv_data->emu_protocol_handler = &nfcv_emu_handle_packet; 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, + " 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]); switch(nfcv_data->type) { - case NfcVTypeSlixL: - FURI_LOG_D(TAG, " Card type: SLIX-L"); - slix_l_prepare(nfcv_data); - break; - case NfcVTypeSlixS: - FURI_LOG_D(TAG, " Card type: SLIX-S"); - slix_s_prepare(nfcv_data); - break; - case NfcVTypeSlix2: - FURI_LOG_D(TAG, " Card type: SLIX2"); - slix2_prepare(nfcv_data); - break; - case NfcVTypeSlix: - FURI_LOG_D(TAG, " Card type: SLIX"); - slix_prepare(nfcv_data); - break; - case NfcVTypePlain: - FURI_LOG_D(TAG, " Card type: Plain"); - break; + case NfcVTypeSlixL: + FURI_LOG_D(TAG, " Card type: SLIX-L"); + slix_l_prepare(nfcv_data); + break; + case NfcVTypeSlixS: + FURI_LOG_D(TAG, " Card type: SLIX-S"); + slix_s_prepare(nfcv_data); + break; + case NfcVTypeSlix2: + FURI_LOG_D(TAG, " Card type: SLIX2"); + slix2_prepare(nfcv_data); + break; + case NfcVTypeSlix: + FURI_LOG_D(TAG, " Card type: SLIX"); + slix_prepare(nfcv_data); + break; + case NfcVTypePlain: + FURI_LOG_D(TAG, " Card type: Plain"); + break; } /* allocate a 512 edge buffer, more than enough */ @@ -510,8 +595,11 @@ void nfcv_emu_deinit(NfcVData* nfcv_data) { pulse_reader_free(nfcv_data->emu_air.reader_signal); } -bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms) { - +bool nfcv_emu_loop( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + NfcVData* nfcv_data, + uint32_t timeout_ms) { bool ret = false; uint32_t frame_state = NFCV_FRAME_STATE_SOF1; uint32_t periods_previous = 0; @@ -523,8 +611,8 @@ bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, Nf bool wait_for_pulse = false; while(true) { - - uint32_t periods = pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout_ms * 1000); + uint32_t periods = + pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout_ms * 1000); if(periods == PULSE_READER_NO_EDGE) { break; @@ -533,113 +621,137 @@ bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, Nf if(wait_for_pulse) { wait_for_pulse = false; if(periods != 1) { - snprintf(reset_reason, sizeof(reset_reason), "SOF: Expected a single low pulse in state %lu, but got %lu", frame_state, periods); + snprintf( + reset_reason, + sizeof(reset_reason), + "SOF: Expected a single low pulse in state %lu, but got %lu", + frame_state, + periods); frame_state = NFCV_FRAME_STATE_RESET; } continue; } switch(frame_state) { - case NFCV_FRAME_STATE_SOF1: - if(periods == 1) { - frame_state = NFCV_FRAME_STATE_SOF2; - } else { - frame_state = NFCV_FRAME_STATE_SOF1; - break; - } + case NFCV_FRAME_STATE_SOF1: + if(periods == 1) { + frame_state = NFCV_FRAME_STATE_SOF2; + } else { + frame_state = NFCV_FRAME_STATE_SOF1; break; + } + break; - case NFCV_FRAME_STATE_SOF2: - /* waiting for the second low period, telling us about coding */ - if(periods == 6) { - frame_state = NFCV_FRAME_STATE_CODING_256; - periods_previous = 0; - wait_for_pulse = true; - } else if(periods == 4) { - frame_state = NFCV_FRAME_STATE_CODING_4; - periods_previous = 2; - wait_for_pulse = true; - } else { - snprintf(reset_reason, sizeof(reset_reason), "SOF: Expected 4/6 periods, got %lu", periods); - frame_state = NFCV_FRAME_STATE_SOF1; - } - break; - - case NFCV_FRAME_STATE_CODING_256: - if(periods_previous > periods) { - snprintf(reset_reason, sizeof(reset_reason), "1oo256: Missing %lu periods from previous symbol, got %lu", periods_previous, periods); - frame_state = NFCV_FRAME_STATE_RESET; - break; - } - /* previous symbol left us with some pulse periods */ - periods -= periods_previous; - - if(periods > 512) { - snprintf(reset_reason, sizeof(reset_reason), "1oo256: %lu periods is too much", periods); - frame_state = NFCV_FRAME_STATE_RESET; - break; - } - - if(periods == 2) { - frame_state = NFCV_FRAME_STATE_EOF; - break; - } - - periods_previous = 512 - (periods + 1); - byte_value = (periods - 1) / 2; - frame_payload[frame_pos++] = (uint8_t)byte_value; - - wait_for_pulse = true; - - break; - - case NFCV_FRAME_STATE_CODING_4: - if(periods_previous > periods) { - snprintf(reset_reason, sizeof(reset_reason), "1oo4: Missing %lu periods from previous symbol, got %lu", periods_previous, periods); - frame_state = NFCV_FRAME_STATE_RESET; - break; - } - - /* previous symbol left us with some pulse periods */ - periods -= periods_previous; + case NFCV_FRAME_STATE_SOF2: + /* waiting for the second low period, telling us about coding */ + if(periods == 6) { + frame_state = NFCV_FRAME_STATE_CODING_256; periods_previous = 0; - - byte_value >>= 2; - bits_received += 2; - - if(periods == 1) { - byte_value |= 0x00 << 6; - periods_previous = 6; - } else if(periods == 3) { - byte_value |= 0x01 << 6; - periods_previous = 4; - } else if(periods == 5) { - byte_value |= 0x02 << 6; - periods_previous = 2; - } else if(periods == 7) { - byte_value |= 0x03 << 6; - periods_previous = 0; - } else if(periods == 2) { - frame_state = NFCV_FRAME_STATE_EOF; - break; - } else { - snprintf(reset_reason, sizeof(reset_reason), "1oo4: Expected 1/3/5/7 low pulses, but got %lu", periods); - frame_state = NFCV_FRAME_STATE_RESET; - break; - } - - if(bits_received >= 8) { - frame_payload[frame_pos++] = (uint8_t)byte_value; - bits_received = 0; - } wait_for_pulse = true; + } else if(periods == 4) { + frame_state = NFCV_FRAME_STATE_CODING_4; + periods_previous = 2; + wait_for_pulse = true; + } else { + snprintf( + reset_reason, + sizeof(reset_reason), + "SOF: Expected 4/6 periods, got %lu", + periods); + frame_state = NFCV_FRAME_STATE_SOF1; + } + break; + + case NFCV_FRAME_STATE_CODING_256: + if(periods_previous > periods) { + snprintf( + reset_reason, + sizeof(reset_reason), + "1oo256: Missing %lu periods from previous symbol, got %lu", + periods_previous, + periods); + frame_state = NFCV_FRAME_STATE_RESET; break; + } + /* previous symbol left us with some pulse periods */ + periods -= periods_previous; + + if(periods > 512) { + snprintf( + reset_reason, sizeof(reset_reason), "1oo256: %lu periods is too much", periods); + frame_state = NFCV_FRAME_STATE_RESET; + break; + } + + if(periods == 2) { + frame_state = NFCV_FRAME_STATE_EOF; + break; + } + + periods_previous = 512 - (periods + 1); + byte_value = (periods - 1) / 2; + frame_payload[frame_pos++] = (uint8_t)byte_value; + + wait_for_pulse = true; + + break; + + case NFCV_FRAME_STATE_CODING_4: + if(periods_previous > periods) { + snprintf( + reset_reason, + sizeof(reset_reason), + "1oo4: Missing %lu periods from previous symbol, got %lu", + periods_previous, + periods); + frame_state = NFCV_FRAME_STATE_RESET; + break; + } + + /* previous symbol left us with some pulse periods */ + periods -= periods_previous; + periods_previous = 0; + + byte_value >>= 2; + bits_received += 2; + + if(periods == 1) { + byte_value |= 0x00 << 6; + periods_previous = 6; + } else if(periods == 3) { + byte_value |= 0x01 << 6; + periods_previous = 4; + } else if(periods == 5) { + byte_value |= 0x02 << 6; + periods_previous = 2; + } else if(periods == 7) { + byte_value |= 0x03 << 6; + periods_previous = 0; + } else if(periods == 2) { + frame_state = NFCV_FRAME_STATE_EOF; + break; + } else { + snprintf( + reset_reason, + sizeof(reset_reason), + "1oo4: Expected 1/3/5/7 low pulses, but got %lu", + periods); + frame_state = NFCV_FRAME_STATE_RESET; + break; + } + + if(bits_received >= 8) { + frame_payload[frame_pos++] = (uint8_t)byte_value; + bits_received = 0; + } + wait_for_pulse = true; + break; } - + /* post-state-machine cleanup and reset */ if(frame_state == NFCV_FRAME_STATE_RESET) { frame_state = NFCV_FRAME_STATE_SOF1; - + FURI_LOG_D(TAG, "Resetting state machine, reason: '%s'", reset_reason); } else if(frame_state == NFCV_FRAME_STATE_EOF) { break; diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index 435bcc235..3e76aa206 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -34,33 +34,33 @@ #define NFCV_SIG_EOF 3 /* ISO15693 command codes */ -#define ISO15693_INVENTORY 0x01 -#define ISO15693_STAYQUIET 0x02 -#define ISO15693_READBLOCK 0x20 -#define ISO15693_WRITEBLOCK 0x21 -#define ISO15693_LOCKBLOCK 0x22 -#define ISO15693_READ_MULTI_BLOCK 0x23 -#define ISO15693_WRITE_MULTI_BLOCK 0x24 -#define ISO15693_SELECT 0x25 -#define ISO15693_RESET_TO_READY 0x26 -#define ISO15693_WRITE_AFI 0x27 -#define ISO15693_LOCK_AFI 0x28 -#define ISO15693_WRITE_DSFID 0x29 -#define ISO15693_LOCK_DSFID 0x2A -#define ISO15693_GET_SYSTEM_INFO 0x2B -#define ISO15693_READ_MULTI_SECSTATUS 0x2C +#define ISO15693_INVENTORY 0x01 +#define ISO15693_STAYQUIET 0x02 +#define ISO15693_READBLOCK 0x20 +#define ISO15693_WRITEBLOCK 0x21 +#define ISO15693_LOCKBLOCK 0x22 +#define ISO15693_READ_MULTI_BLOCK 0x23 +#define ISO15693_WRITE_MULTI_BLOCK 0x24 +#define ISO15693_SELECT 0x25 +#define ISO15693_RESET_TO_READY 0x26 +#define ISO15693_WRITE_AFI 0x27 +#define ISO15693_LOCK_AFI 0x28 +#define ISO15693_WRITE_DSFID 0x29 +#define ISO15693_LOCK_DSFID 0x2A +#define ISO15693_GET_SYSTEM_INFO 0x2B +#define ISO15693_READ_MULTI_SECSTATUS 0x2C /* ISO15693 RESPONSE ERROR CODES */ -#define ISO15693_NOERROR 0x00 -#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported -#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error) -#define ISO15693_ERROR_CMD_OPTION 0x03 // Command option not supported -#define ISO15693_ERROR_GENERIC 0x0F // No additional Info about this error -#define ISO15693_ERROR_BLOCK_UNAVAILABLE 0x10 -#define ISO15693_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again -#define ISO15693_ERROR_BLOCK_LOCKED 0x12 // cannot be changed -#define ISO15693_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful -#define ISO15693_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful +#define ISO15693_NOERROR 0x00 +#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported +#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error) +#define ISO15693_ERROR_CMD_OPTION 0x03 // Command option not supported +#define ISO15693_ERROR_GENERIC 0x0F // No additional Info about this error +#define ISO15693_ERROR_BLOCK_UNAVAILABLE 0x10 +#define ISO15693_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again +#define ISO15693_ERROR_BLOCK_LOCKED 0x12 // cannot be changed +#define ISO15693_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful +#define ISO15693_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful typedef enum { NfcVAuthMethodManual, @@ -113,24 +113,31 @@ typedef struct { DigitalSequence* nfcv_signal; } NfcVEmuAir; - typedef struct { - uint8_t* frame; /* ISO15693-2 incoming raw data from air layer */ - uint8_t frame_length; /* ISO15693-2 length of incoming data */ + uint8_t* frame; /* ISO15693-2 incoming raw data from air layer */ + uint8_t frame_length; /* ISO15693-2 length of incoming data */ - uint8_t flags; /* ISO15693-3 flags of the header as specified */ - uint8_t command; /* ISO15693-3 command at offset 1 as specified */ - bool addressed; /* ISO15693-3 flags: addressed frame */ - bool advanced; /* ISO15693-3 command: advanced command */ - uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */ - uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */ + uint8_t flags; /* ISO15693-3 flags of the header as specified */ + uint8_t command; /* ISO15693-3 command at offset 1 as specified */ + bool addressed; /* ISO15693-3 flags: addressed frame */ + bool advanced; /* ISO15693-3 command: advanced command */ + uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */ + uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */ - uint8_t response_buffer[128]; /* pre-allocated response buffer */ - NfcVSendFlags response_flags; /* flags to use when sending response */ + uint8_t response_buffer[128]; /* pre-allocated response buffer */ + NfcVSendFlags response_flags; /* flags to use when sending response */ } NfcVEmuProtocolCtx; -typedef void (*NfcVEmuProtocolHandler) (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data, uint8_t* payload, uint32_t payload_length); -typedef bool (*NfcVEmuProtocolFilter) (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data); +typedef void (*NfcVEmuProtocolHandler)( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data, + uint8_t* payload, + uint32_t payload_length); +typedef bool (*NfcVEmuProtocolFilter)( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data); typedef struct { /* common ISO15693 fields */ @@ -161,7 +168,7 @@ typedef struct { int16_t blocks_read; } NfcVReader; -ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data); +ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data); ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data); ReturnCode nfcv_inventory(uint8_t* uid); bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* data); @@ -169,5 +176,14 @@ bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* d void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data); void nfcv_emu_deinit(NfcVData* nfcv_data); -bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms); -void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, uint8_t length, NfcVSendFlags flags); +bool nfcv_emu_loop( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + NfcVData* nfcv_data, + uint32_t timeout_ms); +void nfcv_emu_send( + FuriHalNfcTxRxContext* tx_rx, + NfcVData* nfcv, + uint8_t* data, + uint8_t length, + NfcVSendFlags flags); diff --git a/lib/nfc/protocols/slix.c b/lib/nfc/protocols/slix.c index 4315a1d57..3ef4a7c75 100644 --- a/lib/nfc/protocols/slix.c +++ b/lib/nfc/protocols/slix.c @@ -9,7 +9,7 @@ #define TAG "SLIX" -static uint32_t slix_read_be(uint8_t *data, uint32_t length) { +static uint32_t slix_read_be(uint8_t* data, uint32_t length) { uint32_t value = 0; for(uint32_t pos = 0; pos < length; pos++) { @@ -87,33 +87,32 @@ ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) { uint16_t received = 0; uint8_t rxBuf[32]; - uint8_t cmd_set_pass[] = { - password_id, - data->sub_data.slix.rand[1], - data->sub_data.slix.rand[0], - data->sub_data.slix.rand[1], - data->sub_data.slix.rand[0] - }; - uint8_t *password = NULL; + uint8_t cmd_set_pass[] = { + password_id, + data->sub_data.slix.rand[1], + data->sub_data.slix.rand[0], + data->sub_data.slix.rand[1], + data->sub_data.slix.rand[0]}; + uint8_t* password = NULL; switch(password_id) { - case SLIX_PASS_READ: - password = data->sub_data.slix.key_read; - break; - case SLIX_PASS_WRITE: - password = data->sub_data.slix.key_write; - break; - case SLIX_PASS_PRIVACY: - password = data->sub_data.slix.key_privacy; - break; - case SLIX_PASS_DESTROY: - password = data->sub_data.slix.key_destroy; - break; - case SLIX_PASS_EASAFI: - password = data->sub_data.slix.key_eas; - break; - default: - break; + case SLIX_PASS_READ: + password = data->sub_data.slix.key_read; + break; + case SLIX_PASS_WRITE: + password = data->sub_data.slix.key_write; + break; + case SLIX_PASS_PRIVACY: + password = data->sub_data.slix.key_privacy; + break; + case SLIX_PASS_DESTROY: + password = data->sub_data.slix.key_destroy; + break; + case SLIX_PASS_EASAFI: + password = data->sub_data.slix.key_eas; + break; + default: + break; } if(!password) { @@ -138,21 +137,26 @@ ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) { return ret; } - -bool slix_generic_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in, uint32_t password_supported) { +bool slix_generic_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in, + uint32_t password_supported) { furi_assert(tx_rx); furi_assert(nfc_data); furi_assert(nfcv_data_in); - + NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; NfcVEmuProtocolCtx* ctx = &nfcv_data->emu_protocol_ctx; NfcVSlixData* slix = &nfcv_data->sub_data.slix; - if(slix->privacy && - ctx->command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER && - ctx->command != ISO15693_CMD_NXP_SET_PASSWORD) { - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), - "command 0x%02X ignored, privacy mode", ctx->command); + if(slix->privacy && ctx->command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER && + ctx->command != ISO15693_CMD_NXP_SET_PASSWORD) { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "command 0x%02X ignored, privacy mode", + ctx->command); FURI_LOG_D(TAG, "%s", nfcv_data->last_command); return true; } @@ -160,115 +164,137 @@ bool slix_generic_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevDa bool handled = false; switch(ctx->command) { - case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: { - slix->rand[0] = furi_hal_random_get(); - slix->rand[1] = furi_hal_random_get(); + case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: { + slix->rand[0] = furi_hal_random_get(); + slix->rand[1] = furi_hal_random_get(); - ctx->response_buffer[0] = ISO15693_NOERROR; - ctx->response_buffer[1] = slix->rand[1]; - ctx->response_buffer[2] = slix->rand[0]; + ctx->response_buffer[0] = ISO15693_NOERROR; + ctx->response_buffer[1] = slix->rand[1]; + ctx->response_buffer[2] = slix->rand[0]; - nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 3, ctx->response_flags); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), - "GET_RANDOM_NUMBER -> 0x%02X%02X", slix->rand[0], slix->rand[1]); + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 3, ctx->response_flags); + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "GET_RANDOM_NUMBER -> 0x%02X%02X", + slix->rand[0], + slix->rand[1]); - handled = true; + handled = true; + break; + } + + case ISO15693_CMD_NXP_SET_PASSWORD: { + uint8_t password_id = ctx->frame[ctx->payload_offset]; + + if(!(password_id & password_supported)) { break; } - case ISO15693_CMD_NXP_SET_PASSWORD: { - uint8_t password_id = ctx->frame[ctx->payload_offset]; + uint8_t* password_xored = &ctx->frame[ctx->payload_offset + 1]; + uint8_t* rand = slix->rand; + uint8_t* password = NULL; + uint8_t password_rcv[4]; - if(!(password_id & password_supported)) { + switch(password_id) { + case SLIX_PASS_READ: + password = slix->key_read; + break; + case SLIX_PASS_WRITE: + password = slix->key_write; + break; + case SLIX_PASS_PRIVACY: + password = slix->key_privacy; + break; + case SLIX_PASS_DESTROY: + password = slix->key_destroy; + break; + case SLIX_PASS_EASAFI: + password = slix->key_eas; + break; + default: + break; + } + + for(int pos = 0; pos < 4; pos++) { + password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2]; + } + uint32_t pass_expect = slix_read_be(password, 4); + uint32_t pass_received = slix_read_be(password_rcv, 4); + + /* if the password is all-zeroes, just accept any password*/ + if(!pass_expect || pass_expect == pass_received) { + switch(password_id) { + case SLIX_PASS_READ: + break; + case SLIX_PASS_WRITE: + break; + case SLIX_PASS_PRIVACY: + slix->privacy = false; + break; + case SLIX_PASS_DESTROY: + FURI_LOG_D(TAG, "Pooof! Got destroyed"); + break; + case SLIX_PASS_EASAFI: + break; + default: break; } - - uint8_t *password_xored = &ctx->frame[ctx->payload_offset + 1]; - uint8_t *rand = slix->rand; - uint8_t *password = NULL; - uint8_t password_rcv[4]; - - switch(password_id) { - case SLIX_PASS_READ: - password = slix->key_read; - break; - case SLIX_PASS_WRITE: - password = slix->key_write; - break; - case SLIX_PASS_PRIVACY: - password = slix->key_privacy; - break; - case SLIX_PASS_DESTROY: - password = slix->key_destroy; - break; - case SLIX_PASS_EASAFI: - password = slix->key_eas; - break; - default: - break; - } - - for(int pos = 0; pos < 4; pos++) { - password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2]; - } - uint32_t pass_expect = slix_read_be(password, 4); - uint32_t pass_received = slix_read_be(password_rcv, 4); - - /* if the password is all-zeroes, just accept any password*/ - if(!pass_expect || pass_expect == pass_received) { - switch(password_id) { - case SLIX_PASS_READ: - break; - case SLIX_PASS_WRITE: - break; - case SLIX_PASS_PRIVACY: - slix->privacy = false; - break; - case SLIX_PASS_DESTROY: - FURI_LOG_D(TAG, "Pooof! Got destroyed"); - break; - case SLIX_PASS_EASAFI: - break; - default: - break; - } - ctx->response_buffer[0] = ISO15693_NOERROR; - nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), - "SET_PASSWORD #%02X 0x%08lX OK", password_id, pass_received); - } else { - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), - "SET_PASSWORD #%02X 0x%08lX/%08lX FAIL", password_id, pass_received, pass_expect); - } - handled = true; - break; - } - - case ISO15693_CMD_NXP_ENABLE_PRIVACY: { ctx->response_buffer[0] = ISO15693_NOERROR; - nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), - "ISO15693_CMD_NXP_ENABLE_PRIVACY"); - - slix->privacy = true; - handled = true; - break; + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "SET_PASSWORD #%02X 0x%08lX OK", + password_id, + pass_received); + } else { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "SET_PASSWORD #%02X 0x%08lX/%08lX FAIL", + password_id, + pass_received, + pass_expect); } + handled = true; + break; + } + + case ISO15693_CMD_NXP_ENABLE_PRIVACY: { + ctx->response_buffer[0] = ISO15693_NOERROR; + + nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags); + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "ISO15693_CMD_NXP_ENABLE_PRIVACY"); + + slix->privacy = true; + handled = true; + break; + } } return handled; } -bool slix_l_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { +bool slix_l_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { furi_assert(tx_rx); furi_assert(nfc_data); furi_assert(nfcv_data_in); bool handled = false; - + /* many SLIX share some of the functions, place that in a generic handler */ - if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) { + if(slix_generic_protocol_filter( + tx_rx, + nfc_data, + nfcv_data_in, + SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) { return true; } @@ -276,21 +302,26 @@ bool slix_l_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nf } void slix_l_prepare(NfcVData* nfcv_data) { - FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); - FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); nfcv_data->emu_protocol_filter = &slix_l_protocol_filter; } -bool slix_s_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { +bool slix_s_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { furi_assert(tx_rx); furi_assert(nfc_data); furi_assert(nfcv_data_in); bool handled = false; - + /* many SLIX share some of the functions, place that in a generic handler */ if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { return true; @@ -300,21 +331,26 @@ bool slix_s_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nf } void slix_s_prepare(NfcVData* nfcv_data) { - FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); - FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); nfcv_data->emu_protocol_filter = &slix_s_protocol_filter; } -bool slix_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { +bool slix_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { furi_assert(tx_rx); furi_assert(nfc_data); furi_assert(nfcv_data_in); bool handled = false; - + /* many SLIX share some of the functions, place that in a generic handler */ if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_EASAFI)) { return true; @@ -324,21 +360,26 @@ bool slix_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_ } void slix_prepare(NfcVData* nfcv_data) { - FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); - FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); nfcv_data->emu_protocol_filter = &slix_protocol_filter; } -bool slix2_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { +bool slix2_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { furi_assert(tx_rx); furi_assert(nfc_data); furi_assert(nfcv_data_in); bool handled = false; - + /* many SLIX share some of the functions, place that in a generic handler */ if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { return true; @@ -348,8 +389,10 @@ bool slix2_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc } void slix2_prepare(NfcVData* nfcv_data) { - FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); - FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); diff --git a/lib/nfc/protocols/slix.h b/lib/nfc/protocols/slix.h index 72c042ee1..719fe6f43 100644 --- a/lib/nfc/protocols/slix.h +++ b/lib/nfc/protocols/slix.h @@ -5,31 +5,32 @@ #include "nfc_util.h" #include -#define ISO15693_MANUFACTURER_NXP 0x04 +#define ISO15693_MANUFACTURER_NXP 0x04 /* ISO15693-3 CUSTOM NXP COMMANDS */ -#define ISO15693_CMD_NXP_SET_EAS 0xA2 -#define ISO15693_CMD_NXP_RESET_EAS 0xA3 -#define ISO15693_CMD_NXP_LOCK_EAS 0xA4 -#define ISO15693_CMD_NXP_EAS_ALARM 0xA5 +#define ISO15693_CMD_NXP_SET_EAS 0xA2 +#define ISO15693_CMD_NXP_RESET_EAS 0xA3 +#define ISO15693_CMD_NXP_LOCK_EAS 0xA4 +#define ISO15693_CMD_NXP_EAS_ALARM 0xA5 #define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6 -#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7 -#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0 +#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7 +#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0 #define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1 -#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2 -#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3 -#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4 -#define ISO15693_CMD_NXP_DESTROY 0xB9 -#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA +#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2 +#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3 +#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4 +#define ISO15693_CMD_NXP_DESTROY 0xB9 +#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA /* available passwords */ -#define SLIX_PASS_READ 0x01 -#define SLIX_PASS_WRITE 0x02 +#define SLIX_PASS_READ 0x01 +#define SLIX_PASS_WRITE 0x02 #define SLIX_PASS_PRIVACY 0x04 #define SLIX_PASS_DESTROY 0x08 -#define SLIX_PASS_EASAFI 0x10 +#define SLIX_PASS_EASAFI 0x10 -#define SLIX_PASS_ALL (SLIX_PASS_READ|SLIX_PASS_WRITE|SLIX_PASS_PRIVACY|SLIX_PASS_DESTROY|SLIX_PASS_EASAFI) +#define SLIX_PASS_ALL \ + (SLIX_PASS_READ | SLIX_PASS_WRITE | SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI) bool slix_check_card_type(FuriHalNfcDevData* nfc_data); bool slix2_check_card_type(FuriHalNfcDevData* nfc_data);