[FL-2369] NFC refactoring ()

* nfc: clean up scenes
* nfc worker: remove field on from worker
* nfc worker: move full data exchange to furi hal
* nfc_device: check UID length
* nfc protocol: introduce mifare common API
* nfc: move common data to furi hal nfc
* nfc: rename emv_decoder -> emv
* nfc: move emv data structure to emv lib
* nfc: remove deactivate after detection
* nfc: rework furi hal nfc detect
* nfc: clean up CLI commands and type
* nfc: remove unused includes and function
* nfc: add TxRxType enum
* nfc: read mifare ultralight refactoring
* nfc: refactore mifare ultralight start
* rfal: fix custom data exchange
* nfc: refactor read bank card
* nfc: refactor read emv application
* nfc: refactor emv test emulation
* nfc: refactor uid emulation
* nfc: add limit to uid emulation logger
* fix source formatting
* furi_hal_nfc: fix data exchange full
* nfc: fix mifare ultralight type load

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
gornekich 2022-04-19 18:23:58 +03:00 committed by GitHub
parent e55d1572da
commit 956788c09b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 1349 additions and 1601 deletions

View File

@ -3,19 +3,19 @@
bool nfc_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
return scene_manager_handle_custom_event(nfc->scene_manager, event);
}
bool nfc_back_event_callback(void* context) {
furi_assert(context);
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
return scene_manager_handle_back_event(nfc->scene_manager);
}
void nfc_tick_event_callback(void* context) {
furi_assert(context);
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
scene_manager_handle_tick_event(nfc->scene_manager);
}

View File

