nfc: add debug PCAP output, refactor Mifare DESFire following #1095 (#1294)

* nfc: refactor nfc_worker_read_mifare_desfire to use furi_hal_nfc_tx_rx
  Renames furi_hal_nfc_exchange_full to furi_hal_nfc_tx_rx_full, and
  rewrites it to use furi_hal_nfc_tx_rx.  This eliminates the final
  remaining use of furi_hal_nfc_exchange, so remove that.
* nfc: write debug.pcap when debug mode enabled
  Limited to NFC protocols that use furi_hal_nfc_tx_rx to communicate.
* switch to Doxygen style comment

Co-authored-by: Kevin Wallace <git+flipperzero@kevin.wallace.seattle.wa.us>
Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Kevin Wallace 2022-06-09 01:35:34 -07:00 committed by GitHub
parent d5df4027d7
commit 9c9f66a30f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 224 additions and 161 deletions

View File

@ -0,0 +1,99 @@
#include "nfc_debug_pcap.h"
#include <furi_hal_rtc.h>
#define TAG "NfcDebugPcap"
#define PCAP_MAGIC 0xa1b2c3d4
#define PCAP_MAJOR 2
#define PCAP_MINOR 4
#define DLT_ISO_14443 264
#define DATA_PICC_TO_PCD 0xFF
#define DATA_PCD_TO_PICC 0xFE
#define DATA_PICC_TO_PCD_CRC_DROPPED 0xFB
#define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA
File* nfc_debug_pcap_open(Storage* storage) {
File* file = storage_file_alloc(storage);
if(!storage_file_open(file, "/ext/nfc/debug.pcap", FSAM_WRITE, FSOM_OPEN_APPEND)) {
storage_file_free(file);
return NULL;
}
if(!storage_file_tell(file)) {
struct {
uint32_t magic;
uint16_t major, minor;
uint32_t reserved[2];
uint32_t snaplen;
uint32_t link_type;
} __attribute__((__packed__)) pcap_hdr = {
.magic = PCAP_MAGIC,
.major = PCAP_MAJOR,
.minor = PCAP_MINOR,
.snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE,
.link_type = DLT_ISO_14443,
};
if(storage_file_write(file, &pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) {
FURI_LOG_E(TAG, "Failed to write pcap header");
}
}
return file;
}
void nfc_debug_pcap_write(Storage* storage, uint8_t event, uint8_t* data, uint16_t len) {
File* file = nfc_debug_pcap_open(storage);
if(!file) return;
FuriHalRtcDateTime datetime;
furi_hal_rtc_get_datetime(&datetime);
struct {
// https://wiki.wireshark.org/Development/LibpcapFileFormat#record-packet-header
uint32_t ts_sec;
uint32_t ts_usec;
uint32_t incl_len;
uint32_t orig_len;
// https://www.kaiser.cx/posts/pcap-iso14443/#_packet_data
uint8_t version;
uint8_t event;
uint16_t len;
} __attribute__((__packed__)) pkt_hdr = {
.ts_sec = furi_hal_rtc_datetime_to_timestamp(&datetime),
.ts_usec = 0,
.incl_len = len + 4,
.orig_len = len + 4,
.version = 0,
.event = event,
.len = len << 8 | len >> 8,
};
if(storage_file_write(file, &pkt_hdr, sizeof(pkt_hdr)) != sizeof(pkt_hdr)) {
FURI_LOG_E(TAG, "Failed to write pcap packet header");
} else if(storage_file_write(file, data, len) != len) {
FURI_LOG_E(TAG, "Failed to write pcap packet data");
}
storage_file_free(file);
}
void nfc_debug_pcap_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
uint8_t event = crc_dropped ? DATA_PCD_TO_PICC_CRC_DROPPED : DATA_PCD_TO_PICC;
nfc_debug_pcap_write(context, event, data, bits / 8);
}
void nfc_debug_pcap_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
uint8_t event = crc_dropped ? DATA_PICC_TO_PCD_CRC_DROPPED : DATA_PICC_TO_PCD;
nfc_debug_pcap_write(context, event, data, bits / 8);
}
void nfc_debug_pcap_prepare_tx_rx(FuriHalNfcTxRxContext* tx_rx, Storage* storage, bool is_picc) {
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
if(is_picc) {
tx_rx->sniff_tx = nfc_debug_pcap_write_rx;
tx_rx->sniff_rx = nfc_debug_pcap_write_tx;
} else {
tx_rx->sniff_tx = nfc_debug_pcap_write_tx;
tx_rx->sniff_rx = nfc_debug_pcap_write_rx;
}
tx_rx->sniff_context = storage;
}
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <furi_hal_nfc.h>
#include <storage/storage.h>
/** Prepare tx/rx context for debug pcap logging, if enabled.
*
* @param tx_rx TX/RX context to log
* @param storage Storage to log to
* @param is_picc if true, record Flipper as PICC, else PCD.
*/
void nfc_debug_pcap_prepare_tx_rx(FuriHalNfcTxRxContext* tx_rx, Storage* storage, bool is_picc);