@ -16,40 +16,35 @@ static void nfc_cli_print_usage() {
}
}
void nfc_cli_detect(Cli* cli, string_t args) {
static void nfc_cli_detect(Cli* cli, string_t args) {
// Check if nfc worker is not busy
if(furi_hal_nfc_is_busy()) {
printf("Nfc is busy\r\n");
return;
}
rfalNfcDevice* dev_list;
uint8_t dev_cnt = 0;
FuriHalNfcDevData dev_data = {};
bool cmd_exit = false;
furi_hal_nfc_exit_sleep();
printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n");
while(!cmd_exit) {
cmd_exit |= cli_cmd_interrupt_received(cli);
cmd_exit |= furi_hal_nfc_detect(&dev_list, &dev_cnt, 400, true);
if(dev_cnt > 0) {
printf("Found %d devices\r\n", dev_cnt);
for(uint8_t i = 0; i < dev_cnt; i++) {
printf("%d found: %s ", i + 1, nfc_get_rfal_type(dev_list[i].type));
if(dev_list[i].type == RFAL_NFC_LISTEN_TYPE_NFCA) {
printf("type: %s, ", nfc_get_nfca_type(dev_list[i].dev.nfca.type));
}
printf("UID length: %d, UID:", dev_list[i].nfcidLen);
for(uint8_t j = 0; j < dev_list[i].nfcidLen; j++) {
printf("%02X", dev_list[i].nfcid[j]);
}
printf("\r\n");
if(furi_hal_nfc_detect(&dev_data, 400)) {
printf("found: %s ", nfc_get_dev_type(dev_data.type));
printf("UID length: %d, UID:", dev_data.uid_len);
for(size_t i = 0; i < dev_data.uid_len; i++) {
printf("%02X", dev_data.uid[i]);
}
printf("\r\n");
break;
}
furi_hal_nfc_sleep();
osDelay(50);
}
furi_hal_nfc_deactivate();
furi_hal_nfc_sleep();
}
void nfc_cli_emulate(Cli* cli, string_t args) {
static void nfc_cli_emulate(Cli* cli, string_t args) {
// Check if nfc worker is not busy
if(furi_hal_nfc_is_busy()) {
printf("Nfc is busy\r\n");
@ -60,26 +55,25 @@ void nfc_cli_emulate(Cli* cli, string_t args) {
printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n");
printf("Press Ctrl+C to abort\r\n");
NfcDeviceCommonData params = {
FuriHalNfcDevData params = {
.uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34},
.uid_len = 7,
.atqa = {0x44, 0x00},
.sak = 0x00,
.device = NfcDeviceNfca,
.protocol = NfcDeviceProtocolMifareUl,
.type = FuriHalNfcTypeA,
};
while(!cli_cmd_interrupt_received(cli)) {
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) {
printf("Reader detected\r\n");
furi_hal_nfc_deactivate();
furi_hal_nfc_sleep();
}
osDelay(50);
}
furi_hal_nfc_deactivate();
furi_hal_nfc_sleep();
}
void nfc_cli_field(Cli* cli, string_t args) {
static void nfc_cli_field(Cli* cli, string_t args) {
// Check if nfc worker is not busy
if(furi_hal_nfc_is_busy()) {
printf("Nfc is busy\r\n");
@ -97,7 +91,7 @@ void nfc_cli_field(Cli* cli, string_t args) {
}
furi_hal_nfc_field_off();
furi_hal_nfc_deactivate();
furi_hal_nfc_sleep();
}
static void nfc_cli(Cli* cli, string_t args, void* context) {

View File

@ -41,31 +41,31 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_str
static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
if(string_start_with_str_p(format_string, "UID")) {
dev->format = NfcDeviceSaveFormatUid;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown;
dev->dev_data.protocol = NfcDeviceProtocolUnknown;
return true;
}
if(string_start_with_str_p(format_string, "Bank card")) {
dev->format = NfcDeviceSaveFormatBankCard;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV;
dev->dev_data.protocol = NfcDeviceProtocolEMV;
return true;
}
// Check Mifare Ultralight types
for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) {
if(string_start_with_str_p(format_string, nfc_mf_ul_type(type, true))) {
if(string_equal_str_p(format_string, nfc_mf_ul_type(type, true))) {
dev->format = NfcDeviceSaveFormatMifareUl;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl;
dev->dev_data.protocol = NfcDeviceProtocolMifareUl;
dev->dev_data.mf_ul_data.type = type;
return true;
}
}
if(string_start_with_str_p(format_string, "Mifare Classic")) {
dev->format = NfcDeviceSaveFormatMifareClassic;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareClassic;
dev->dev_data.protocol = NfcDeviceProtocolMifareClassic;
return true;
}
if(string_start_with_str_p(format_string, "Mifare DESFire")) {
dev->format = NfcDeviceSaveFormatMifareDesfire;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareDesfire;
dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire;
return true;
}
return false;
@ -73,7 +73,7 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_strin
static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
bool saved = false;
MifareUlData* data = &dev->dev_data.mf_ul_data;
MfUltralightData* data = &dev->dev_data.mf_ul_data;
string_t temp_str;
string_init(temp_str);
@ -122,7 +122,7 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev)
bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
bool parsed = false;
MifareUlData* data = &dev->dev_data.mf_ul_data;
MfUltralightData* data = &dev->dev_data.mf_ul_data;
string_t temp_str;
string_init(temp_str);
@ -548,7 +548,7 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
bool saved = false;
NfcEmvData* data = &dev->dev_data.emv_data;
EmvData* data = &dev->dev_data.emv_data;
uint32_t data_temp = 0;
do {
@ -577,8 +577,8 @@ static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev)
bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
bool parsed = false;
NfcEmvData* data = &dev->dev_data.emv_data;
memset(data, 0, sizeof(NfcEmvData));
EmvData* data = &dev->dev_data.emv_data;
memset(data, 0, sizeof(EmvData));
uint32_t data_cnt = 0;
string_t temp_str;
string_init(temp_str);
@ -700,7 +700,7 @@ static bool nfc_device_save_file(
bool saved = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
FuriHalNfcDevData* data = &dev->dev_data.nfc_data;
string_t temp_str;
string_init(temp_str);
@ -758,7 +758,7 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
bool parsed = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
FuriHalNfcDevData* data = &dev->dev_data.nfc_data;
uint32_t data_cnt = 0;
string_t temp_str;
string_init(temp_str);
@ -789,6 +789,7 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
if(!nfc_device_parse_format_string(dev, temp_str)) break;
// Read and parse UID, ATQA and SAK
if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break;
if(!(data_cnt == 4 || data_cnt == 7)) break;
data->uid_len = data_cnt;
if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
@ -863,7 +864,7 @@ bool nfc_file_select(NfcDevice* dev) {
}
void nfc_device_data_clear(NfcDeviceData* dev_data) {
if(dev_data->nfc_data.protocol == NfcDeviceProtocolMifareDesfire) {
if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) {
mf_df_clear(&dev_data->mf_df_data);
}
}

View File

@ -5,6 +5,8 @@
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include <furi_hal_nfc.h>
#include <lib/nfc_protocols/emv.h>
#include <lib/nfc_protocols/mifare_ultralight.h>
#include <lib/nfc_protocols/mifare_classic.h>
#include <lib/nfc_protocols/mifare_desfire.h>
@ -17,13 +19,6 @@
#define NFC_APP_EXTENSION ".nfc"
#define NFC_APP_SHADOW_EXTENSION ".shd"
typedef enum {
NfcDeviceNfca,
NfcDeviceNfcb,
NfcDeviceNfcf,
NfcDeviceNfcv,
} NfcDeviceType;
typedef enum {
NfcDeviceProtocolUnknown,
NfcDeviceProtocolEMV,
@ -40,38 +35,18 @@ typedef enum {
NfcDeviceSaveFormatMifareDesfire,
} NfcDeviceSaveFormat;
typedef struct {
uint8_t uid_len;
uint8_t uid[10];
uint8_t atqa[2];
uint8_t sak;
NfcDeviceType device;
NfcProtocol protocol;
} NfcDeviceCommonData;
typedef struct {
char name[32];
uint8_t aid[16];
uint16_t aid_len;
uint8_t number[10];
uint8_t number_len;
uint8_t exp_mon;
uint8_t exp_year;
uint16_t country_code;
uint16_t currency_code;
} NfcEmvData;
typedef struct {
uint8_t data[NFC_READER_DATA_MAX_SIZE];
uint16_t size;
} NfcReaderRequestData;
typedef struct {
NfcDeviceCommonData nfc_data;
FuriHalNfcDevData nfc_data;
NfcProtocol protocol;
NfcReaderRequestData reader_data;
union {
NfcEmvData emv_data;
MifareUlData mf_ul_data;
EmvData emv_data;
MfUltralightData mf_ul_data;
MfClassicData mf_classic_data;
MifareDesfireData mf_df_data;
};

View File

@ -40,7 +40,7 @@ struct Nfc {
NotificationApp* notifications;
SceneManager* scene_manager;
NfcDevice* dev;
NfcDeviceCommonData dev_edit_data;
FuriHalNfcDevData dev_edit_data;
char text_store[NFC_TEXT_STORE_SIZE + 1];
string_t text_box_store;

View File

@ -1,48 +1,14 @@
#include "nfc_types.h"
const char* nfc_get_rfal_type(rfalNfcDevType type) {
if(type == RFAL_NFC_LISTEN_TYPE_NFCA) {
const char* nfc_get_dev_type(FuriHalNfcType type) {
if(type == FuriHalNfcTypeA) {
return "NFC-A";
} else if(type == RFAL_NFC_LISTEN_TYPE_NFCB) {
} else if(type == FuriHalNfcTypeB) {
return "NFC-B";
} else if(type == RFAL_NFC_LISTEN_TYPE_NFCF) {
} else if(type == FuriHalNfcTypeF) {
return "NFC-F";
} else if(type == RFAL_NFC_LISTEN_TYPE_NFCV) {
} else if(type == FuriHalNfcTypeV) {
return "NFC-V";
} else if(type == RFAL_NFC_LISTEN_TYPE_ST25TB) {
return "NFC-ST25TB";
} else if(type == RFAL_NFC_LISTEN_TYPE_AP2P) {
return "NFC-AP2P";
} else {
return "Unknown";
}
}
const char* nfc_get_dev_type(NfcDeviceType type) {
if(type == NfcDeviceNfca) {
return "NFC-A";
} else if(type == NfcDeviceNfcb) {
return "NFC-B";
} else if(type == NfcDeviceNfcf) {
return "NFC-F";
} else if(type == NfcDeviceNfcv) {
return "NFC-V";
} else {
return "Unknown";
}
}
const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) {
if(type == RFAL_NFCA_T1T) {
return "T1T";
} else if(type == RFAL_NFCA_T2T) {
return "T2T";
} else if(type == RFAL_NFCA_T4T) {
return "T4T";
} else if(type == RFAL_NFCA_NFCDEP) {
return "NFCDEP";
} else if(type == RFAL_NFCA_T4T_NFCDEP) {
return "T4T_NFCDEP";
} else {
return "Unknown";
}

View File

@ -1,16 +1,8 @@
#pragma once
#include "st_errno.h"
#include "rfal_nfc.h"
#include "nfc_device.h"
#include <gui/view_dispatcher.h>
#include "nfc_worker.h"
const char* nfc_get_rfal_type(rfalNfcDevType type);
const char* nfc_get_dev_type(NfcDeviceType type);
const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type);
const char* nfc_get_dev_type(FuriHalNfcType type);
const char* nfc_guess_protocol(NfcProtocol protocol);

View File

@ -2,7 +2,8 @@
#include <furi_hal.h>
#include <lib/nfc_protocols/nfc_util.h>
#include <lib/nfc_protocols/emv_decoder.h>
#include <lib/nfc_protocols/emv.h>
#include <lib/nfc_protocols/mifare_common.h>
#include <lib/nfc_protocols/mifare_ultralight.h>
#include <lib/nfc_protocols/mifare_classic.h>
#include <lib/nfc_protocols/mifare_desfire.h>
@ -94,22 +95,20 @@ int32_t nfc_worker_task(void* context) {
nfc_worker_emulate(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadEMVApp) {
nfc_worker_read_emv_app(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadEMV) {
} else if(nfc_worker->state == NfcWorkerStateReadEMVData) {
nfc_worker_read_emv(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
nfc_worker_emulate_apdu(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadMifareUl) {
nfc_worker_read_mifare_ul(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
} else if(nfc_worker->state == NfcWorkerStateReadMifareUltralight) {
nfc_worker_read_mifare_ultralight(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
nfc_worker_emulate_mifare_ul(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
nfc_worker_mifare_classic_dict_attack(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
nfc_worker_read_mifare_desfire(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateField) {
nfc_worker_field(nfc_worker);
}
furi_hal_nfc_deactivate();
furi_hal_nfc_sleep();
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
furi_hal_power_insomnia_exit();
@ -117,579 +116,225 @@ int32_t nfc_worker_task(void* context) {
}
void nfc_worker_detect(NfcWorker* nfc_worker) {
rfalNfcDevice* dev_list;
rfalNfcDevice* dev;
uint8_t dev_cnt;
nfc_device_data_clear(nfc_worker->dev_data);
NfcDeviceCommonData* result = &nfc_worker->dev_data->nfc_data;
NfcDeviceData* dev_data = nfc_worker->dev_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
while(nfc_worker->state == NfcWorkerStateDetect) {
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) {
if(furi_hal_nfc_detect(nfc_data, 1000)) {
// Process first found device
dev = &dev_list[0];
result->uid_len = dev->nfcidLen;
memcpy(result->uid, dev->nfcid, dev->nfcidLen);
if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCA) {
result->device = NfcDeviceNfca;
result->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo;
result->atqa[1] = dev->dev.nfca.sensRes.platformInfo;
result->sak = dev->dev.nfca.selRes.sak;
if(mf_ul_check_card_type(
dev->dev.nfca.sensRes.anticollisionInfo,
dev->dev.nfca.sensRes.platformInfo,
dev->dev.nfca.selRes.sak)) {
result->protocol = NfcDeviceProtocolMifareUl;
if(nfc_data->type == FuriHalNfcTypeA) {
if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
dev_data->protocol = NfcDeviceProtocolMifareUl;
} else if(mf_classic_check_card_type(
dev->dev.nfca.sensRes.anticollisionInfo,
dev->dev.nfca.sensRes.platformInfo,
dev->dev.nfca.selRes.sak)) {
result->protocol = NfcDeviceProtocolMifareClassic;
nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
dev_data->protocol = NfcDeviceProtocolMifareClassic;
} else if(mf_df_check_card_type(
dev->dev.nfca.sensRes.anticollisionInfo,
dev->dev.nfca.sensRes.platformInfo,
dev->dev.nfca.selRes.sak)) {
result->protocol = NfcDeviceProtocolMifareDesfire;
} else if(dev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
result->protocol = NfcDeviceProtocolEMV;
nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
dev_data->protocol = NfcDeviceProtocolMifareDesfire;
} else if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
dev_data->protocol = NfcDeviceProtocolEMV;
} else {
result->protocol = NfcDeviceProtocolUnknown;
dev_data->protocol = NfcDeviceProtocolUnknown;
}
} else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCB) {
result->device = NfcDeviceNfcb;
} else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCF) {
result->device = NfcDeviceNfcf;
} else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCV) {
result->device = NfcDeviceNfcv;
}
// Notify caller and exit
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
}
break;
}
furi_hal_nfc_sleep();
osDelay(100);
}
}
bool nfc_worker_emulate_uid_callback(
uint8_t* buff_rx,
uint16_t buff_rx_len,
uint8_t* buff_tx,
uint16_t* buff_tx_len,
uint32_t* data_type,
void* context) {
furi_assert(context);
NfcWorker* nfc_worker = context;
NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
reader_data->size = buff_rx_len / 8;
if(reader_data->size > 0) {
memcpy(reader_data->data, buff_rx, reader_data->size);
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
}
}
return true;
}
void nfc_worker_emulate(NfcWorker* nfc_worker) {
NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data;
FuriHalNfcTxRxContext tx_rx = {};
FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
while(nfc_worker->state == NfcWorkerStateEmulate) {
furi_hal_nfc_emulate_nfca(
data->uid,
data->uid_len,
data->atqa,
data->sak,
nfc_worker_emulate_uid_callback,
nfc_worker,
1000);
if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, true, 100)) {
if(furi_hal_nfc_tx_rx(&tx_rx, 100)) {
reader_data->size = tx_rx.rx_bits / 8;
if(reader_data->size > 0) {
memcpy(reader_data->data, tx_rx.rx_data, reader_data->size);
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
}
}
} else {
FURI_LOG_E(TAG, "Failed to get reader commands");
}
}
}
}
void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
ReturnCode err;
rfalNfcDevice* dev_list;
FuriHalNfcTxRxContext tx_rx = {};
EmvApplication emv_app = {};
uint8_t dev_cnt = 0;
uint8_t tx_buff[255] = {};
uint16_t tx_len = 0;
uint8_t* rx_buff;
uint16_t* rx_len;
NfcDeviceData* result = nfc_worker->dev_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
nfc_device_data_clear(result);
while(nfc_worker->state == NfcWorkerStateReadEMVApp) {
memset(&emv_app, 0, sizeof(emv_app));
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) {
if(furi_hal_nfc_detect(nfc_data, 1000)) {
// Card was found. Check that it supports EMV
if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
memcpy(
result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
result->nfc_data.protocol = NfcDeviceProtocolEMV;
FURI_LOG_D(TAG, "Send select PPSE command");
tx_len = emv_prepare_select_ppse(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err != ERR_NONE) {
FURI_LOG_D(TAG, "Error during selection PPSE request: %d", err);
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Select PPSE response received. Start parsing response");
if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) {
FURI_LOG_D(TAG, "Select PPSE responce parced");
if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
result->protocol = NfcDeviceProtocolEMV;
if(emv_search_application(&tx_rx, &emv_app)) {
// Notify caller and exit
result->emv_data.aid_len = emv_app.aid_len;
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
}
break;
} else {
FURI_LOG_D(TAG, "Can't find pay application");
furi_hal_nfc_deactivate();
continue;
}
} else {
// Can't find EMV card
FURI_LOG_W(TAG, "Card doesn't support EMV");
furi_hal_nfc_deactivate();
}
} else {
// Can't find EMV card
FURI_LOG_D(TAG, "Can't find any cards");
furi_hal_nfc_deactivate();
}
furi_hal_nfc_sleep();
osDelay(20);
}
}
void nfc_worker_read_emv(NfcWorker* nfc_worker) {
ReturnCode err;
rfalNfcDevice* dev_list;
FuriHalNfcTxRxContext tx_rx = {};
EmvApplication emv_app = {};
uint8_t dev_cnt = 0;
uint8_t tx_buff[255] = {};
uint16_t tx_len = 0;
uint8_t* rx_buff;
uint16_t* rx_len;
NfcDeviceData* result = nfc_worker->dev_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
nfc_device_data_clear(result);
while(nfc_worker->state == NfcWorkerStateReadEMV) {
memset(&emv_app, 0, sizeof(emv_app));
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) {
while(nfc_worker->state == NfcWorkerStateReadEMVData) {
if(furi_hal_nfc_detect(nfc_data, 1000)) {
// Card was found. Check that it supports EMV
if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
memcpy(
result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
result->nfc_data.protocol = NfcDeviceProtocolEMV;
FURI_LOG_D(TAG, "Send select PPSE command");
tx_len = emv_prepare_select_ppse(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err != ERR_NONE) {
FURI_LOG_D(TAG, "Error during selection PPSE request: %d", err);
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Select PPSE response received. Start parsing response");
if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) {
FURI_LOG_D(TAG, "Select PPSE responce parced");
if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
result->protocol = NfcDeviceProtocolEMV;
if(emv_read_bank_card(&tx_rx, &emv_app)) {
result->emv_data.number_len = emv_app.card_number_len;
memcpy(
result->emv_data.number, emv_app.card_number, result->emv_data.number_len);
result->emv_data.aid_len = emv_app.aid_len;
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
} else {
FURI_LOG_D(TAG, "Can't find pay application");
furi_hal_nfc_deactivate();
continue;
if(emv_app.name_found) {
memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name));
}
if(emv_app.exp_month) {
result->emv_data.exp_mon = emv_app.exp_month;
result->emv_data.exp_year = emv_app.exp_year;
}
if(emv_app.country_code) {
result->emv_data.country_code = emv_app.country_code;
}
if(emv_app.currency_code) {
result->emv_data.currency_code = emv_app.currency_code;
}
// Notify caller and exit
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
}
break;
}
FURI_LOG_D(TAG, "Starting application ...");
tx_len = emv_prepare_select_app(tx_buff, &emv_app);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err != ERR_NONE) {
FURI_LOG_D(TAG, "Error during application selection request: %d", err);
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Select application response received. Start parsing response");
if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) {
FURI_LOG_D(TAG, "Card name: %s", emv_app.name);
memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name));
} else if(emv_app.pdol.size > 0) {
FURI_LOG_D(TAG, "Can't find card name, but PDOL is present.");
} else {
FURI_LOG_D(TAG, "Can't find card name or PDOL");
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Starting Get Processing Options command ...");
tx_len = emv_prepare_get_proc_opt(tx_buff, &emv_app);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err != ERR_NONE) {
FURI_LOG_D(TAG, "Error during Get Processing Options command: %d", err);
furi_hal_nfc_deactivate();
continue;
}
if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) {
FURI_LOG_D(TAG, "Card number parsed");
result->emv_data.number_len = emv_app.card_number_len;
memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len);
} else {
FURI_LOG_W(TAG, "Card doesn't support EMV");
}
} else {
FURI_LOG_D(TAG, "Can't find any cards");
}
furi_hal_nfc_sleep();
osDelay(20);
}
}
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {};
FuriHalNfcDevData params = {
.uid = {0xCF, 0x72, 0xd4, 0x40},
.uid_len = 4,
.atqa = {0x00, 0x04},
.sak = 0x20,
.type = FuriHalNfcTypeA,
};
while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) {
FURI_LOG_D(TAG, "POS terminal detected");
if(emv_card_emulation(&tx_rx)) {
FURI_LOG_D(TAG, "EMV card emulated");
}
} else {
FURI_LOG_D(TAG, "Can't find reader");
}
furi_hal_nfc_sleep();
osDelay(20);
}
}
void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {};
MfUltralightReader reader = {};
MfUltralightData data = {};
NfcDeviceData* result = nfc_worker->dev_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
while(nfc_worker->state == NfcWorkerStateReadMifareUltralight) {
if(furi_hal_nfc_detect(nfc_data, 300)) {
if(nfc_data->type == FuriHalNfcTypeA &&
mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Start reading");
if(mf_ul_read_card(&tx_rx, &reader, &data)) {
result->protocol = NfcDeviceProtocolMifareUl;
result->mf_ul_data = data;
// Notify caller and exit
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
}
break;
} else {
// Mastercard doesn't give PAN / card number as GPO response
// Iterate over all files found in application
bool pan_found = false;
for(uint8_t i = 0; (i < emv_app.afl.size) && !pan_found; i += 4) {
uint8_t sfi = emv_app.afl.data[i] >> 3;
uint8_t record_start = emv_app.afl.data[i + 1];
uint8_t record_end = emv_app.afl.data[i + 2];
// Iterate over all records in file
for(uint8_t record = record_start; record <= record_end; ++record) {
tx_len = emv_prepare_read_sfi_record(tx_buff, sfi, record);
err = furi_hal_nfc_data_exchange(
tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err != ERR_NONE) {
FURI_LOG_D(
TAG,
"Error reading application sfi %d, record %d",
sfi,
record);
}
if(emv_decode_read_sfi_record(rx_buff, *rx_len, &emv_app)) {
pan_found = true;
break;
}
}
}
if(pan_found) {
FURI_LOG_D(TAG, "Card PAN found");
result->emv_data.number_len = emv_app.card_number_len;
memcpy(
result->emv_data.number,
emv_app.card_number,
result->emv_data.number_len);
if(emv_app.exp_month) {
result->emv_data.exp_mon = emv_app.exp_month;
result->emv_data.exp_year = emv_app.exp_year;
}
if(emv_app.country_code) {
result->emv_data.country_code = emv_app.country_code;
}
if(emv_app.currency_code) {
result->emv_data.currency_code = emv_app.currency_code;
}
// Notify caller and exit
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
}
break;
} else {
FURI_LOG_D(TAG, "Can't read card number");
}
furi_hal_nfc_deactivate();
FURI_LOG_D(TAG, "Failed reading Mifare Ultralight");
}
} else {
// Can't find EMV card
FURI_LOG_W(TAG, "Card doesn't support EMV");
furi_hal_nfc_deactivate();
}
} else {
// Can't find EMV card
FURI_LOG_D(TAG, "Can't find any cards");
furi_hal_nfc_deactivate();
}
osDelay(20);
}
}
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
ReturnCode err;
uint8_t tx_buff[255] = {};
uint16_t tx_len = 0;
uint8_t* rx_buff;
uint16_t* rx_len;
NfcDeviceCommonData params = {
.uid = {0xCF, 0x72, 0xd4, 0x40},
.uid_len = 4,
.atqa = {0x00, 0x04},
.sak = 0x20,
.device = NfcDeviceNfca,
.protocol = NfcDeviceProtocolEMV,
};
// Test RX data
const uint8_t debug_rx[] = {
0xba, 0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca,
0xca, 0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba,
0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca,
0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b,
0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe,
0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba,
0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa,
0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba,
0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce,
0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba, 0x20,
0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce, 0x14,
0x88, 0x00};
// Test TX data
const uint8_t debug_tx[] = {
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
0x10, 0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad,
0xbe, 0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12,
0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe,
0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34,
0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14,
0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef,
0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56,
0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88,
0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce,
0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78,
0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02,
0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce, 0xee,
0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78, 0x9a,
0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02, 0x28,
0x00, 0x00};
while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) {
FURI_LOG_D(TAG, "POS terminal detected");
// Read data from POS terminal
err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
FURI_LOG_D(TAG, "Received Select PPSE");
} else {
FURI_LOG_D(TAG, "Error in 1st data exchange: select PPSE");
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Transive SELECT PPSE ANS");
tx_len = emv_select_ppse_ans(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
FURI_LOG_D(TAG, "Received Select APP");
} else {
FURI_LOG_D(TAG, "Error in 2nd data exchange: select APP");
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Transive SELECT APP ANS");
tx_len = emv_select_app_ans(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
FURI_LOG_D(TAG, "Received PDOL");
} else {
FURI_LOG_D(TAG, "Error in 3rd data exchange: receive PDOL");
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Transive PDOL ANS");
tx_len = emv_get_proc_opt_ans(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
FURI_LOG_D(TAG, "Transive PDOL ANS");
} else {
FURI_LOG_D(TAG, "Error in 4rd data exchange: Transive PDOL ANS");
furi_hal_nfc_deactivate();
continue;
}
if(*rx_len != sizeof(debug_rx) || memcmp(rx_buff, debug_rx, sizeof(debug_rx))) {
FURI_LOG_D(TAG, "Failed long message test");
} else {
FURI_LOG_D(TAG, "Correct debug message received");
tx_len = sizeof(debug_tx);
err = furi_hal_nfc_data_exchange(
(uint8_t*)debug_tx, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
FURI_LOG_D(TAG, "Transive Debug message");
}
}
furi_hal_nfc_deactivate();
} else {
FURI_LOG_D(TAG, "Can't find reader");
}
osDelay(20);
}
}
void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) {
ReturnCode err;
rfalNfcDevice* dev_list;
uint8_t dev_cnt = 0;
uint8_t tx_buff[255] = {};
uint16_t tx_len = 0;
uint8_t* rx_buff;
uint16_t* rx_len;
MifareUlDevice mf_ul_read;
NfcDeviceData* result = nfc_worker->dev_data;
nfc_device_data_clear(result);
while(nfc_worker->state == NfcWorkerStateReadMifareUl) {
furi_hal_nfc_deactivate();
memset(&mf_ul_read, 0, sizeof(mf_ul_read));
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA &&
mf_ul_check_card_type(
dev_list[0].dev.nfca.sensRes.anticollisionInfo,
dev_list[0].dev.nfca.sensRes.platformInfo,
dev_list[0].dev.nfca.selRes.sak)) {
// Get Mifare Ultralight version
FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Reading tag version");
tx_len = mf_ul_prepare_get_version(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
mf_ul_parse_get_version_response(rx_buff, &mf_ul_read);
FURI_LOG_D(
TAG,
"Mifare Ultralight Type: %d, Pages: %d",
mf_ul_read.data.type,
mf_ul_read.pages_to_read);
FURI_LOG_D(TAG, "Reading signature ...");
tx_len = mf_ul_prepare_read_signature(tx_buff);
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
FURI_LOG_D(TAG, "Failed reading signature");
memset(mf_ul_read.data.signature, 0, sizeof(mf_ul_read.data.signature));
} else {
mf_ul_parse_read_signature_response(rx_buff, &mf_ul_read);
}
} else if(err == ERR_TIMEOUT) {
FURI_LOG_D(
TAG,
"Card doesn't respond to GET VERSION command. Setting default read parameters");
err = ERR_NONE;
mf_ul_set_default_version(&mf_ul_read);
// Reinit device
furi_hal_nfc_deactivate();
if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
FURI_LOG_D(TAG, "Lost connection. Restarting search");
continue;
}
} else {
FURI_LOG_D(
TAG, "Error getting Mifare Ultralight version. Error code: %d", err);
continue;
}
if(mf_ul_read.support_fast_read) {
FURI_LOG_D(TAG, "Reading pages ...");
tx_len = mf_ul_prepare_fast_read(tx_buff, 0x00, mf_ul_read.pages_to_read - 1);
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
FURI_LOG_D(TAG, "Failed reading pages");
continue;
} else {
mf_ul_parse_fast_read_response(
rx_buff, 0x00, mf_ul_read.pages_to_read - 1, &mf_ul_read);
}
FURI_LOG_D(TAG, "Reading 3 counters ...");
for(uint8_t i = 0; i < 3; i++) {
tx_len = mf_ul_prepare_read_cnt(tx_buff, i);
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
FURI_LOG_W(TAG, "Failed reading Counter %d", i);
mf_ul_read.data.counter[i] = 0;
} else {
mf_ul_parse_read_cnt_response(rx_buff, i, &mf_ul_read);
}
}
FURI_LOG_D(TAG, "Checking tearing flags ...");
for(uint8_t i = 0; i < 3; i++) {
tx_len = mf_ul_prepare_check_tearing(tx_buff, i);
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
FURI_LOG_D(TAG, "Error checking tearing flag %d", i);
mf_ul_read.data.tearing[i] = MF_UL_TEARING_FLAG_DEFAULT;
} else {
mf_ul_parse_check_tearing_response(rx_buff, i, &mf_ul_read);
}
}
} else {
// READ card with READ command (4 pages at a time)
for(uint8_t page = 0; page < mf_ul_read.pages_to_read; page += 4) {
FURI_LOG_D(TAG, "Reading pages %d - %d ...", page, page + 3);
tx_len = mf_ul_prepare_read(tx_buff, page);
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
FURI_LOG_D(TAG, "Read pages %d - %d failed", page, page + 3);
continue;
} else {
mf_ul_parse_read_response(rx_buff, page, &mf_ul_read);
}
}
}
// Fill result data
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
result->nfc_data.protocol = NfcDeviceProtocolMifareUl;
memcpy(
result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
result->mf_ul_data = mf_ul_read.data;
// Notify caller and exit
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
}
break;
} else {
FURI_LOG_W(TAG, "Tag does not support Mifare Ultralight");
FURI_LOG_W(TAG, "Tag is not Mifare Ultralight");
}
} else {
FURI_LOG_D(TAG, "Can't find any tags");
}
furi_hal_nfc_sleep();
osDelay(100);
}
}
void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
NfcDeviceCommonData* nfc_common = &nfc_worker->dev_data->nfc_data;
MifareUlDevice mf_ul_emulate;
mf_ul_prepare_emulation(&mf_ul_emulate, &nfc_worker->dev_data->mf_ul_data);
while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
MfUltralightEmulator emulator = {};
mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data);
while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
furi_hal_nfc_emulate_nfca(
nfc_common->uid,
nfc_common->uid_len,
nfc_common->atqa,
nfc_common->sak,
nfc_data->uid,
nfc_data->uid_len,
nfc_data->atqa,
nfc_data->sak,
mf_ul_prepare_emulation_response,
&mf_ul_emulate,
&emulator,
5000);
// Check if data was modified
if(mf_ul_emulate.data_changed) {
nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data;
if(emulator.data_changed) {
nfc_worker->dev_data->mf_ul_data = emulator.data;
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
}
mf_ul_emulate.data_changed = false;
emulator.data_changed = false;
}
}
}
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
furi_assert(nfc_worker->callback);
rfalNfcDevice* dev_list;
rfalNfcDevice* dev;
NfcDeviceCommonData* nfc_common;
uint8_t dev_cnt = 0;
FuriHalNfcTxRxContext tx_rx_ctx = {};
MfClassicAuthContext auth_ctx = {};
MfClassicReader reader = {};
@ -697,6 +342,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
uint16_t curr_sector = 0;
uint8_t total_sectors = 0;
NfcWorkerEvent event;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
// Open dictionary
nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage);
@ -710,14 +356,13 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
// Detect Mifare Classic card
while(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
dev = &dev_list[0];
if(furi_hal_nfc_detect(nfc_data, 300)) {
if(mf_classic_get_type(
dev->nfcid,
dev->nfcidLen,
dev->dev.nfca.sensRes.anticollisionInfo,
dev->dev.nfca.sensRes.platformInfo,
dev->dev.nfca.selRes.sak,
nfc_data->uid,
nfc_data->uid_len,
nfc_data->atqa[0],
nfc_data->atqa[1],
nfc_data->sak,
&reader)) {
total_sectors = mf_classic_get_total_sectors_num(&reader);
if(reader.type == MfClassicType1k) {
@ -745,7 +390,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector);
bool sector_key_found = false;
while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) {
furi_hal_nfc_deactivate();
furi_hal_nfc_sleep();
if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) {
if(!card_found_notified) {
if(reader.type == MfClassicType1k) {
@ -817,15 +462,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
uint8_t sectors_read =
mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data);
if(sectors_read) {
dev = &dev_list[0];
nfc_common = &nfc_worker->dev_data->nfc_data;
nfc_common->uid_len = dev->dev.nfca.nfcId1Len;
nfc_common->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo;
nfc_common->atqa[1] = dev->dev.nfca.sensRes.platformInfo;
nfc_common->sak = dev->dev.nfca.selRes.sak;
nfc_common->protocol = NfcDeviceProtocolMifareClassic;
memcpy(nfc_common->uid, dev->dev.nfca.nfcId1, nfc_common->uid_len);
event = NfcWorkerEventSuccess;
nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic;
FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read);
} else {
event = NfcWorkerEventFail;
@ -838,42 +476,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
stream_free(nfc_worker->dict_stream);
}
ReturnCode nfc_exchange_full(
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;
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len, false);
if(*part_len > rx_cap) {
return ERR_OVERRUN;
}
memcpy(rx_buff, part_buff, *part_len);
*rx_len = *part_len;
while(err == ERR_NONE && rx_buff[0] == 0xAF) {
err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len, false);
if(*part_len > rx_cap - *rx_len) {
return ERR_OVERRUN;
}
if(*part_len == 0) {
return ERR_PROTO;
}
memcpy(rx_buff + *rx_len, part_buff + 1, *part_len - 1);
*rx_buff = *part_buff;
*rx_len += *part_len - 1;
}
return err;
}
void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
ReturnCode err;
rfalNfcDevice* dev_list;
uint8_t dev_cnt = 0;
uint8_t tx_buff[64] = {};
uint16_t tx_len = 0;
uint8_t rx_buff[512] = {};
@ -881,19 +485,17 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
NfcDeviceData* result = nfc_worker->dev_data;
nfc_device_data_clear(result);
MifareDesfireData* data = &result->mf_df_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
furi_hal_nfc_deactivate();
if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
furi_hal_nfc_sleep();
if(!furi_hal_nfc_detect(nfc_data, 300)) {
osDelay(100);
continue;
}
memset(data, 0, sizeof(MifareDesfireData));
if(dev_list[0].type != RFAL_NFC_LISTEN_TYPE_NFCA ||
!mf_df_check_card_type(
dev_list[0].dev.nfca.sensRes.anticollisionInfo,
dev_list[0].dev.nfca.sensRes.platformInfo,
dev_list[0].dev.nfca.selRes.sak)) {
if(nfc_data->type != FuriHalNfcTypeA ||
!mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
FURI_LOG_D(TAG, "Tag is not DESFire");
osDelay(100);
continue;
@ -901,18 +503,11 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
FURI_LOG_D(TAG, "Found DESFire tag");
// Fill non-DESFire result data
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
result->nfc_data.device = NfcDeviceNfca;
result->nfc_data.protocol = NfcDeviceProtocolMifareDesfire;
memcpy(result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
result->protocol = NfcDeviceProtocolMifareDesfire;
// Get DESFire version
tx_len = mf_df_prepare_get_version(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err);
continue;
@ -923,7 +518,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
}
tx_len = mf_df_prepare_get_free_memory(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err == ERR_NONE) {
data->free_memory = malloc(sizeof(MifareDesfireFreeMemory));
memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory));
@ -935,7 +530,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
}
tx_len = mf_df_prepare_get_key_settings(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) {
FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err);
} else {
@ -951,7 +546,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
&data->master_key_settings->key_version_head;
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);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err =
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
continue;
@ -970,7 +566,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
}
tx_len = mf_df_prepare_get_application_ids(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err);
} else {
@ -981,13 +577,13 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
tx_len = mf_df_prepare_select_application(tx_buff, app->id);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(!mf_df_parse_select_application_response(rx_buff, rx_len)) {
FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err);
continue;
}
tx_len = mf_df_prepare_get_key_settings(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err);
} else {
@ -1002,7 +598,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
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++) {
tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err = furi_hal_nfc_exchange_full(
tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
continue;
@ -1021,7 +618,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
}
tx_len = mf_df_prepare_get_file_ids(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err);
} else {
@ -1032,7 +629,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err =
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err);
continue;
@ -1054,7 +652,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0);
break;
}
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
err =
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err);
continue;
@ -1073,11 +672,3 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
break;
}
}
void nfc_worker_field(NfcWorker* nfc_worker) {
furi_hal_nfc_field_on();
while(nfc_worker->state == NfcWorkerStateField) {
osDelay(50);
}
furi_hal_nfc_field_off();
}

View File

@ -13,11 +13,11 @@ typedef enum {
NfcWorkerStateDetect,
NfcWorkerStateEmulate,
NfcWorkerStateReadEMVApp,
NfcWorkerStateReadEMV,
NfcWorkerStateReadEMVData,
NfcWorkerStateEmulateApdu,
NfcWorkerStateField,
NfcWorkerStateReadMifareUl,
NfcWorkerStateEmulateMifareUl,
NfcWorkerStateReadMifareUltralight,
NfcWorkerStateEmulateMifareUltralight,
NfcWorkerStateReadMifareClassic,
NfcWorkerStateReadMifareDesfire,
// Transition

View File

@ -4,19 +4,8 @@
#include "nfc_worker.h"
#include <furi.h>
#include <stdbool.h>
#include <lib/toolbox/stream/file_stream.h>
#include <rfal_analogConfig.h>
#include <rfal_rf.h>
#include <rfal_nfc.h>
#include <rfal_nfca.h>
#include <rfal_nfcb.h>
#include <rfal_nfcf.h>
#include <rfal_nfcv.h>
#include <st25r3916.h>
#include <st25r3916_irq.h>
struct NfcWorker {
FuriThread* thread;
Storage* storage;
@ -44,9 +33,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker);
void nfc_worker_emulate(NfcWorker* nfc_worker);
void nfc_worker_field(NfcWorker* nfc_worker);
void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker);
void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker);
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker);

View File

@ -17,7 +17,7 @@ void nfc_scene_card_menu_on_enter(void* context) {
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
if(nfc->dev->dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) {
if(nfc->dev->dev_data.protocol > NfcDeviceProtocolUnknown) {
submenu_add_item(
submenu,
"Run Compatible App",
@ -49,13 +49,13 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
if(event.event == SubmenuIndexRunApp) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp);
if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) {
if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
} else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareDesfire) {
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareDesfire) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire);
} else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) {
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolEMV) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
} else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareClassic) {
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic);
}
consumed = true;

View File

@ -2,7 +2,6 @@ ADD_SCENE(nfc, start, Start)
ADD_SCENE(nfc, read_card, ReadCard)
ADD_SCENE(nfc, read_card_success, ReadCardSuccess)
ADD_SCENE(nfc, card_menu, CardMenu)
ADD_SCENE(nfc, not_implemented, NotImplemented)
ADD_SCENE(nfc, emulate_uid, EmulateUid)
ADD_SCENE(nfc, save_name, SaveName)
ADD_SCENE(nfc, save_success, SaveSuccess)

View File

@ -6,13 +6,13 @@ enum SubmenuDebugIndex {
};
void nfc_scene_debug_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_debug_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
submenu_add_item(
@ -28,7 +28,7 @@ void nfc_scene_debug_on_enter(void* context) {
}
bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
@ -48,7 +48,7 @@ bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
}
void nfc_scene_debug_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
submenu_reset(nfc->submenu);
}

View File

@ -1,29 +1,28 @@
#include "../nfc_i.h"
void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_delete_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Setup Custom Widget view
char delete_str[64];
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", nfc->dev->dev_name);
widget_add_text_box_element(nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str);
char temp_str[64];
snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", nfc->dev->dev_name);
widget_add_text_box_element(nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str);
widget_add_button_element(
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc);
widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc);
char uid_str[32];
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
if(data->uid_len == 4) {
snprintf(
uid_str,
sizeof(uid_str),
temp_str,
sizeof(temp_str),
"UID: %02X %02X %02X %02X",
data->uid[0],
data->uid[1],
@ -31,8 +30,8 @@ void nfc_scene_delete_on_enter(void* context) {
data->uid[3]);
} else if(data->uid_len == 7) {
snprintf(
uid_str,
sizeof(uid_str),
temp_str,
sizeof(temp_str),
"UID: %02X %02X %02X %02X %02X %02X %02X",
data->uid[0],
data->uid[1],
@ -42,12 +41,13 @@ void nfc_scene_delete_on_enter(void* context) {
data->uid[5],
data->uid[6]);
}
widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, uid_str);
widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, temp_str);
const char* protocol_name = NULL;
if(data->protocol == NfcDeviceProtocolEMV) {
protocol_name = nfc_guess_protocol(data->protocol);
} else if(data->protocol == NfcDeviceProtocolMifareUl) {
NfcProtocol protocol = nfc->dev->dev_data.protocol;
if(protocol == NfcDeviceProtocolEMV) {
protocol_name = nfc_guess_protocol(protocol);
} else if(protocol == NfcDeviceProtocolMifareUl) {
protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
}
if(protocol_name) {
@ -56,18 +56,17 @@ void nfc_scene_delete_on_enter(void* context) {
}
// TODO change dinamically
widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A");
char sak_str[16];
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak);
widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, sak_str);
char atqa_str[16];
snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, atqa_str);
snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak);
widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, temp_str);
snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
@ -79,14 +78,14 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart);
}
return true;
consumed = true;
}
}
return false;
return consumed;
}
void nfc_scene_delete_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
widget_reset(nfc->widget);
}

View File

@ -1,12 +1,12 @@
#include "../nfc_i.h"
void nfc_scene_delete_success_popup_callback(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
}
void nfc_scene_delete_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Setup view
Popup* popup = nfc->popup;
@ -20,27 +20,21 @@ void nfc_scene_delete_success_on_enter(void* context) {
}
bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventViewExit) {
return scene_manager_search_and_switch_to_previous_scene(
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart);
}
}
return false;
return consumed;
}
void nfc_scene_delete_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
}
popup_reset(nfc->popup);
}

View File

@ -43,12 +43,12 @@ void nfc_scene_device_info_on_enter(void* context) {
widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc);
}
char uid_str[32];
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
char temp_str[32];
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
if(data->uid_len == 4) {
snprintf(
uid_str,
sizeof(uid_str),
temp_str,
sizeof(temp_str),
"UID: %02X %02X %02X %02X",
data->uid[0],
data->uid[1],
@ -56,8 +56,8 @@ void nfc_scene_device_info_on_enter(void* context) {
data->uid[3]);
} else if(data->uid_len == 7) {
snprintf(
uid_str,
sizeof(uid_str),
temp_str,
sizeof(temp_str),
"UID: %02X %02X %02X %02X %02X %02X %02X",
data->uid[0],
data->uid[1],
@ -67,15 +67,15 @@ void nfc_scene_device_info_on_enter(void* context) {
data->uid[5],
data->uid[6]);
}
widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str);
widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, temp_str);
const char* protocol_name = NULL;
if(data->protocol == NfcDeviceProtocolEMV ||
data->protocol == NfcDeviceProtocolMifareDesfire) {
protocol_name = nfc_guess_protocol(data->protocol);
} else if(data->protocol == NfcDeviceProtocolMifareUl) {
NfcProtocol protocol = nfc->dev->dev_data.protocol;
if(protocol == NfcDeviceProtocolEMV || protocol == NfcDeviceProtocolMifareDesfire) {
protocol_name = nfc_guess_protocol(protocol);
} else if(protocol == NfcDeviceProtocolMifareUl) {
protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
} else if(data->protocol == NfcDeviceProtocolMifareClassic) {
} else if(protocol == NfcDeviceProtocolMifareClassic) {
protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type);
}
if(protocol_name) {
@ -84,12 +84,10 @@ void nfc_scene_device_info_on_enter(void* context) {
}
// TODO change dinamically
widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A");
char sak_str[16];
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak);
widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, sak_str);
char atqa_str[16];
snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, atqa_str);
snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak);
widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, temp_str);
snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, temp_str);
// Setup Data View
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
@ -99,7 +97,7 @@ void nfc_scene_device_info_on_enter(void* context) {
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback);
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
TextBox* text_box = nfc->text_box;
text_box_set_font(text_box, TextBoxFontHex);
for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) {
@ -130,7 +128,7 @@ void nfc_scene_device_info_on_enter(void* context) {
widget_add_string_element(
nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store);
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
BankCard* bank_card = nfc->bank_card;
bank_card_set_name(bank_card, emv_data->name);
bank_card_set_number(bank_card, emv_data->number, emv_data->number_len);
@ -212,21 +210,16 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
}
void nfc_scene_device_info_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear Custom Widget
// Clear views
widget_reset(nfc->widget);
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
// Clear Dialog
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_reset(dialog_ex);
dialog_ex_reset(nfc->dialog_ex);
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
// Clear TextBox
text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store);
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
// Clear Bank Card
bank_card_clear(nfc->bank_card);
}
}