View File

@ -10,6 +10,7 @@
#include <lib/nfc_protocols/nfca.h> #include <lib/nfc_protocols/nfca.h>
#include "helpers/nfc_mf_classic_dict.h" #include "helpers/nfc_mf_classic_dict.h"
#include "helpers/nfc_debug_pcap.h"
#define TAG "NfcWorker" #define TAG "NfcWorker"
@ -153,6 +154,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) {
void nfc_worker_emulate(NfcWorker* nfc_worker) { void nfc_worker_emulate(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {}; FuriHalNfcTxRxContext tx_rx = {};
nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true);
FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data; FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data; NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
@ -175,6 +177,7 @@ void nfc_worker_emulate(NfcWorker* nfc_worker) {
void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {}; FuriHalNfcTxRxContext tx_rx = {};
nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false);
EmvApplication emv_app = {}; EmvApplication emv_app = {};
NfcDeviceData* result = nfc_worker->dev_data; NfcDeviceData* result = nfc_worker->dev_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
@ -206,6 +209,7 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
void nfc_worker_read_emv(NfcWorker* nfc_worker) { void nfc_worker_read_emv(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {}; FuriHalNfcTxRxContext tx_rx = {};
nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false);
EmvApplication emv_app = {}; EmvApplication emv_app = {};
NfcDeviceData* result = nfc_worker->dev_data; NfcDeviceData* result = nfc_worker->dev_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
@ -254,6 +258,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {}; FuriHalNfcTxRxContext tx_rx = {};
nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true);
FuriHalNfcDevData params = { FuriHalNfcDevData params = {
.uid = {0xCF, 0x72, 0xd4, 0x40}, .uid = {0xCF, 0x72, 0xd4, 0x40},
.uid_len = 4, .uid_len = 4,
@ -278,6 +283,7 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) { void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {}; FuriHalNfcTxRxContext tx_rx = {};
nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false);
MfUltralightReader reader = {}; MfUltralightReader reader = {};
MfUltralightData data = {}; MfUltralightData data = {};
NfcDeviceData* result = nfc_worker->dev_data; NfcDeviceData* result = nfc_worker->dev_data;
@ -342,6 +348,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
furi_assert(nfc_worker->callback); furi_assert(nfc_worker->callback);
FuriHalNfcTxRxContext tx_rx_ctx = {}; FuriHalNfcTxRxContext tx_rx_ctx = {};
nfc_debug_pcap_prepare_tx_rx(&tx_rx_ctx, nfc_worker->storage, false);
MfClassicAuthContext auth_ctx = {}; MfClassicAuthContext auth_ctx = {};
MfClassicReader reader = {}; MfClassicReader reader = {};
uint64_t curr_key = 0; uint64_t curr_key = 0;
@ -483,7 +490,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
} }
void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) { void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx; FuriHalNfcTxRxContext tx_rx = {};
nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true);
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
MfClassicEmulator emulator = { MfClassicEmulator emulator = {
.cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4),
@ -511,11 +519,8 @@ void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) {
} }
void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
ReturnCode err; FuriHalNfcTxRxContext tx_rx = {};
uint8_t tx_buff[64] = {}; nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false);
uint16_t tx_len = 0;
uint8_t rx_buff[512] = {};
uint16_t rx_len;
NfcDeviceData* result = nfc_worker->dev_data; NfcDeviceData* result = nfc_worker->dev_data;
nfc_device_data_clear(result); nfc_device_data_clear(result);
MifareDesfireData* data = &result->mf_df_data; MifareDesfireData* data = &result->mf_df_data;
@ -540,37 +545,36 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
result->protocol = NfcDeviceProtocolMifareDesfire; result->protocol = NfcDeviceProtocolMifareDesfire;
// Get DESFire version // Get DESFire version
tx_len = mf_df_prepare_get_version(tx_buff); tx_rx.tx_bits = 8 * mf_df_prepare_get_version(tx_rx.tx_data);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting version");
FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err);
continue; continue;
} }
if(!mf_df_parse_get_version_response(rx_buff, rx_len, &data->version)) { if(!mf_df_parse_get_version_response(tx_rx.rx_data, tx_rx.rx_bits / 8, &data->version)) {
FURI_LOG_W(TAG, "Bad DESFire GET_VERSION response"); FURI_LOG_W(TAG, "Bad DESFire GET_VERSION response");
continue; continue;
} }
tx_len = mf_df_prepare_get_free_memory(tx_buff); tx_rx.tx_bits = 8 * mf_df_prepare_get_free_memory(tx_rx.tx_data);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(furi_hal_nfc_tx_rx_full(&tx_rx)) {
if(err == ERR_NONE) {
data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); data->free_memory = malloc(sizeof(MifareDesfireFreeMemory));
memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory)); memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory));
if(!mf_df_parse_get_free_memory_response(rx_buff, rx_len, data->free_memory)) { if(!mf_df_parse_get_free_memory_response(
tx_rx.rx_data, tx_rx.rx_bits / 8, data->free_memory)) {
FURI_LOG_D(TAG, "Bad DESFire GET_FREE_MEMORY response (normal for pre-EV1 cards)"); FURI_LOG_D(TAG, "Bad DESFire GET_FREE_MEMORY response (normal for pre-EV1 cards)");
free(data->free_memory); free(data->free_memory);
data->free_memory = NULL; data->free_memory = NULL;
} }
} }
tx_len = mf_df_prepare_get_key_settings(tx_buff); tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
if(err != ERR_NONE) { FURI_LOG_D(TAG, "Bad exchange getting key settings");
FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err);
} else { } else {
data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings));
memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings));
if(!mf_df_parse_get_key_settings_response(rx_buff, rx_len, data->master_key_settings)) { if(!mf_df_parse_get_key_settings_response(
tx_rx.rx_data, tx_rx.rx_bits / 8, data->master_key_settings)) {
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response");
free(data->master_key_settings); free(data->master_key_settings);
data->master_key_settings = NULL; data->master_key_settings = NULL;
@ -580,17 +584,16 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
MifareDesfireKeyVersion** key_version_head = MifareDesfireKeyVersion** key_version_head =
&data->master_key_settings->key_version_head; &data->master_key_settings->key_version_head;
for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) {
tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id);
err = if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); FURI_LOG_W(TAG, "Bad exchange getting key version");
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
continue; continue;
} }
MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion));
memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); memset(key_version, 0, sizeof(MifareDesfireKeyVersion));
key_version->id = key_id; key_version->id = key_id;
if(!mf_df_parse_get_key_version_response(rx_buff, rx_len, key_version)) { if(!mf_df_parse_get_key_version_response(
tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) {
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response");
free(key_version); free(key_version);
continue; continue;
@ -600,31 +603,31 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
} }
} }
tx_len = mf_df_prepare_get_application_ids(tx_buff); tx_rx.tx_bits = 8 * mf_df_prepare_get_application_ids(tx_rx.tx_data);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting application IDs");
FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err);
} else { } else {
if(!mf_df_parse_get_application_ids_response(rx_buff, rx_len, &data->app_head)) { if(!mf_df_parse_get_application_ids_response(
tx_rx.rx_data, tx_rx.rx_bits / 8, &data->app_head)) {
FURI_LOG_W(TAG, "Bad DESFire GET_APPLICATION_IDS response"); FURI_LOG_W(TAG, "Bad DESFire GET_APPLICATION_IDS response");
} }
} }
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
tx_len = mf_df_prepare_select_application(tx_buff, app->id); tx_rx.tx_bits = 8 * mf_df_prepare_select_application(tx_rx.tx_data, app->id);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(!furi_hal_nfc_tx_rx_full(&tx_rx) ||
if(!mf_df_parse_select_application_response(rx_buff, rx_len)) { !mf_df_parse_select_application_response(tx_rx.rx_data, tx_rx.rx_bits / 8)) {
FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err); FURI_LOG_W(TAG, "Bad exchange selecting application");
continue; continue;
} }
tx_len = mf_df_prepare_get_key_settings(tx_buff); tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting key settings");
FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err);
} else { } else {
app->key_settings = malloc(sizeof(MifareDesfireKeySettings)); app->key_settings = malloc(sizeof(MifareDesfireKeySettings));
memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings)); memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings));
if(!mf_df_parse_get_key_settings_response(rx_buff, rx_len, app->key_settings)) { if(!mf_df_parse_get_key_settings_response(
tx_rx.rx_data, tx_rx.rx_bits / 8, app->key_settings)) {
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response");
free(app->key_settings); free(app->key_settings);
app->key_settings = NULL; app->key_settings = NULL;
@ -633,17 +636,16 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head; MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head;
for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) { for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) {
tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id);
err = furi_hal_nfc_exchange_full( if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); FURI_LOG_W(TAG, "Bad exchange getting key version");
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
continue; continue;
} }
MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion));
memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); memset(key_version, 0, sizeof(MifareDesfireKeyVersion));
key_version->id = key_id; key_version->id = key_id;
if(!mf_df_parse_get_key_version_response(rx_buff, rx_len, key_version)) { if(!mf_df_parse_get_key_version_response(
tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) {
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response");
free(key_version); free(key_version);
continue; continue;
@ -653,48 +655,45 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
} }
} }
tx_len = mf_df_prepare_get_file_ids(tx_buff); tx_rx.tx_bits = 8 * mf_df_prepare_get_file_ids(tx_rx.tx_data);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting file IDs");
FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err);
} else { } else {
if(!mf_df_parse_get_file_ids_response(rx_buff, rx_len, &app->file_head)) { if(!mf_df_parse_get_file_ids_response(
tx_rx.rx_data, tx_rx.rx_bits / 8, &app->file_head)) {
FURI_LOG_W(TAG, "Bad DESFire GET_FILE_IDS response"); FURI_LOG_W(TAG, "Bad DESFire GET_FILE_IDS response");
} }
} }
for(MifareDesfireFile* file = app->file_head; file; file = file->next) { for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id); tx_rx.tx_bits = 8 * mf_df_prepare_get_file_settings(tx_rx.tx_data, file->id);
err = if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); FURI_LOG_W(TAG, "Bad exchange getting file settings");
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err);
continue; continue;
} }
if(!mf_df_parse_get_file_settings_response(rx_buff, rx_len, file)) { if(!mf_df_parse_get_file_settings_response(
tx_rx.rx_data, tx_rx.rx_bits / 8, file)) {
FURI_LOG_W(TAG, "Bad DESFire GET_FILE_SETTINGS response"); FURI_LOG_W(TAG, "Bad DESFire GET_FILE_SETTINGS response");
continue; continue;
} }
switch(file->type) { switch(file->type) {
case MifareDesfireFileTypeStandard: case MifareDesfireFileTypeStandard:
case MifareDesfireFileTypeBackup: case MifareDesfireFileTypeBackup:
tx_len = mf_df_prepare_read_data(tx_buff, file->id, 0, 0); tx_rx.tx_bits = 8 * mf_df_prepare_read_data(tx_rx.tx_data, file->id, 0, 0);
break; break;
case MifareDesfireFileTypeValue: case MifareDesfireFileTypeValue:
tx_len = mf_df_prepare_get_value(tx_buff, file->id); tx_rx.tx_bits = 8 * mf_df_prepare_get_value(tx_rx.tx_data, file->id);
break; break;
case MifareDesfireFileTypeLinearRecord: case MifareDesfireFileTypeLinearRecord:
case MifareDesfireFileTypeCyclicRecord: case MifareDesfireFileTypeCyclicRecord:
tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0); tx_rx.tx_bits = 8 * mf_df_prepare_read_records(tx_rx.tx_data, file->id, 0, 0);
break; break;
} }
err = if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); FURI_LOG_W(TAG, "Bad exchange reading file %d", file->id);
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err);
continue; continue;
} }
if(!mf_df_parse_read_data_response(rx_buff, rx_len, file)) { if(!mf_df_parse_read_data_response(tx_rx.rx_data, tx_rx.rx_bits / 8, file)) {
FURI_LOG_W(TAG, "Bad response reading file %d", file->id); FURI_LOG_W(TAG, "Bad response reading file %d", file->id);
continue; continue;
} }