View File

@ -1,36 +1,34 @@
#include "../nfc_i.h"
void nfc_scene_emulate_apdu_sequence_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Setup view
Popup* popup = nfc->popup;
popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop);
// Setup and start worker
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc);
}
bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10);
return true;
consumed = true;
}
return false;
return consumed;
}
void nfc_scene_emulate_apdu_sequence_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
Popup* popup = nfc->popup;
popup_reset(popup);
popup_reset(nfc->popup);
}

View File

@ -5,13 +5,14 @@
#define NFC_MF_UL_DATA_CHANGED (1UL)
void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
}
void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcEmulate);
// Setup view
@ -26,14 +27,14 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
nfc_worker_start(
nfc->worker,
NfcWorkerStateEmulateMifareUl,
NfcWorkerStateEmulateMifareUltralight,
&nfc->dev->dev_data,
nfc_emulate_mifare_ul_worker_callback,
nfc);
}
bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) {
@ -55,11 +56,8 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event
}
void nfc_scene_emulate_mifare_ul_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_reset(nfc->popup);
}

View File

@ -1,6 +1,8 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>
#define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200)
enum {
NfcSceneEmulateUidStateWidget,
NfcSceneEmulateUidStateTextBox,
@ -28,7 +30,7 @@ void nfc_emulate_uid_textbox_callback(void* context) {
// Add widget with device name or inform that data received
static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
Widget* widget = nfc->widget;
widget_reset(widget);
string_t info_str;
@ -95,13 +97,15 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) {
nfc_scene_emulate_uid_widget_config(nfc, true);
}
// Update TextBox data
string_cat_printf(nfc->text_box_store, "R:");
for(uint16_t i = 0; i < reader_data->size; i++) {
string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]);
if(string_size(nfc->text_box_store) < NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX) {
string_cat_printf(nfc->text_box_store, "R:");
for(uint16_t i = 0; i < reader_data->size; i++) {
string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]);
}
string_push_back(nfc->text_box_store, '\n');
text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store));
}
string_push_back(nfc->text_box_store, '\n');
memset(reader_data, 0, sizeof(NfcReaderRequestData));
text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store));
consumed = true;
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);

View File

@ -1,7 +1,7 @@
#include "../nfc_i.h"
void nfc_scene_field_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
furi_hal_nfc_field_on();
@ -23,12 +23,9 @@ bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) {
}
void nfc_scene_field_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
notification_internal_message(nfc->notifications, &sequence_reset_blue);
Popup* popup = nfc->popup;
popup_reset(popup);
Nfc* nfc = context;
furi_hal_nfc_field_off();
notification_internal_message(nfc->notifications, &sequence_reset_blue);
popup_reset(nfc->popup);
}

View File

@ -1,7 +1,7 @@
#include "../nfc_i.h"
void nfc_scene_file_select_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Process file_select return
if(nfc_file_select(nfc->dev)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);

View File

@ -18,13 +18,13 @@ MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) {
}
void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_mifare_desfire_app_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc);
if(!app) {
@ -73,7 +73,8 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) {
}
bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp);
if(event.type == SceneManagerEventTypeCustom) {
@ -96,24 +97,24 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
return true;
consumed = true;
} else if(event.type == SceneManagerEventTypeBack) {
if(state & 1) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1);
return true;
consumed = true;
}
}
return false;
return consumed;
}
void nfc_scene_mifare_desfire_app_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear views
text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store);
submenu_reset(nfc->submenu);
}

View File

@ -19,7 +19,7 @@ void nfc_scene_mifare_desfire_data_submenu_callback(void* context, uint32_t inde
}
void nfc_scene_mifare_desfire_data_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
@ -61,7 +61,8 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) {
}
bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
@ -76,7 +77,7 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
nfc->scene_manager,
NfcSceneMifareDesfireData,
MifareDesfireDataStateItem + SubmenuIndexCardInfo);
return true;
consumed = true;
} else {
uint16_t index = event.event - SubmenuIndexDynamic;
scene_manager_set_scene_state(
@ -84,25 +85,25 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp);
return true;
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
if(state >= MifareDesfireDataStateItem) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu);
return true;
consumed = true;
}
}
return false;
return consumed;
}
void nfc_scene_mifare_desfire_data_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear views
text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store);
submenu_reset(nfc->submenu);
}

View File

@ -5,13 +5,13 @@ enum SubmenuIndex {
};
void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
submenu_add_item(
@ -24,7 +24,8 @@ void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
}
bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSave) {
@ -34,15 +35,16 @@ bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent eve
// Clear device name
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true;
consumed = true;
}
}
return false;
return consumed;
}
void nfc_scene_mifare_desfire_menu_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
submenu_reset(nfc->submenu);
}

View File

@ -6,13 +6,13 @@ enum SubmenuIndex {
};
void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_mifare_ul_menu_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
submenu_add_item(
@ -26,7 +26,8 @@ void nfc_scene_mifare_ul_menu_on_enter(void* context) {
}
bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSave) {
@ -36,23 +37,24 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
// Clear device name
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true;
consumed = true;
} else if(event.event == SubmenuIndexEmulate) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
return true;
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
return scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart);
consumed =
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);
}
return false;
return consumed;
}
void nfc_scene_mifare_ul_menu_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
submenu_reset(nfc->submenu);
}

View File

@ -1,42 +0,0 @@
#include "../nfc_i.h"
void nfc_scene_not_implemented_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = (Nfc*)context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
void nfc_scene_not_implemented_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
// TODO Set data from worker
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Back");
dialog_ex_set_header(dialog_ex, "Not implemented", 60, 24, AlignCenter, AlignCenter);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_not_implemented_dialog_callback);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
}
bool nfc_scene_not_implemented_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) {
return scene_manager_previous_scene(nfc->scene_manager);
}
}
return false;
}
void nfc_scene_not_implemented_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
}

View File

@ -2,12 +2,12 @@
#include <dolphin/dolphin.h>
void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
}
void nfc_scene_read_card_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcRead);
// Setup view
@ -22,29 +22,26 @@ void nfc_scene_read_card_on_enter(void* context) {
}
bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventWorkerExit) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
return true;
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10);
return true;
consumed = true;
}
return false;
return consumed;
}
void nfc_scene_read_card_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_reset(nfc->popup);
}

View File

@ -7,13 +7,15 @@ void nfc_scene_read_card_success_widget_callback(
void* context) {
furi_assert(context);
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_read_card_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
string_t data_str;
string_t uid_str;
string_init(data_str);
@ -24,9 +26,9 @@ void nfc_scene_read_card_success_on_enter(void* context) {
notification_message(nfc->notifications, &sequence_success);
// Setup view
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
Widget* widget = nfc->widget;
string_set_str(data_str, nfc_get_dev_type(data->device));
string_set_str(data_str, nfc_get_dev_type(data->type));
string_set_str(uid_str, "UID:");
for(uint8_t i = 0; i < data->uid_len; i++) {
string_cat_printf(uid_str, " %02X", data->uid[i]);
@ -34,7 +36,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc);
if(data->device == NfcDeviceNfca) {
if(data->type == FuriHalNfcTypeA) {
widget_add_button_element(
widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc);
widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21);
@ -44,7 +46,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
string_printf(
data_str,
"%s\nATQA: %02X%02X SAK: %02X",
nfc_guess_protocol(data->protocol),
nfc_guess_protocol(nfc->dev->dev_data.protocol),
data->atqa[0],
data->atqa[1],
data->sak);
@ -66,14 +68,14 @@ void nfc_scene_read_card_success_on_enter(void* context) {
}
bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
Nfc* nfc = context;
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
} else if(data->device == NfcDeviceNfca && event.event == GuiButtonTypeRight) {
} else if(data->type == FuriHalNfcTypeA && event.event == GuiButtonTypeRight) {
// Clear device name
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu);
@ -84,6 +86,8 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event
}
void nfc_scene_read_card_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
widget_reset(nfc->widget);
}

View File

@ -2,12 +2,12 @@
#include <dolphin/dolphin.h>
void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
}
void nfc_scene_read_emv_app_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcRead);
// Setup view
@ -26,31 +26,30 @@ void nfc_scene_read_emv_app_on_enter(void* context) {
}
bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventWorkerExit) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE);
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess);
return true;
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10);
return true;
consumed = true;
}
return false;
return consumed;
}
void nfc_scene_read_emv_app_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_reset(nfc->popup);
}

View File

@ -2,27 +2,38 @@
#include "../helpers/nfc_emv_parser.h"
#include <dolphin/dolphin.h>
#define NFC_SCENE_READ_SUCCESS_SHIFT " "
void nfc_scene_read_emv_app_success_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = (Nfc*)context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
void nfc_scene_read_emv_app_widget_callback(GuiButtonType result, InputType type, void* context) {
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_read_emv_app_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Setup view
NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data;
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "Run app");
dialog_ex_set_header(dialog_ex, "Found EMV App", 36, 8, AlignLeft, AlignCenter);
dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21);
// Display UID and AID
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
Widget* widget = nfc->widget;
widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_emv_app_widget_callback, nfc);
widget_add_button_element(
widget, GuiButtonTypeRight, "Run app", nfc_scene_read_emv_app_widget_callback, nfc);
widget_add_string_element(widget, 36, 5, AlignLeft, AlignTop, FontPrimary, "Found EMV App");
widget_add_icon_element(widget, 8, 5, &I_Medium_chip_22x21);
// Display UID
string_t temp_str;
string_init_printf(temp_str, "UID:");
for(size_t i = 0; i < nfc_data->uid_len; i++) {
string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
}
widget_add_string_element(
widget, 36, 18, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
string_reset(temp_str);
// Display application
string_printf(temp_str, "App: ");
string_t aid;
string_init(aid);
bool aid_found =
@ -32,19 +43,11 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
string_cat_printf(aid, "%02X", emv_data->aid[i]);
}
}
nfc_text_store_set(
nfc,
NFC_SCENE_READ_SUCCESS_SHIFT "UID: %02X %02X %02X %02X \n" NFC_SCENE_READ_SUCCESS_SHIFT
"Application:\n%s",
nfc_data->uid[0],
nfc_data->uid[1],
nfc_data->uid[2],
nfc_data->uid[3],
string_get_cstr(aid));
string_cat(temp_str, aid);
widget_add_string_element(
widget, 7, 29, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
string_clear(temp_str);
string_clear(aid);
dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_emv_app_success_dialog_callback);
// Send notification
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) ==
@ -54,32 +57,27 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE);
}
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) {
return scene_manager_previous_scene(nfc->scene_manager);
} else if(event.event == DialogExResultRight) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
} else if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm);
return true;
consumed = true;
}
}
return false;
return consumed;
}
void nfc_scene_read_emv_app_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_right_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
// Clear views
widget_reset(nfc->widget);
}

View File

@ -2,12 +2,12 @@
#include <dolphin/dolphin.h>
void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
}
void nfc_scene_read_emv_data_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcRead);
// Setup view
@ -21,38 +21,35 @@ void nfc_scene_read_emv_data_on_enter(void* context) {
// Start worker
nfc_worker_start(
nfc->worker,
NfcWorkerStateReadEMV,
NfcWorkerStateReadEMVData,
&nfc->dev->dev_data,
nfc_read_emv_data_worker_callback,
nfc);
}
bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventWorkerExit) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE);
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess);
return true;
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10);
return true;
consumed = true;
}
return false;
return consumed;
}
void nfc_scene_read_emv_data_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_reset(nfc->popup);
}

View File

@ -6,16 +6,16 @@ void nfc_scene_read_emv_data_success_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_read_emv_data_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data;
Nfc* nfc = context;
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Setup Custom Widget view
@ -78,25 +78,23 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
string_clear(disp_currency);
}
string_clear(currency_name);
char temp_str[32];
// Add ATQA
char atqa_str[16];
snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]);
widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, atqa_str);
snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]);
widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, temp_str);
// Add UID
char uid_str[32];
snprintf(
uid_str,
sizeof(uid_str),
temp_str,
sizeof(temp_str),
"UID: %02X %02X %02X %02X",
nfc_data->uid[0],
nfc_data->uid[1],
nfc_data->uid[2],
nfc_data->uid[3]);
widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, uid_str);
widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, temp_str);
// Add SAK
char sak_str[16];
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak);
widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str);
snprintf(temp_str, sizeof(temp_str), "SAK: %02X", nfc_data->sak);
widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, temp_str);
// Add expiration date
if(emv_data->exp_mon) {
char exp_str[16];
@ -117,28 +115,30 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
}
bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
return scene_manager_search_and_switch_to_previous_scene(
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
} else if(event.event == GuiButtonTypeRight) {
// Clear device name
nfc_device_set_name(nfc->dev, "");
nfc->dev->format = NfcDeviceSaveFormatBankCard;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true;
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
return scene_manager_search_and_switch_to_previous_scene(
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
}
return false;
return consumed;
}
void nfc_scene_read_emv_data_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
widget_reset(nfc->widget);
}

View File

@ -2,12 +2,12 @@
#include <dolphin/dolphin.h>
void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
}
void nfc_scene_read_mifare_desfire_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcRead);
// Setup view
@ -26,31 +26,28 @@ void nfc_scene_read_mifare_desfire_on_enter(void* context) {
}
bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventWorkerExit) {
notification_message(nfc->notifications, &sequence_success);
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
return true;
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10);
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
return true;
consumed = true;
}
return false;
return consumed;
}
void nfc_scene_read_mifare_desfire_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_reset(nfc->popup);
}

View File

@ -9,13 +9,13 @@ enum {
};
void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
DialogEx* dialog_ex = nfc->dialog_ex;
@ -67,9 +67,9 @@ void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
uint32_t state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) {
@ -98,9 +98,8 @@ bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerE
}
void nfc_scene_read_mifare_desfire_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clean dialog
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_reset(dialog_ex);
dialog_ex_reset(nfc->dialog_ex);
}

View File

@ -19,7 +19,7 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) {
// Start worker
nfc_worker_start(
nfc->worker,
NfcWorkerStateReadMifareUl,
NfcWorkerStateReadMifareUltralight,
&nfc->dev->dev_data,
nfc_read_mifare_ul_worker_callback,
nfc);
@ -43,6 +43,7 @@ bool nfc_scene_read_mifare_ul_on_event(void* context, SceneManagerEvent event) {
void nfc_scene_read_mifare_ul_on_exit(void* context) {
Nfc* nfc = context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view

View File

@ -9,21 +9,21 @@ enum {
};
void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Send notification
notification_message(nfc->notifications, &sequence_success);
// Setup dialog view
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
@ -69,9 +69,9 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
uint32_t state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
@ -99,14 +99,10 @@ bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent
}
void nfc_scene_read_mifare_ul_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clean dialog
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_reset(dialog_ex);
// Clean TextBox
TextBox* text_box = nfc->text_box;
text_box_reset(text_box);
// Clean views
dialog_ex_reset(nfc->dialog_ex);
text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store);
}

View File

@ -1,12 +1,12 @@
#include "../nfc_i.h"
void nfc_scene_restore_original_popup_callback(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
}
void nfc_scene_restore_original_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Setup view
Popup* popup = nfc->popup;
@ -20,7 +20,7 @@ void nfc_scene_restore_original_on_enter(void* context) {
}
bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
@ -32,15 +32,8 @@ bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event)
}
void nfc_scene_restore_original_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
popup_reset(nfc->popup);
}

View File

@ -1,15 +1,13 @@
#include "../nfc_i.h"
#define NFC_SCENE_READ_SUCCESS_SHIFT " "
void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Back");
@ -29,28 +27,23 @@ void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
}
bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) {
return scene_manager_previous_scene(nfc->scene_manager);
consumed = scene_manager_previous_scene(nfc->scene_manager);
} else if(event.event == DialogExResultRight) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData);
return true;
consumed = true;
}
}
return false;
return consumed;
}
void nfc_scene_run_emv_app_confirm_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_right_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
// Clean view
dialog_ex_reset(nfc->dialog_ex);
}

View File

@ -3,13 +3,13 @@
#include <gui/modules/validators.h>
void nfc_scene_save_name_text_input_callback(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone);
}
void nfc_scene_save_name_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Setup view
TextInput* text_input = nfc->text_input;
@ -37,7 +37,8 @@ void nfc_scene_save_name_on_enter(void* context) {
}
bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventTextInputDone) {
@ -50,18 +51,18 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
if(nfc_device_save(nfc->dev, nfc->text_store)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
return true;
consumed = true;
} else {
return scene_manager_search_and_switch_to_previous_scene(
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart);
}
}
}
return false;
return consumed;
}
void nfc_scene_save_name_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
void* validator_context = text_input_get_validator_callback_context(nfc->text_input);

View File

@ -2,12 +2,12 @@
#include <dolphin/dolphin.h>
void nfc_scene_save_success_popup_callback(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
}
void nfc_scene_save_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcSave);
// Setup view
@ -22,7 +22,7 @@ void nfc_scene_save_success_on_enter(void* context) {
}
bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
@ -47,15 +47,8 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
}
void nfc_scene_save_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
popup_reset(nfc->popup);
}

View File

@ -9,13 +9,13 @@ enum SubmenuIndex {
};
void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_saved_menu_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
if(nfc->dev->format == NfcDeviceSaveFormatUid ||
@ -56,7 +56,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
}
bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
@ -92,7 +92,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
}
void nfc_scene_saved_menu_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
submenu_reset(nfc->submenu);
}

View File

@ -1,13 +1,13 @@
#include "../nfc_i.h"
void nfc_scene_set_atqa_byte_input_callback(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
}
void nfc_scene_set_atqa_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Setup view
ByteInput* byte_input = nfc->byte_input;
@ -23,19 +23,20 @@ void nfc_scene_set_atqa_on_enter(void* context) {
}
bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
return true;
consumed = true;
}
}
return false;
return consumed;
}
void nfc_scene_set_atqa_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);

View File

@ -1,13 +1,13 @@
#include "../nfc_i.h"
void nfc_scene_set_sak_byte_input_callback(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
}
void nfc_scene_set_sak_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Setup view
ByteInput* byte_input = nfc->byte_input;
@ -23,19 +23,20 @@ void nfc_scene_set_sak_on_enter(void* context) {
}
bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua);
return true;
consumed = true;
}
}
return false;
return consumed;
}
void nfc_scene_set_sak_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);

View File

@ -6,13 +6,13 @@ enum SubmenuIndex {
};
void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_set_type_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
// Clear device name
nfc_device_set_name(nfc->dev, "");
@ -24,26 +24,27 @@ void nfc_scene_set_type_on_enter(void* context) {
}
bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexNFCA7) {
nfc->dev->dev_data.nfc_data.uid_len = 7;
nfc->dev->format = NfcDeviceSaveFormatUid;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
return true;
consumed = true;
} else if(event.event == SubmenuIndexNFCA4) {
nfc->dev->dev_data.nfc_data.uid_len = 4;
nfc->dev->format = NfcDeviceSaveFormatUid;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
return true;
consumed = true;
}
}
return false;
return consumed;
}
void nfc_scene_set_type_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
submenu_reset(nfc->submenu);
}

View File

@ -2,13 +2,13 @@
#include <dolphin/dolphin.h>
void nfc_scene_set_uid_byte_input_callback(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
}
void nfc_scene_set_uid_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Setup view
ByteInput* byte_input = nfc->byte_input;
@ -26,19 +26,20 @@ void nfc_scene_set_uid_on_enter(void* context) {
bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) {
DOLPHIN_DEED(DolphinDeedNfcAdd);
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true;
consumed = true;
}
}
return false;
return consumed;
}
void nfc_scene_set_uid_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Clear view
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);

View File

@ -9,13 +9,13 @@ enum SubmenuIndex {
};
void nfc_scene_start_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_start_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
submenu_add_item(
@ -43,7 +43,7 @@ void nfc_scene_start_on_enter(void* context) {
}
bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
@ -70,7 +70,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
}
void nfc_scene_start_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
submenu_reset(nfc->submenu);
}

View File

@ -48,13 +48,12 @@ void furi_hal_nfc_exit_sleep() {
rfalLowPowerModeStop();
}
bool furi_hal_nfc_detect(
rfalNfcDevice** dev_list,
uint8_t* dev_cnt,
uint32_t timeout,
bool deactivate) {
furi_assert(dev_list);
furi_assert(dev_cnt);
bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) {
furi_assert(nfc_data);
rfalNfcDevice* dev_list = NULL;
uint8_t dev_cnt = 0;
bool detected = false;
rfalLowPowerModeStop();
rfalNfcState state = rfalNfcGetState();
@ -77,9 +76,13 @@ bool furi_hal_nfc_detect(
uint32_t start = DWT->CYCCNT;
rfalNfcDiscover(&params);
while(state != RFAL_NFC_STATE_ACTIVATED) {
while(true) {
rfalNfcWorker();
state = rfalNfcGetState();
if(state == RFAL_NFC_STATE_ACTIVATED) {
detected = true;
break;
}
FURI_LOG_T(TAG, "Current state %d", state);
if(state == RFAL_NFC_STATE_POLL_ACTIVATION) {
start = DWT->CYCCNT;
@ -91,16 +94,42 @@ bool furi_hal_nfc_detect(
if(DWT->CYCCNT - start > timeout * clocks_in_ms) {
rfalNfcDeactivate(true);
FURI_LOG_T(TAG, "Timeout");
return false;
break;
}
osThreadYield();
}
rfalNfcGetDevicesFound(dev_list, dev_cnt);
if(deactivate) {
rfalNfcDeactivate(false);
rfalLowPowerModeStart();
rfalNfcGetDevicesFound(&dev_list, &dev_cnt);
if(detected) {
if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA) {
nfc_data->type = FuriHalNfcTypeA;
nfc_data->atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
nfc_data->atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
nfc_data->sak = dev_list[0].dev.nfca.selRes.sak;
uint8_t* cuid_start = dev_list[0].nfcid;
if(dev_list[0].nfcidLen == 7) {
cuid_start = &dev_list[0].nfcid[3];
}
nfc_data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) |
(cuid_start[3]);
} else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB) {
nfc_data->type = FuriHalNfcTypeB;
} else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCF) {
nfc_data->type = FuriHalNfcTypeF;
} else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCV) {
nfc_data->type = FuriHalNfcTypeV;
}
if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_RF) {
nfc_data->interface = FuriHalNfcInterfaceRf;
} else if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
nfc_data->interface = FuriHalNfcInterfaceIsoDep;
} else if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_NFCDEP) {
nfc_data->interface = FuriHalNfcInterfaceNfcDep;
}
nfc_data->uid_len = dev_list[0].nfcidLen;
memcpy(nfc_data->uid, dev_list[0].nfcid, nfc_data->uid_len);
}
return true;
return detected;
}
bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid) {
@ -326,12 +355,6 @@ bool furi_hal_nfc_emulate_nfca(
return true;
}
bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) {
ReturnCode ret =
rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT);
return ret == ERR_NONE;
}
ReturnCode furi_hal_nfc_data_exchange(
uint8_t* tx_buff,
uint16_t tx_len,
@ -370,6 +393,22 @@ ReturnCode furi_hal_nfc_data_exchange(
return ret;
}
static uint32_t furi_hal_nfc_tx_rx_get_flag(FuriHalNfcTxRxType type) {
uint32_t flags = 0;
if(type == FuriHalNfcTxRxTypeRxNoCrc) {
flags = RFAL_TXRX_FLAGS_CRC_RX_KEEP;
} else if(type == FuriHalNfcTxRxTypeRxKeepPar) {
flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP |
RFAL_TXRX_FLAGS_PAR_RX_KEEP;
} else if(type == FuriHalNfcTxRxTypeRaw) {
flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP |
RFAL_TXRX_FLAGS_PAR_RX_KEEP | RFAL_TXRX_FLAGS_PAR_TX_NONE;
}
return flags;
}
static uint16_t furi_hal_nfc_data_and_parity_to_bitstream(
uint8_t* data,
uint16_t len,
@ -420,8 +459,8 @@ uint16_t furi_hal_nfc_bitstream_to_data_and_parity(
return curr_byte;
}
bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) {
furi_assert(tx_rx_ctx);
bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
furi_assert(tx_rx);
ReturnCode ret;
rfalNfcState state = RFAL_NFC_STATE_ACTIVATED;
@ -431,26 +470,18 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) {
uint16_t* temp_rx_bits = NULL;
// Prepare data for FIFO if necessary
if(tx_rx_ctx->tx_rx_type == FURI_HAL_NFC_TXRX_RAW) {
uint32_t flags = furi_hal_nfc_tx_rx_get_flag(tx_rx->tx_rx_type);
if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) {
temp_tx_bits = furi_hal_nfc_data_and_parity_to_bitstream(
tx_rx_ctx->tx_data, tx_rx_ctx->tx_bits / 8, tx_rx_ctx->tx_parity, temp_tx_buff);
tx_rx->tx_data, tx_rx->tx_bits / 8, tx_rx->tx_parity, temp_tx_buff);
ret = rfalNfcDataExchangeCustomStart(
temp_tx_buff,
temp_tx_bits,
&temp_rx_buff,
&temp_rx_bits,
RFAL_FWT_NONE,
tx_rx_ctx->tx_rx_type);
temp_tx_buff, temp_tx_bits, &temp_rx_buff, &temp_rx_bits, RFAL_FWT_NONE, flags);
} else {
ret = rfalNfcDataExchangeCustomStart(
tx_rx_ctx->tx_data,
tx_rx_ctx->tx_bits,
&temp_rx_buff,
&temp_rx_bits,
RFAL_FWT_NONE,
tx_rx_ctx->tx_rx_type);
tx_rx->tx_data, tx_rx->tx_bits, &temp_rx_buff, &temp_rx_bits, RFAL_FWT_NONE, flags);
}
if(ret != ERR_NONE) {
FURI_LOG_E(TAG, "Failed to start data exchange");
return false;
}
uint32_t start = DWT->CYCCNT;
@ -459,28 +490,64 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) {
state = rfalNfcGetState();
ret = rfalNfcDataExchangeGetStatus();
if(ret == ERR_BUSY) {
if(DWT->CYCCNT - start > 4 * clocks_in_ms) {
if(DWT->CYCCNT - start > timeout_ms * clocks_in_ms) {
FURI_LOG_D(TAG, "Timeout during data exchange");
return false;
}
continue;
} else {
start = DWT->CYCCNT;
}
taskYIELD();
osThreadYield();
}
if(tx_rx_ctx->tx_rx_type == FURI_HAL_NFC_TXRX_RAW) {
tx_rx_ctx->rx_bits =
8 * furi_hal_nfc_bitstream_to_data_and_parity(
temp_rx_buff, *temp_rx_bits, tx_rx_ctx->rx_data, tx_rx_ctx->rx_parity);
if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) {
tx_rx->rx_bits = 8 * furi_hal_nfc_bitstream_to_data_and_parity(
temp_rx_buff, *temp_rx_bits, tx_rx->rx_data, tx_rx->rx_parity);
} else {
memcpy(tx_rx_ctx->rx_data, temp_rx_buff, *temp_rx_bits / 8);
memcpy(tx_rx->rx_data, temp_rx_buff, MIN(*temp_rx_bits / 8, FURI_HAL_NFC_DATA_BUFF_SIZE));
tx_rx->rx_bits = *temp_rx_bits;
}
return true;
}
void furi_hal_nfc_deactivate() {
ReturnCode furi_hal_nfc_exchange_full(
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;
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len_bits, false);
part_len_bytes = *part_len_bits / 8;
if(part_len_bytes > rx_cap) {
return ERR_OVERRUN;
}
memcpy(rx_buff, part_buff, part_len_bytes);
*rx_len = part_len_bytes;
while(err == ERR_NONE && rx_buff[0] == 0xAF) {
err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len_bits, false);
part_len_bytes = *part_len_bits / 8;
if(part_len_bytes > rx_cap - *rx_len) {
return ERR_OVERRUN;
}
if(part_len_bytes == 0) {
return ERR_PROTO;
}
memcpy(rx_buff + *rx_len, part_buff + 1, part_len_bytes - 1);
*rx_buff = *part_buff;
*rx_len += part_len_bytes - 1;
}
return err;
}
void furi_hal_nfc_sleep() {
rfalNfcDeactivate(false);
rfalLowPowerModeStart();
}

View File