View File

@ -366,44 +366,6 @@ bool furi_hal_nfc_emulate_nfca(
return true; return true;
} }
ReturnCode furi_hal_nfc_data_exchange(
uint8_t* tx_buff,
uint16_t tx_len,
uint8_t** rx_buff,
uint16_t** rx_len,
bool deactivate) {
furi_assert(rx_buff);
furi_assert(rx_len);
ReturnCode ret;
rfalNfcState state = RFAL_NFC_STATE_ACTIVATED;
ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT);
if(ret != ERR_NONE) {
return ret;
}
uint32_t start = DWT->CYCCNT;
while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) {
rfalNfcWorker();
state = rfalNfcGetState();
ret = rfalNfcDataExchangeGetStatus();
if(ret == ERR_BUSY) {
if(DWT->CYCCNT - start > 1000 * clocks_in_ms) {
ret = ERR_TIMEOUT;
break;
}
continue;
} else {
start = DWT->CYCCNT;
}
taskYIELD();
}
if(deactivate) {
rfalNfcDeactivate(false);
rfalLowPowerModeStart();
}
return ret;
}
static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
furi_assert(tx_rx->nfca_signal); furi_assert(tx_rx->nfca_signal);
@ -576,6 +538,12 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
FURI_LOG_E(TAG, "Failed to start data exchange"); FURI_LOG_E(TAG, "Failed to start data exchange");
return false; return false;
} }
if(tx_rx->sniff_tx) {
bool crc_dropped = !(flags & RFAL_TXRX_FLAGS_CRC_TX_MANUAL);
tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, crc_dropped, tx_rx->sniff_context);
}
uint32_t start = DWT->CYCCNT; uint32_t start = DWT->CYCCNT;
while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) {
rfalNfcWorker(); rfalNfcWorker();
@ -602,42 +570,42 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
tx_rx->rx_bits = *temp_rx_bits; tx_rx->rx_bits = *temp_rx_bits;
} }
if(tx_rx->sniff_rx) {
bool crc_dropped = !(flags & RFAL_TXRX_FLAGS_CRC_RX_KEEP);
tx_rx->sniff_rx(tx_rx->rx_data, tx_rx->rx_bits, crc_dropped, tx_rx->sniff_context);
}
return true; return true;
} }
ReturnCode furi_hal_nfc_exchange_full( bool furi_hal_nfc_tx_rx_full(FuriHalNfcTxRxContext* tx_rx) {
uint8_t* tx_buff,
uint16_t tx_len,
uint8_t* rx_buff,
uint16_t rx_cap,
uint16_t* rx_len) {
ReturnCode err;
uint8_t* part_buff;
uint16_t* part_len_bits;
uint16_t part_len_bytes; uint16_t part_len_bytes;
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len_bits, false); if(!furi_hal_nfc_tx_rx(tx_rx, 1000)) {
part_len_bytes = *part_len_bits / 8; return false;
if(part_len_bytes > rx_cap) {
return ERR_OVERRUN;
} }
memcpy(rx_buff, part_buff, part_len_bytes); while(tx_rx->rx_bits && tx_rx->rx_data[0] == 0xAF) {
*rx_len = part_len_bytes; FuriHalNfcTxRxContext tmp = *tx_rx;
while(err == ERR_NONE && rx_buff[0] == 0xAF) { tmp.tx_data[0] = 0xAF;
err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len_bits, false); tmp.tx_bits = 8;
part_len_bytes = *part_len_bits / 8; if(!furi_hal_nfc_tx_rx(&tmp, 1000)) {
if(part_len_bytes > rx_cap - *rx_len) { return false;
return ERR_OVERRUN; }
part_len_bytes = tmp.rx_bits / 8;
if(part_len_bytes > FURI_HAL_NFC_DATA_BUFF_SIZE - tx_rx->rx_bits / 8) {
FURI_LOG_W(TAG, "Overrun rx buf");
return false;
} }
if(part_len_bytes == 0) { if(part_len_bytes == 0) {
return ERR_PROTO; FURI_LOG_W(TAG, "Empty 0xAF response");
return false;
} }
memcpy(rx_buff + *rx_len, part_buff + 1, part_len_bytes - 1); memcpy(tx_rx->rx_data + tx_rx->rx_bits / 8, tmp.rx_data + 1, part_len_bytes - 1);
*rx_buff = *part_buff; tx_rx->rx_data[0] = tmp.rx_data[0];
*rx_len += part_len_bytes - 1; tx_rx->rx_bits += 8 * (part_len_bytes - 1);
} }
return err; return true;
} }
void furi_hal_nfc_sleep() { void furi_hal_nfc_sleep() {

41
firmware/targets/furi_hal_include/furi_hal_nfc.h Executable file → Normal file
View File

@ -17,7 +17,7 @@ extern "C" {
#endif #endif
#define FURI_HAL_NFC_UID_MAX_LEN 10 #define FURI_HAL_NFC_UID_MAX_LEN 10
#define FURI_HAL_NFC_DATA_BUFF_SIZE (256) #define FURI_HAL_NFC_DATA_BUFF_SIZE (512)
#define FURI_HAL_NFC_PARITY_BUFF_SIZE (FURI_HAL_NFC_DATA_BUFF_SIZE / 8) #define FURI_HAL_NFC_PARITY_BUFF_SIZE (FURI_HAL_NFC_DATA_BUFF_SIZE / 8)
#define FURI_HAL_NFC_TXRX_DEFAULT \ #define FURI_HAL_NFC_TXRX_DEFAULT \
@ -80,6 +80,9 @@ typedef struct {
uint8_t sak; uint8_t sak;
} FuriHalNfcDevData; } FuriHalNfcDevData;
typedef void (
*FuriHalNfcTxRxSniffCallback)(uint8_t* data, uint16_t bits, bool crc_dropped, void* context);
typedef struct { typedef struct {
uint8_t tx_data[FURI_HAL_NFC_DATA_BUFF_SIZE]; uint8_t tx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
uint8_t tx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE]; uint8_t tx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
@ -89,6 +92,10 @@ typedef struct {
uint16_t rx_bits; uint16_t rx_bits;
FuriHalNfcTxRxType tx_rx_type; FuriHalNfcTxRxType tx_rx_type;
NfcaSignal* nfca_signal; NfcaSignal* nfca_signal;
FuriHalNfcTxRxSniffCallback sniff_tx;
FuriHalNfcTxRxSniffCallback sniff_rx;
void* sniff_context;
} FuriHalNfcTxRxContext; } FuriHalNfcTxRxContext;
/** Init nfc /** Init nfc
@ -165,23 +172,6 @@ bool furi_hal_nfc_emulate_nfca(
void* context, void* context,
uint32_t timeout); uint32_t timeout);
/** NFC data exchange
*
* @param tx_buff transmit buffer
* @param tx_len transmit buffer length
* @param rx_buff receive buffer
* @param rx_len receive buffer length
* @param deactivate deactivate flag
*
* @return ST ReturnCode
*/
ReturnCode furi_hal_nfc_data_exchange(
uint8_t* tx_buff,
uint16_t tx_len,
uint8_t** rx_buff,
uint16_t** rx_len,
bool deactivate);
/** NFC data exchange /** NFC data exchange
* *
* @param tx_rx_ctx FuriHalNfcTxRxContext instance * @param tx_rx_ctx FuriHalNfcTxRxContext instance
@ -192,20 +182,11 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms);
/** NFC data full exhange /** NFC data full exhange
* *
* @param tx_buff transmit buffer * @param tx_rx_ctx FuriHalNfcTxRxContext instance
* @param tx_len transmit buffer length
* @param rx_buff receive buffer
* @param rx_cap receive buffer capacity
* @param rx_len receive buffer length
* *
* @return ST ReturnCode * @return true on success
*/ */
ReturnCode furi_hal_nfc_exchange_full( bool furi_hal_nfc_tx_rx_full(FuriHalNfcTxRxContext* tx_rx);
uint8_t* tx_buff,
uint16_t tx_len,
uint8_t* rx_buff,
uint16_t rx_cap,
uint16_t* rx_len);
/** NFC deactivate and start sleep /** NFC deactivate and start sleep
*/ */

View File

@ -397,7 +397,8 @@ bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) {
bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) { bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) {
furi_assert(tx_rx); furi_assert(tx_rx);
bool emulation_complete = false; bool emulation_complete = false;
memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext)); tx_rx->tx_bits = 0;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
do { do {
FURI_LOG_D(TAG, "Read select PPSE command"); FURI_LOG_D(TAG, "Read select PPSE command");

View File

@ -270,7 +270,9 @@ static bool mf_classic_auth(
MfClassicKey key_type, MfClassicKey key_type,
Crypto1* crypto) { Crypto1* crypto) {
bool auth_success = false; bool auth_success = false;
memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext)); memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data));
memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity));
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
do { do {
if(key_type == MfClassicKeyA) { if(key_type == MfClassicKeyA) {
@ -372,7 +374,8 @@ bool mf_classic_read_block(
bool read_block_success = false; bool read_block_success = false;
uint8_t plain_cmd[4] = {MF_CLASSIC_READ_SECT_CMD, block_num, 0x00, 0x00}; uint8_t plain_cmd[4] = {MF_CLASSIC_READ_SECT_CMD, block_num, 0x00, 0x00};
nfca_append_crc16(plain_cmd, 2); nfca_append_crc16(plain_cmd, 2);
memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext)); memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data));
memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity));
for(uint8_t i = 0; i < 4; i++) { for(uint8_t i = 0; i < 4; i++) {
tx_rx->tx_data[i] = crypto1_byte(crypto, 0x00, 0) ^ plain_cmd[i]; tx_rx->tx_data[i] = crypto1_byte(crypto, 0x00, 0) ^ plain_cmd[i];