@ -15,32 +15,31 @@ extern "C" {
#endif
#define FURI_HAL_NFC_UID_MAX_LEN 10
#define FURI_HAL_NFC_DATA_BUFF_SIZE (64)
#define FURI_HAL_NFC_DATA_BUFF_SIZE (256)
#define FURI_HAL_NFC_PARITY_BUFF_SIZE (FURI_HAL_NFC_DATA_BUFF_SIZE / 8)
#define FURI_HAL_NFC_TXRX_DEFAULT \
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \
(uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \
(uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
#define FURI_HAL_NFC_TX_DEFAULT_RX_NO_CRC \
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
(uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \
(uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
#define FURI_HAL_NFC_TXRX_WITH_PAR \
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
(uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \
(uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
#define FURI_HAL_NFC_TXRX_RAW \
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
(uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE | \
(uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE)
typedef enum {
FuriHalNfcTxRxTypeDefault,
FuriHalNfcTxRxTypeRxNoCrc,
FuriHalNfcTxRxTypeRxKeepPar,
FuriHalNfcTxRxTypeRaw,
} FuriHalNfcTxRxType;
typedef bool (*FuriHalNfcEmulateCallback)(
uint8_t* buff_rx,
@ -50,6 +49,29 @@ typedef bool (*FuriHalNfcEmulateCallback)(
uint32_t* flags,
void* context);
typedef enum {
FuriHalNfcTypeA,
FuriHalNfcTypeB,
FuriHalNfcTypeF,
FuriHalNfcTypeV,
} FuriHalNfcType;
typedef enum {
FuriHalNfcInterfaceRf,
FuriHalNfcInterfaceIsoDep,
FuriHalNfcInterfaceNfcDep,
} FuriHalNfcInterface;
typedef struct {
FuriHalNfcType type;
FuriHalNfcInterface interface;
uint8_t uid_len;
uint8_t uid[10];
uint32_t cuid;
uint8_t atqa[2];
uint8_t sak;
} FuriHalNfcDevData;
typedef struct {
uint8_t tx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
uint8_t tx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
@ -57,7 +79,7 @@ typedef struct {
uint8_t rx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
uint8_t rx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
uint16_t rx_bits;
uint32_t tx_rx_type;
FuriHalNfcTxRxType tx_rx_type;
} FuriHalNfcTxRxContext;
/** Init nfc
@ -95,11 +117,7 @@ void furi_hal_nfc_exit_sleep();
*
* @return true on success
*/
bool furi_hal_nfc_detect(
rfalNfcDevice** dev_list,
uint8_t* dev_cnt,
uint32_t timeout,
bool deactivate);
bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout);
/** Activate NFC-A tag
*
@ -138,15 +156,6 @@ bool furi_hal_nfc_emulate_nfca(
void* context,
uint32_t timeout);
/** Get first command from reader after activation in emulation mode
*
* @param rx_buff pointer to receive buffer
* @param rx_len receive buffer length
*
* @return true on success
*/
bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len);
/** NFC data exchange
*
* @param tx_buff transmit buffer
@ -170,11 +179,28 @@ ReturnCode furi_hal_nfc_data_exchange(
*
* @return true on success
*/
bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx);
bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms);
/** NFC data full exhange
*
* @param tx_buff transmit buffer
* @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
*/
ReturnCode furi_hal_nfc_exchange_full(
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
*/
void furi_hal_nfc_deactivate();
void furi_hal_nfc_sleep();
void furi_hal_nfc_stop();

View File

@ -3015,7 +3015,7 @@ ReturnCode rfalIsoDepGetApduTransceiveStatus(void) {
}
/* Update output param rxLen */
*gIsoDep.APDUParam.rxLen = gIsoDep.APDURxPos;
*gIsoDep.APDUParam.rxLen = gIsoDep.APDURxPos * 8;
/* Wait for following I-Block or APDU TxRx has finished */
return ((ret == ERR_AGAIN) ? ERR_BUSY : ERR_NONE);

View File

@ -725,9 +725,14 @@ ReturnCode rfalNfcDataExchangeCustomStart(
{
/*******************************************************************************/
case RFAL_NFC_INTERFACE_RF:
ctx.rxBuf = gNfcDev.rxBuf.rfBuf, ctx.rxBufLen = sizeof(gNfcDev.rxBuf.rfBuf),
ctx.rxRcvdLen = &gNfcDev.rxLen, ctx.txBuf = txData, ctx.txBufLen = txDataLen,
ctx.flags = flags, ctx.fwt = fwt, *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf;
ctx.rxBuf = gNfcDev.rxBuf.rfBuf;
ctx.rxBufLen = 8 * sizeof(gNfcDev.rxBuf.rfBuf);
ctx.rxRcvdLen = &gNfcDev.rxLen;
ctx.txBuf = txData;
ctx.txBufLen = txDataLen;
ctx.flags = flags;
ctx.fwt = fwt;
*rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf;
*rvdLen = (uint16_t*)&gNfcDev.rxLen;
err = rfalStartTransceive(&ctx);
break;
@ -736,13 +741,14 @@ ReturnCode rfalNfcDataExchangeCustomStart(
/*******************************************************************************/
case RFAL_NFC_INTERFACE_ISODEP: {
rfalIsoDepApduTxRxParam isoDepTxRx;
uint16_t tx_bytes = txDataLen / 8;
if(txDataLen > sizeof(gNfcDev.txBuf.isoDepBuf.apdu)) {
if(tx_bytes > sizeof(gNfcDev.txBuf.isoDepBuf.apdu)) {
return ERR_NOMEM;
}
if(txDataLen > 0U) {
ST_MEMCPY((uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, txDataLen);
if(tx_bytes > 0U) {
ST_MEMCPY((uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, tx_bytes);
}
isoDepTxRx.DID = RFAL_ISODEP_NO_DID;
@ -751,7 +757,7 @@ ReturnCode rfalNfcDataExchangeCustomStart(
isoDepTxRx.dFWT = gNfcDev.activeDev->proto.isoDep.info.dFWT;
isoDepTxRx.FWT = gNfcDev.activeDev->proto.isoDep.info.FWT;
isoDepTxRx.txBuf = &gNfcDev.txBuf.isoDepBuf;
isoDepTxRx.txBufLen = txDataLen;
isoDepTxRx.txBufLen = tx_bytes;
isoDepTxRx.rxBuf = &gNfcDev.rxBuf.isoDepBuf;
isoDepTxRx.rxLen = &gNfcDev.rxLen;
isoDepTxRx.tmpBuf = &gNfcDev.tmpBuf.isoDepBuf;

View File

@ -1,4 +1,8 @@
#include "emv_decoder.h"
#include "emv.h"
#include <furi/common_defines.h>
#define TAG "Emv"
const PDOLValue pdol_term_info = {0x9F59, {0xC8, 0x80, 0x00}}; // Terminal transaction information
const PDOLValue pdol_term_type = {0x9F5A, {0x00}}; // Terminal transaction type
@ -69,19 +73,6 @@ static bool emv_decode_search_tag_u16_r(uint16_t tag, uint8_t* buff, uint16_t* i
return false;
}
uint16_t emv_prepare_select_ppse(uint8_t* dest) {
const uint8_t emv_select_ppse[] = {
0x00, 0xA4, // SELECT ppse
0x04, 0x00, // P1:By name, P2: empty
0x0e, // Lc: Data length
0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, // Data string:
0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, // 2PAY.SYS.DDF01 (PPSE)
0x00 // Le
};
memcpy(dest, emv_select_ppse, sizeof(emv_select_ppse));
return sizeof(emv_select_ppse);
}
bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
uint16_t i = 0;
bool app_aid_found = false;
@ -89,7 +80,7 @@ bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app)
while(i < len) {
if(buff[i] == EMV_TAG_APP_TEMPLATE) {
uint8_t app_len = buff[++i];
for(uint16_t j = i; j < i + app_len; j++) {
for(uint16_t j = i; j < MIN(i + app_len, len - 1); j++) {
if(buff[j] == EMV_TAG_AID) {
app_aid_found = true;
app->aid_len = buff[j + 1];
@ -105,7 +96,59 @@ bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app)
return app_aid_found;
}
uint16_t emv_prepare_select_app(uint8_t* dest, EmvApplication* app) {
bool emv_select_ppse(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
bool app_aid_found = false;
const uint8_t emv_select_ppse_cmd[] = {
0x00, 0xA4, // SELECT ppse
0x04, 0x00, // P1:By name, P2: empty
0x0e, // Lc: Data length
0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, // Data string:
0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, // 2PAY.SYS.DDF01 (PPSE)
0x00 // Le
};
memcpy(tx_rx->tx_data, emv_select_ppse_cmd, sizeof(emv_select_ppse_cmd));
tx_rx->tx_bits = sizeof(emv_select_ppse_cmd) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
FURI_LOG_D(TAG, "Send select PPSE");
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
if(emv_decode_ppse_response(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
app_aid_found = true;
} else {
FURI_LOG_E(TAG, "Failed to parse application");
}
} else {
FURI_LOG_E(TAG, "Failed select PPSE");
}
return app_aid_found;
}
static bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
uint16_t i = 0;
bool decode_success = false;
while(i < len) {
if(buff[i] == EMV_TAG_CARD_NAME) {
uint8_t name_len = buff[i + 1];
emv_parse_TLV((uint8_t*)app->name, buff, &i);
app->name[name_len] = '\0';
app->name_found = true;
decode_success = true;
} else if(((buff[i] << 8) | buff[i + 1]) == EMV_TAG_PDOL) {
i++;
app->pdol.size = emv_parse_TLV(app->pdol.data, buff, &i);
decode_success = true;
}
i++;
}
return decode_success;
}
bool emv_select_app(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
bool select_app_success = false;
const uint8_t emv_select_header[] = {
0x00,
0xA4, // SELECT application
@ -113,33 +156,29 @@ uint16_t emv_prepare_select_app(uint8_t* dest, EmvApplication* app) {
0x00 // P1:By name, P2:First or only occurence
};
uint16_t size = sizeof(emv_select_header);
// Copy header
memcpy(dest, emv_select_header, size);
memcpy(tx_rx->tx_data, emv_select_header, size);
// Copy AID
dest[size++] = app->aid_len;
memcpy(&dest[size], app->aid, app->aid_len);
tx_rx->tx_data[size++] = app->aid_len;
memcpy(&tx_rx->tx_data[size], app->aid, app->aid_len);
size += app->aid_len;
dest[size++] = 0;
return size;
}
tx_rx->tx_data[size++] = 0x00;
tx_rx->tx_bits = size * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
uint16_t i = 0;
bool found_name = false;
while(i < len) {
if(buff[i] == EMV_TAG_CARD_NAME) {
uint8_t name_len = buff[i + 1];
emv_parse_TLV((uint8_t*)app->name, buff, &i);
app->name[name_len] = '\0';
found_name = true;
} else if(((buff[i] << 8) | buff[i + 1]) == EMV_TAG_PDOL) {
i++;
app->pdol.size = emv_parse_TLV(app->pdol.data, buff, &i);
FURI_LOG_D(TAG, "Start application");
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
if(emv_decode_select_app_response(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
select_app_success = true;
} else {
FURI_LOG_E(TAG, "Failed to read PAN or PDOL");
}
i++;
} else {
FURI_LOG_E(TAG, "Failed to start application");
}
return found_name;
return select_app_success;
}
static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) {
@ -175,53 +214,56 @@ static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) {
return dest->size;
}
uint16_t emv_prepare_get_proc_opt(uint8_t* dest, EmvApplication* app) {
// Get processing option header
const uint8_t emv_gpo_header[] = {0x80, 0xA8, 0x00, 0x00};
uint16_t size = sizeof(emv_gpo_header);
// Copy header
memcpy(dest, emv_gpo_header, size);
APDU pdol_data = {0, {0}};
// Prepare and copy pdol parameters
emv_prepare_pdol(&pdol_data, &app->pdol);
dest[size++] = 0x02 + pdol_data.size;
dest[size++] = 0x83;
dest[size++] = pdol_data.size;
memcpy(dest + size, pdol_data.data, pdol_data.size);
size += pdol_data.size;
dest[size++] = 0;
return size;
}
static bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app) {
bool card_num_read = false;
bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app) {
for(uint16_t i = 0; i < len; i++) {
if(buff[i] == EMV_TAG_CARD_NUM) {
app->card_number_len = 8;
memcpy(app->card_number, &buff[i + 2], app->card_number_len);
return true;
card_num_read = true;
} else if(buff[i] == EMV_TAG_AFL) {
app->afl.size = emv_parse_TLV(app->afl.data, buff, &i);
}
}
return false;
return card_num_read;
}
uint16_t emv_prepare_read_sfi_record(uint8_t* dest, uint8_t sfi, uint8_t record_num) {
const uint8_t sfi_param = (sfi << 3) | (1 << 2);
const uint8_t emv_sfi_header[] = {
0x00,
0xB2, // READ RECORD
record_num,
sfi_param, // P1:record_number and P2:SFI
0x00 // Le
};
uint16_t size = sizeof(emv_sfi_header);
memcpy(dest, emv_sfi_header, size);
return size;
static bool emv_get_processing_options(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
bool card_num_read = false;
const uint8_t emv_gpo_header[] = {0x80, 0xA8, 0x00, 0x00};
uint16_t size = sizeof(emv_gpo_header);
// Copy header
memcpy(tx_rx->tx_data, emv_gpo_header, size);
APDU pdol_data = {0, {0}};
// Prepare and copy pdol parameters
emv_prepare_pdol(&pdol_data, &app->pdol);
tx_rx->tx_data[size++] = 0x02 + pdol_data.size;
tx_rx->tx_data[size++] = 0x83;
tx_rx->tx_data[size++] = pdol_data.size;
memcpy(tx_rx->tx_data + size, pdol_data.data, pdol_data.size);
size += pdol_data.size;
tx_rx->tx_data[size++] = 0;
tx_rx->tx_bits = size * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
FURI_LOG_D(TAG, "Get proccessing options");
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
if(emv_decode_get_proc_opt(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
card_num_read = true;
}
} else {
FURI_LOG_E(TAG, "Failed to get processing options");
}
return card_num_read;
}
bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app) {
static bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app) {
bool pan_parsed = false;
for(uint16_t i = 0; i < len; i++) {
if(buff[i] == EMV_TAG_PAN) {
if(buff[i + 1] == 8 || buff[i + 1] == 10) {
@ -240,20 +282,118 @@ bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app
i += 2;
}
}
return pan_parsed;
}
uint16_t emv_select_ppse_ans(uint8_t* buff) {
memcpy(buff, select_ppse_ans, sizeof(select_ppse_ans));
return sizeof(select_ppse_ans);
static bool emv_read_sfi_record(
FuriHalNfcTxRxContext* tx_rx,
EmvApplication* app,
uint8_t sfi,
uint8_t record_num) {
bool card_num_read = false;
uint8_t sfi_param = (sfi << 3) | (1 << 2);
uint8_t emv_sfi_header[] = {
0x00,
0xB2, // READ RECORD
record_num, // P1:record_number
sfi_param, // P2:SFI
0x00 // Le
};
memcpy(tx_rx->tx_data, emv_sfi_header, sizeof(emv_sfi_header));
tx_rx->tx_bits = sizeof(emv_sfi_header) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
if(emv_decode_read_sfi_record(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
card_num_read = true;
}
} else {
FURI_LOG_E(TAG, "Failed to read SFI record %d", record_num);
}
return card_num_read;
}
uint16_t emv_select_app_ans(uint8_t* buff) {
memcpy(buff, select_app_ans, sizeof(select_app_ans));
return sizeof(select_app_ans);
static bool emv_read_files(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
bool card_num_read = false;
if(app->afl.size == 0) {
return false;
}
FURI_LOG_D(TAG, "Search PAN in SFI");
// Iterate through all files
for(size_t i = 0; i < app->afl.size; i += 4) {
uint8_t sfi = app->afl.data[i] >> 3;
uint8_t record_start = app->afl.data[i + 1];
uint8_t record_end = app->afl.data[i + 2];
// Iterate through all records in file
for(uint8_t record = record_start; record <= record_end; ++record) {
card_num_read |= emv_read_sfi_record(tx_rx, app, sfi, record);
}
}
return card_num_read;
}
uint16_t emv_get_proc_opt_ans(uint8_t* buff) {
memcpy(buff, pdol_ans, sizeof(pdol_ans));
return sizeof(pdol_ans);
bool emv_search_application(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) {
furi_assert(tx_rx);
furi_assert(emv_app);
memset(emv_app, 0, sizeof(EmvApplication));
return emv_select_ppse(tx_rx, emv_app);
}
bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) {
furi_assert(tx_rx);
furi_assert(emv_app);
bool card_num_read = false;
memset(emv_app, 0, sizeof(EmvApplication));
do {
if(!emv_select_ppse(tx_rx, emv_app)) break;
if(!emv_select_app(tx_rx, emv_app)) break;
if(emv_get_processing_options(tx_rx, emv_app)) {
card_num_read = true;
} else {
card_num_read = emv_read_files(tx_rx, emv_app);
}
} while(false);
return card_num_read;
}
bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) {
furi_assert(tx_rx);
bool emulation_complete = false;
memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext));
do {
FURI_LOG_D(TAG, "Read select PPSE command");
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
memcpy(tx_rx->tx_data, select_ppse_ans, sizeof(select_ppse_ans));
tx_rx->tx_bits = sizeof(select_ppse_ans) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
FURI_LOG_D(TAG, "Send select PPSE answer and read select App command");
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
memcpy(tx_rx->tx_data, select_app_ans, sizeof(select_app_ans));
tx_rx->tx_bits = sizeof(select_app_ans) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
FURI_LOG_D(TAG, "Send select App answer and read get PDOL command");
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
memcpy(tx_rx->tx_data, pdol_ans, sizeof(pdol_ans));
tx_rx->tx_bits = sizeof(pdol_ans) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
FURI_LOG_D(TAG, "Send get PDOL answer");
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
emulation_complete = true;
} while(false);
return emulation_complete;
}

87
lib/nfc_protocols/emv.h Executable file
View File

@ -0,0 +1,87 @@
#pragma once
#include <furi_hal_nfc.h>
#define MAX_APDU_LEN 255
#define EMV_TAG_APP_TEMPLATE 0x61
#define EMV_TAG_AID 0x4F
#define EMV_TAG_PRIORITY 0x87
#define EMV_TAG_PDOL 0x9F38
#define EMV_TAG_CARD_NAME 0x50
#define EMV_TAG_FCI 0xBF0C
#define EMV_TAG_LOG_CTRL 0x9F4D
#define EMV_TAG_CARD_NUM 0x57
#define EMV_TAG_PAN 0x5A
#define EMV_TAG_AFL 0x94
#define EMV_TAG_EXP_DATE 0x5F24
#define EMV_TAG_COUNTRY_CODE 0x5F28
#define EMV_TAG_CURRENCY_CODE 0x9F42
#define EMV_TAG_CARDHOLDER_NAME 0x5F20
typedef struct {
char name[32];
uint8_t aid[16];
uint16_t aid_len;
uint8_t number[10];
uint8_t number_len;
uint8_t exp_mon;
uint8_t exp_year;
uint16_t country_code;
uint16_t currency_code;
} EmvData;
typedef struct {
uint16_t tag;
uint8_t data[];
} PDOLValue;
typedef struct {
uint8_t size;
uint8_t data[MAX_APDU_LEN];
} APDU;
typedef struct {
uint8_t priority;
uint8_t aid[16];
uint8_t aid_len;
char name[32];
bool name_found;
uint8_t card_number[10];
uint8_t card_number_len;
uint8_t exp_month;
uint8_t exp_year;
uint16_t country_code;
uint16_t currency_code;
APDU pdol;
APDU afl;
} EmvApplication;
/** Read bank card data
* @note Search EMV Application, start it, try to read AID, PAN, card name,
* expiration date, currency and country codes
*
* @param tx_rx FuriHalNfcTxRxContext instance
* @param emv_app EmvApplication instance
*
* @return true on success
*/
bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app);
/** Search for EMV Application
*
* @param tx_rx FuriHalNfcTxRxContext instance
* @param emv_app EmvApplication instance
*
* @return true on success
*/
bool emv_search_application(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app);
/** Emulate bank card
* @note Answer to application selection and PDOL
*
* @param tx_rx FuriHalNfcTxRxContext instance
*
* @return true on success
*/
bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx);

View File

@ -1,67 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define MAX_APDU_LEN 255
#define EMV_TAG_APP_TEMPLATE 0x61
#define EMV_TAG_AID 0x4F
#define EMV_TAG_PRIORITY 0x87
#define EMV_TAG_PDOL 0x9F38
#define EMV_TAG_CARD_NAME 0x50
#define EMV_TAG_FCI 0xBF0C
#define EMV_TAG_LOG_CTRL 0x9F4D
#define EMV_TAG_CARD_NUM 0x57
#define EMV_TAG_PAN 0x5A
#define EMV_TAG_AFL 0x94
#define EMV_TAG_EXP_DATE 0x5F24
#define EMV_TAG_COUNTRY_CODE 0x5F28
#define EMV_TAG_CURRENCY_CODE 0x9F42
#define EMV_TAG_CARDHOLDER_NAME 0x5F20
typedef struct {
uint16_t tag;
uint8_t data[];
} PDOLValue;
extern const PDOLValue* const pdol_values[];
typedef struct {
uint8_t size;
uint8_t data[MAX_APDU_LEN];
} APDU;
typedef struct {
uint8_t priority;
uint8_t aid[16];
uint8_t aid_len;
char name[32];
uint8_t card_number[10];
uint8_t card_number_len;
uint8_t exp_month;
uint8_t exp_year;
uint16_t country_code;
uint16_t currency_code;
APDU pdol;
APDU afl;
} EmvApplication;
/* Terminal emulation */
uint16_t emv_prepare_select_ppse(uint8_t* dest);
bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app);
uint16_t emv_prepare_select_app(uint8_t* dest, EmvApplication* app);
bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app);
uint16_t emv_prepare_get_proc_opt(uint8_t* dest, EmvApplication* app);
bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app);
uint16_t emv_prepare_read_sfi_record(uint8_t* dest, uint8_t sfi, uint8_t record_num);
bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app);
/* Card emulation */
uint16_t emv_select_ppse_ans(uint8_t* buff);
uint16_t emv_select_app_ans(uint8_t* buff);
uint16_t emv_get_proc_opt_ans(uint8_t* buff);

View File

@ -116,17 +116,15 @@ static bool mf_classic_auth(
tx_rx->tx_data[0] = MF_CLASSIC_AUTH_KEY_B_CMD;
}
tx_rx->tx_data[1] = block;
tx_rx->tx_rx_type = FURI_HAL_NFC_TX_DEFAULT_RX_NO_CRC;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRxNoCrc;
tx_rx->tx_bits = 2 * 8;
if(!furi_hal_nfc_tx_rx(tx_rx)) break;
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) break;
uint32_t nt = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4);
crypto1_init(crypto, key);
crypto1_word(crypto, nt ^ cuid, 0);
uint8_t nr[4] = {};
// uint8_t parity = 0;
nfc_util_num2bytes(prng_successor(DWT->CYCCNT, 32), 4, nr);
// uint8_t nr_ar[8] = {};
for(uint8_t i = 0; i < 4; i++) {
tx_rx->tx_data[i] = crypto1_byte(crypto, nr[i], 0) ^ nr[i];
tx_rx->tx_parity[0] |=
@ -140,9 +138,9 @@ static bool mf_classic_auth(
(((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01)
<< (7 - i));
}
tx_rx->tx_rx_type = FURI_HAL_NFC_TXRX_RAW;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw;
tx_rx->tx_bits = 8 * 8;
if(!furi_hal_nfc_tx_rx(tx_rx)) break;
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) break;
if(tx_rx->rx_bits == 32) {
crypto1_word(crypto, 0, 0);
auth_success = true;
@ -178,7 +176,7 @@ bool mf_classic_auth_attempt(
}
if(need_halt) {
furi_hal_nfc_deactivate();
furi_hal_nfc_sleep();
furi_hal_nfc_activate_nfca(300, &auth_ctx->cuid);
}
@ -220,9 +218,9 @@ bool mf_classic_read_block(
((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_cmd[i])) & 0x01) << (7 - i);
}
tx_rx->tx_bits = 4 * 9;
tx_rx->tx_rx_type = FURI_HAL_NFC_TXRX_RAW;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw;
if(furi_hal_nfc_tx_rx(tx_rx)) {
if(furi_hal_nfc_tx_rx(tx_rx, 4)) {
if(tx_rx->rx_bits == 8 * 18) {
for(uint8_t i = 0; i < 18; i++) {
block->value[i] = crypto1_byte(crypto, 0, 0) ^ tx_rx->rx_data[i];
@ -248,7 +246,7 @@ bool mf_classic_read_sector(
uint8_t first_block;
bool sector_read = false;
furi_hal_nfc_deactivate();
furi_hal_nfc_sleep();
do {
// Activate card
if(!furi_hal_nfc_activate_nfca(200, &cuid)) break;

View File

@ -0,0 +1,17 @@
#include "mifare_common.h"
MifareType mifare_common_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
MifareType type = MifareTypeUnknown;
if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
type = MifareTypeUltralight;
} else if(
((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08)) ||
((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18))) {
type = MifareTypeClassic;
} else if(ATQA0 == 0x44 && ATQA1 == 0x03 && SAK == 0x20) {
type = MifareTypeDesfire;
}
return type;
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
typedef enum {
MifareTypeUnknown,
MifareTypeUltralight,
MifareTypeClassic,
MifareTypeDesfire,
} MifareType;
MifareType mifare_common_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);

View File

@ -1,6 +1,7 @@
#include "mifare_ultralight.h"
#include <furi.h>
#include <furi_hal_nfc.h>
#define TAG "MfUltralight"
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
@ -9,187 +10,204 @@ bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
return false;
}
uint16_t mf_ul_prepare_get_version(uint8_t* dest) {
dest[0] = MF_UL_GET_VERSION_CMD;
return 1;
static void mf_ul_set_default_version(MfUltralightReader* reader, MfUltralightData* data) {
data->type = MfUltralightTypeUnknown;
reader->pages_to_read = 16;
reader->support_fast_read = false;
}
void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) {
MfUltralightVersion* version = (MfUltralightVersion*)buff;
memcpy(&mf_ul_read->data.version, version, sizeof(MfUltralightVersion));
if(version->storage_size == 0x0B || version->storage_size == 0x00) {
mf_ul_read->data.type = MfUltralightTypeUL11;
mf_ul_read->pages_to_read = 20;
mf_ul_read->support_fast_read = true;
} else if(version->storage_size == 0x0E) {
mf_ul_read->data.type = MfUltralightTypeUL21;
mf_ul_read->pages_to_read = 41;
mf_ul_read->support_fast_read = true;
} else if(version->storage_size == 0x0F) {
mf_ul_read->data.type = MfUltralightTypeNTAG213;
mf_ul_read->pages_to_read = 45;
mf_ul_read->support_fast_read = false;
} else if(version->storage_size == 0x11) {
mf_ul_read->data.type = MfUltralightTypeNTAG215;
mf_ul_read->pages_to_read = 135;
mf_ul_read->support_fast_read = false;
} else if(version->storage_size == 0x13) {
mf_ul_read->data.type = MfUltralightTypeNTAG216;
mf_ul_read->pages_to_read = 231;
mf_ul_read->support_fast_read = false;
bool mf_ultralight_read_version(
FuriHalNfcTxRxContext* tx_rx,
MfUltralightReader* reader,
MfUltralightData* data) {
bool version_read = false;
do {
FURI_LOG_D(TAG, "Reading version");
tx_rx->tx_data[0] = MF_UL_GET_VERSION_CMD;
tx_rx->tx_bits = 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
FURI_LOG_D(TAG, "Failed reading version");
mf_ul_set_default_version(reader, data);
furi_hal_nfc_sleep();
furi_hal_nfc_activate_nfca(300, NULL);
break;
}
MfUltralightVersion* version = (MfUltralightVersion*)tx_rx->rx_data;
data->version = *version;
if(version->storage_size == 0x0B || version->storage_size == 0x00) {
data->type = MfUltralightTypeUL11;
reader->pages_to_read = 20;
reader->support_fast_read = true;
} else if(version->storage_size == 0x0E) {
data->type = MfUltralightTypeUL21;
reader->pages_to_read = 41;
reader->support_fast_read = true;
} else if(version->storage_size == 0x0F) {
data->type = MfUltralightTypeNTAG213;
reader->pages_to_read = 45;
reader->support_fast_read = false;
} else if(version->storage_size == 0x11) {
data->type = MfUltralightTypeNTAG215;
reader->pages_to_read = 135;
reader->support_fast_read = false;
} else if(version->storage_size == 0x13) {
data->type = MfUltralightTypeNTAG216;
reader->pages_to_read = 231;
reader->support_fast_read = false;
} else {
mf_ul_set_default_version(reader, data);
break;
}
version_read = true;
} while(false);
return version_read;
}
bool mf_ultralight_read_pages(
FuriHalNfcTxRxContext* tx_rx,
MfUltralightReader* reader,
MfUltralightData* data) {
uint8_t pages_read_cnt = 0;
for(size_t i = 0; i < reader->pages_to_read; i += 4) {
FURI_LOG_D(TAG, "Reading pages %d - %d", i, i + 3);
tx_rx->tx_data[0] = MF_UL_READ_CMD;
tx_rx->tx_data[1] = i;
tx_rx->tx_bits = 16;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
FURI_LOG_D(TAG, "Failed to read pages %d - %d", i, i + 3);
break;
}
if(i + 4 <= reader->pages_to_read) {
pages_read_cnt = 4;
} else {
pages_read_cnt = reader->pages_to_read - reader->pages_read;
}
reader->pages_read += pages_read_cnt;
data->data_size = reader->pages_read * 4;
memcpy(&data->data[i * 4], tx_rx->rx_data, pages_read_cnt * 4);
}
return reader->pages_read == reader->pages_to_read;
}
bool mf_ultralight_fast_read_pages(
FuriHalNfcTxRxContext* tx_rx,
MfUltralightReader* reader,
MfUltralightData* data) {
FURI_LOG_D(TAG, "Reading pages 0 - %d", reader->pages_to_read);
tx_rx->tx_data[0] = MF_UL_FAST_READ_CMD;
tx_rx->tx_data[1] = 0;
tx_rx->tx_data[2] = reader->pages_to_read - 1;
tx_rx->tx_bits = 24;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
if(furi_hal_nfc_tx_rx(tx_rx, 20)) {
reader->pages_read = reader->pages_to_read;
data->data_size = reader->pages_read * 4;
memcpy(data->data, tx_rx->rx_data, data->data_size);
} else {
mf_ul_set_default_version(mf_ul_read);
}
}
void mf_ul_set_default_version(MifareUlDevice* mf_ul_read) {
mf_ul_read->data.type = MfUltralightTypeUnknown;
mf_ul_read->pages_to_read = 16;
mf_ul_read->support_fast_read = false;
}
uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page) {
dest[0] = MF_UL_READ_CMD;
dest[1] = start_page;
return 2;
}
void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read) {
uint8_t pages_read = 4;
uint8_t page_read_count = mf_ul_read->pages_read + pages_read;
if(page_read_count > mf_ul_read->pages_to_read) {
pages_read -= page_read_count - mf_ul_read->pages_to_read;
}
mf_ul_read->pages_read += pages_read;
mf_ul_read->data.data_size = mf_ul_read->pages_read * 4;
memcpy(&mf_ul_read->data.data[page_addr * 4], buff, pages_read * 4);
}
uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page) {
dest[0] = MF_UL_FAST_READ_CMD;
dest[1] = start_page;
dest[2] = end_page;
return 3;
}
void mf_ul_parse_fast_read_response(
uint8_t* buff,
uint8_t start_page,
uint8_t end_page,
MifareUlDevice* mf_ul_read) {
mf_ul_read->pages_read = end_page - start_page + 1;
mf_ul_read->data.data_size = mf_ul_read->pages_read * 4;
memcpy(mf_ul_read->data.data, buff, mf_ul_read->data.data_size);
}
uint16_t mf_ul_prepare_read_signature(uint8_t* dest) {
dest[0] = MF_UL_READ_SIG;
dest[1] = 0;
return 2;
}
void mf_ul_parse_read_signature_response(uint8_t* buff, MifareUlDevice* mf_ul_read) {
memcpy(mf_ul_read->data.signature, buff, sizeof(mf_ul_read->data.signature));
}
uint16_t mf_ul_prepare_read_cnt(uint8_t* dest, uint8_t cnt_index) {
if(cnt_index > 2) {
return 0;
}
dest[0] = MF_UL_READ_CNT;
dest[1] = cnt_index;
return 2;
}
void mf_ul_parse_read_cnt_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read) {
// Reverse LSB sequence
if(cnt_index < 3) {
mf_ul_read->data.counter[cnt_index] = (buff[2] << 16) | (buff[1] << 8) | (buff[0]);
}
}
uint16_t mf_ul_prepare_inc_cnt(uint8_t* dest, uint8_t cnt_index, uint32_t value) {
if(cnt_index > 2) {
return 0;
}
dest[0] = MF_UL_INC_CNT;
dest[1] = cnt_index;
dest[2] = (uint8_t)value;
dest[3] = (uint8_t)(value >> 8);
dest[4] = (uint8_t)(value >> 16);
dest[5] = 0;
return 6;
}
uint16_t mf_ul_prepare_check_tearing(uint8_t* dest, uint8_t cnt_index) {
if(cnt_index > 2) {
return 0;
}
dest[0] = MF_UL_CHECK_TEARING;
dest[1] = cnt_index;
return 2;
}
void mf_ul_parse_check_tearing_response(
uint8_t* buff,
uint8_t cnt_index,
MifareUlDevice* mf_ul_read) {
if(cnt_index < 2) {
mf_ul_read->data.tearing[cnt_index] = buff[0];
}
}
uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data) {
if(page_addr < 2) {
return 0;
}
dest[0] = MF_UL_WRITE;
dest[1] = page_addr;
dest[2] = (uint8_t)(data >> 24);
dest[3] = (uint8_t)(data >> 16);
dest[4] = (uint8_t)(data >> 8);
dest[5] = (uint8_t)data;
return 6;
}
void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) {
mf_ul_emulate->data = *data;
mf_ul_emulate->auth_data = NULL;
mf_ul_emulate->data_changed = false;
mf_ul_emulate->comp_write_cmd_started = false;
if(data->version.storage_size == 0) {
mf_ul_emulate->data.type = MfUltralightTypeUnknown;
mf_ul_emulate->support_fast_read = false;
} else if(data->version.storage_size == 0x0B) {
mf_ul_emulate->data.type = MfUltralightTypeUL11;
mf_ul_emulate->support_fast_read = true;
} else if(data->version.storage_size == 0x0E) {
mf_ul_emulate->data.type = MfUltralightTypeUL21;
mf_ul_emulate->support_fast_read = true;
} else if(data->version.storage_size == 0x0F) {
mf_ul_emulate->data.type = MfUltralightTypeNTAG213;
mf_ul_emulate->support_fast_read = true;
} else if(data->version.storage_size == 0x11) {
mf_ul_emulate->data.type = MfUltralightTypeNTAG215;
mf_ul_emulate->support_fast_read = true;
} else if(data->version.storage_size == 0x13) {
mf_ul_emulate->data.type = MfUltralightTypeNTAG216;
mf_ul_emulate->support_fast_read = true;
FURI_LOG_D(TAG, "Failed to read pages 0 - %d", reader->pages_to_read);
}
if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) {
uint16_t pwd_page = (data->data_size / 4) - 2;
mf_ul_emulate->auth_data = (MifareUlAuthData*)&data->data[pwd_page * 4];
}
return reader->pages_read == reader->pages_to_read;
}
void mf_ul_protect_auth_data_on_read_command(
bool mf_ultralight_read_signature(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
bool signature_read = false;
FURI_LOG_D(TAG, "Reading signature");
tx_rx->tx_data[0] = MF_UL_READ_SIG;
tx_rx->tx_data[1] = 0;
tx_rx->tx_bits = 16;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
if(furi_hal_nfc_tx_rx(tx_rx, 7)) {
memcpy(data->signature, tx_rx->rx_data, sizeof(data->signature));
signature_read = true;
} else {
FURI_LOG_D(TAG, "Failed redaing signature");
}
return signature_read;
}
bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
uint8_t counter_read = 0;
FURI_LOG_D(TAG, "Reading counters");
for(size_t i = 0; i < 3; i++) {
tx_rx->tx_data[0] = MF_UL_READ_CNT;
tx_rx->rx_data[1] = i;
tx_rx->tx_bits = 16;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
FURI_LOG_D(TAG, "Failed to read %d counter", i);
break;
}
data->counter[i] = (tx_rx->rx_data[2] << 16) | (tx_rx->rx_data[1] << 8) |
tx_rx->rx_data[0];
counter_read++;
}
return counter_read == 2;
}
bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
uint8_t flag_read = 0;
FURI_LOG_D(TAG, "Reading tearing flags");
for(size_t i = 0; i < 3; i++) {
tx_rx->tx_data[0] = MF_UL_CHECK_TEARING;
tx_rx->rx_data[1] = i;
tx_rx->tx_bits = 16;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
FURI_LOG_D(TAG, "Failed to read %d tearing flag", i);
break;
}
data->tearing[i] = tx_rx->rx_data[0];
flag_read++;
}
return flag_read == 2;
}
bool mf_ul_read_card(
FuriHalNfcTxRxContext* tx_rx,
MfUltralightReader* reader,
MfUltralightData* data) {
furi_assert(tx_rx);
furi_assert(reader);
furi_assert(data);
bool card_read = false;
// Read Mifare Ultralight version
if(mf_ultralight_read_version(tx_rx, reader, data)) {
// Read Signature
mf_ultralight_read_signature(tx_rx, data);
}
// Read data blocks
if(reader->support_fast_read) {
mf_ultralight_read_counters(tx_rx, data);
mf_ultralight_read_tearing_flags(tx_rx, data);
}
card_read = mf_ultralight_read_pages(tx_rx, reader, data);
return card_read;
}
// TODO rework
static void mf_ul_protect_auth_data_on_read_command(
uint8_t* tx_buff,
uint8_t start_page,
uint8_t end_page,
MifareUlDevice* mf_ul_emulate) {
if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) {
uint8_t pwd_page = (mf_ul_emulate->data.data_size / 4) - 2;
MfUltralightEmulator* emulator) {
if(emulator->data.type >= MfUltralightTypeNTAG213) {
uint8_t pwd_page = (emulator->data.data_size / 4) - 2;
uint8_t pack_page = pwd_page + 1;
if((start_page <= pwd_page) && (end_page >= pwd_page)) {
memset(&tx_buff[(pwd_page - start_page) * 4], 0, 4);
@ -200,6 +218,31 @@ void mf_ul_protect_auth_data_on_read_command(
}
}
void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data) {
emulator->data = *data;
emulator->auth_data = NULL;
emulator->data_changed = false;
emulator->comp_write_cmd_started = false;
if(data->type == MfUltralightTypeUnknown) {
emulator->support_fast_read = false;
} else if(data->type == MfUltralightTypeUL11) {
emulator->support_fast_read = true;
} else if(data->type == MfUltralightTypeUL21) {
emulator->support_fast_read = true;
} else if(data->type == MfUltralightTypeNTAG213) {
emulator->support_fast_read = false;
} else if(data->type == MfUltralightTypeNTAG215) {
emulator->support_fast_read = false;
} else if(data->type == MfUltralightTypeNTAG216) {
emulator->support_fast_read = false;
}
if(data->type >= MfUltralightTypeNTAG213) {
uint16_t pwd_page = (data->data_size / 4) - 2;
emulator->auth_data = (MfUltralightAuth*)&data->data[pwd_page * 4];
}
}
bool mf_ul_prepare_emulation_response(
uint8_t* buff_rx,
uint16_t buff_rx_len,
@ -208,30 +251,30 @@ bool mf_ul_prepare_emulation_response(
uint32_t* data_type,
void* context) {
furi_assert(context);
MifareUlDevice* mf_ul_emulate = context;
MfUltralightEmulator* emulator = context;
uint8_t cmd = buff_rx[0];
uint16_t page_num = mf_ul_emulate->data.data_size / 4;
uint16_t page_num = emulator->data.data_size / 4;
uint16_t tx_bytes = 0;
uint16_t tx_bits = 0;
bool command_parsed = false;
// Check composite commands
if(mf_ul_emulate->comp_write_cmd_started) {
if(emulator->comp_write_cmd_started) {
// Compatibility write is the only one composit command
if(buff_rx_len == 16) {
memcpy(&mf_ul_emulate->data.data[mf_ul_emulate->comp_write_page_addr * 4], buff_rx, 4);
mf_ul_emulate->data_changed = true;
memcpy(&emulator->data.data[emulator->comp_write_page_addr * 4], buff_rx, 4);
emulator->data_changed = true;
// Send ACK message
buff_tx[0] = 0x0A;
tx_bits = 4;
*data_type = FURI_HAL_NFC_TXRX_RAW;
command_parsed = true;
}
mf_ul_emulate->comp_write_cmd_started = false;
emulator->comp_write_cmd_started = false;
} else if(cmd == MF_UL_GET_VERSION_CMD) {
if(mf_ul_emulate->data.type != MfUltralightTypeUnknown) {
tx_bytes = sizeof(mf_ul_emulate->data.version);
memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes);
if(emulator->data.type != MfUltralightTypeUnknown) {
tx_bytes = sizeof(emulator->data.version);
memcpy(buff_tx, &emulator->data.version, tx_bytes);
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
command_parsed = true;
}
@ -242,28 +285,24 @@ bool mf_ul_prepare_emulation_response(
if(start_page + 4 > page_num) {
// Handle roll-over mechanism
uint8_t end_pages_num = page_num - start_page;
memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], end_pages_num * 4);
memcpy(
&buff_tx[end_pages_num * 4],
mf_ul_emulate->data.data,
(4 - end_pages_num) * 4);
memcpy(buff_tx, &emulator->data.data[start_page * 4], end_pages_num * 4);
memcpy(&buff_tx[end_pages_num * 4], emulator->data.data, (4 - end_pages_num) * 4);
} else {
memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes);
memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes);
}
mf_ul_protect_auth_data_on_read_command(
buff_tx, start_page, (start_page + 4), mf_ul_emulate);
buff_tx, start_page, (start_page + 4), emulator);
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
command_parsed = true;
}
} else if(cmd == MF_UL_FAST_READ_CMD) {
if(mf_ul_emulate->support_fast_read) {
if(emulator->support_fast_read) {
uint8_t start_page = buff_rx[1];
uint8_t end_page = buff_rx[2];
if((start_page < page_num) && (end_page < page_num) && (start_page < (end_page + 1))) {
tx_bytes = ((end_page + 1) - start_page) * 4;
memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes);
mf_ul_protect_auth_data_on_read_command(
buff_tx, start_page, end_page, mf_ul_emulate);
memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes);
mf_ul_protect_auth_data_on_read_command(buff_tx, start_page, end_page, emulator);
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
command_parsed = true;
}
@ -271,8 +310,8 @@ bool mf_ul_prepare_emulation_response(
} else if(cmd == MF_UL_WRITE) {
uint8_t write_page = buff_rx[1];
if((write_page > 1) && (write_page < page_num - 2)) {
memcpy(&mf_ul_emulate->data.data[write_page * 4], &buff_rx[2], 4);
mf_ul_emulate->data_changed = true;
memcpy(&emulator->data.data[write_page * 4], &buff_rx[2], 4);
emulator->data_changed = true;
// ACK
buff_tx[0] = 0x0A;
tx_bits = 4;
@ -282,8 +321,8 @@ bool mf_ul_prepare_emulation_response(
} else if(cmd == MF_UL_COMP_WRITE) {
uint8_t write_page = buff_rx[1];
if((write_page > 1) && (write_page < page_num - 2)) {
mf_ul_emulate->comp_write_cmd_started = true;
mf_ul_emulate->comp_write_page_addr = write_page;
emulator->comp_write_cmd_started = true;
emulator->comp_write_page_addr = write_page;
// ACK
buff_tx[0] = 0x0A;
tx_bits = 4;
@ -293,9 +332,9 @@ bool mf_ul_prepare_emulation_response(
} else if(cmd == MF_UL_READ_CNT) {
uint8_t cnt_num = buff_rx[1];
if(cnt_num < 3) {
buff_tx[0] = mf_ul_emulate->data.counter[cnt_num] >> 16;
buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8;
buff_tx[2] = mf_ul_emulate->data.counter[cnt_num];
buff_tx[0] = emulator->data.counter[cnt_num] >> 16;
buff_tx[1] = emulator->data.counter[cnt_num] >> 8;
buff_tx[2] = emulator->data.counter[cnt_num];
tx_bytes = 3;
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
command_parsed = true;
@ -303,9 +342,9 @@ bool mf_ul_prepare_emulation_response(
} else if(cmd == MF_UL_INC_CNT) {
uint8_t cnt_num = buff_rx[1];
uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16));
if((cnt_num < 3) && (mf_ul_emulate->data.counter[cnt_num] + inc < 0x00FFFFFF)) {
mf_ul_emulate->data.counter[cnt_num] += inc;
mf_ul_emulate->data_changed = true;
if((cnt_num < 3) && (emulator->data.counter[cnt_num] + inc < 0x00FFFFFF)) {
emulator->data.counter[cnt_num] += inc;
emulator->data_changed = true;
// ACK
buff_tx[0] = 0x0A;
tx_bits = 4;
@ -313,14 +352,14 @@ bool mf_ul_prepare_emulation_response(
command_parsed = true;
}
} else if(cmd == MF_UL_AUTH) {
if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) {
if(memcmp(&buff_rx[1], mf_ul_emulate->auth_data->pwd, 4) == 0) {
buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0];
buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1];
if(emulator->data.type >= MfUltralightTypeNTAG213) {
if(memcmp(&buff_rx[1], emulator->auth_data->pwd, 4) == 0) {
buff_tx[0] = emulator->auth_data->pack.raw[0];
buff_tx[1] = emulator->auth_data->pack.raw[1];
tx_bytes = 2;
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
command_parsed = true;
} else if(!mf_ul_emulate->auth_data->pack.value) {
} else if(!emulator->auth_data->pack.value) {
buff_tx[0] = 0x80;
buff_tx[1] = 0x80;
tx_bytes = 2;
@ -331,15 +370,15 @@ bool mf_ul_prepare_emulation_response(
} else if(cmd == MF_UL_READ_SIG) {
// Check 2nd byte = 0x00 - RFU
if(buff_rx[1] == 0x00) {
tx_bytes = sizeof(mf_ul_emulate->data.signature);
memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes);
tx_bytes = sizeof(emulator->data.signature);
memcpy(buff_tx, emulator->data.signature, tx_bytes);
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
command_parsed = true;
}
} else if(cmd == MF_UL_CHECK_TEARING) {
uint8_t cnt_num = buff_rx[1];
if(cnt_num < 3) {
buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num];
buff_tx[0] = emulator->data.tearing[cnt_num];
tx_bytes = 1;
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
command_parsed = true;

View File

@ -1,8 +1,6 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <furi_hal_nfc.h>
#define MF_UL_MAX_DUMP_SIZE 1024
@ -62,7 +60,7 @@ typedef struct {
uint8_t tearing[3];
uint16_t data_size;
uint8_t data[MF_UL_MAX_DUMP_SIZE];
} MifareUlData;
} MfUltralightData;
typedef struct {
uint8_t pwd[4];
@ -70,52 +68,53 @@ typedef struct {
uint8_t raw[2];
uint16_t value;
} pack;
} MifareUlAuthData;
} MfUltralightAuth;
typedef struct {
uint8_t pages_to_read;
uint8_t pages_read;
bool support_fast_read;
} MfUltralightReader;
typedef struct {
MfUltralightData data;
bool support_fast_read;
bool data_changed;
MifareUlData data;
MifareUlAuthData* auth_data;
bool comp_write_cmd_started;
uint8_t comp_write_page_addr;
} MifareUlDevice;
MfUltralightAuth* auth_data;
} MfUltralightEmulator;
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
uint16_t mf_ul_prepare_get_version(uint8_t* dest);
void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read);
void mf_ul_set_default_version(MifareUlDevice* mf_ul_read);
bool mf_ultralight_read_version(
FuriHalNfcTxRxContext* tx_rx,
MfUltralightReader* reader,
MfUltralightData* data);
uint16_t mf_ul_prepare_read_signature(uint8_t* dest);
void mf_ul_parse_read_signature_response(uint8_t* buff, MifareUlDevice* mf_ul_read);
bool mf_ultralight_read_pages(
FuriHalNfcTxRxContext* tx_rx,
MfUltralightReader* reader,
MfUltralightData* data);
uint16_t mf_ul_prepare_read_cnt(uint8_t* dest, uint8_t cnt_index);
void mf_ul_parse_read_cnt_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read);
bool mf_ultralight_fast_read_pages(
FuriHalNfcTxRxContext* tx_rx,
MfUltralightReader* reader,
MfUltralightData* data);
uint16_t mf_ul_prepare_inc_cnt(uint8_t* dest, uint8_t cnt_index, uint32_t value);
bool mf_ultralight_read_signature(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data);
uint16_t mf_ul_prepare_check_tearing(uint8_t* dest, uint8_t cnt_index);
void mf_ul_parse_check_tearing_response(
uint8_t* buff,
uint8_t cnt_index,
MifareUlDevice* mf_ul_read);
bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data);
uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page);
void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read);
bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data);
uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page);
void mf_ul_parse_fast_read_response(
uint8_t* buff,
uint8_t start_page,
uint8_t end_page,
MifareUlDevice* mf_ul_read);
bool mf_ul_read_card(
FuriHalNfcTxRxContext* tx_rx,
MfUltralightReader* reader,
MfUltralightData* data);
uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data);
void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data);
void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data);
bool mf_ul_prepare_emulation_response(
uint8_t* buff_rx,
uint16_t buff_rx_len,