[FL-2369] NFC refactoring (#1095)
* 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:
parent
e55d1572da
commit
956788c09b
applications/nfc
nfc.cnfc_cli.cnfc_device.cnfc_device.hnfc_i.hnfc_types.cnfc_types.hnfc_worker.cnfc_worker.hnfc_worker_i.h
scenes
nfc_scene_card_menu.cnfc_scene_config.hnfc_scene_debug.cnfc_scene_delete.cnfc_scene_delete_success.cnfc_scene_device_info.cnfc_scene_emulate_apdu_sequence.cnfc_scene_emulate_mifare_ul.cnfc_scene_emulate_uid.cnfc_scene_field.cnfc_scene_file_select.cnfc_scene_mifare_desfire_app.cnfc_scene_mifare_desfire_data.cnfc_scene_mifare_desfire_menu.cnfc_scene_mifare_ul_menu.cnfc_scene_not_implemented.cnfc_scene_read_card.cnfc_scene_read_card_success.cnfc_scene_read_emv_app.cnfc_scene_read_emv_app_success.cnfc_scene_read_emv_data.cnfc_scene_read_emv_data_success.cnfc_scene_read_mifare_desfire.cnfc_scene_read_mifare_desfire_success.cnfc_scene_read_mifare_ul.cnfc_scene_read_mifare_ul_success.cnfc_scene_restore_original.cnfc_scene_run_emv_app_confirm.cnfc_scene_save_name.cnfc_scene_save_success.cnfc_scene_saved_menu.cnfc_scene_set_atqa.cnfc_scene_set_sak.cnfc_scene_set_type.cnfc_scene_set_uid.cnfc_scene_start.c
firmware/targets
lib
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ typedef enum {
|
||||
NfcWorkerStateDetect,
|
||||
NfcWorkerStateEmulate,
|
||||
NfcWorkerStateReadEMVApp,
|
||||
NfcWorkerStateReadEMV,
|
||||
NfcWorkerStateReadEMVData,
|
||||
NfcWorkerStateEmulateApdu,
|
||||
NfcWorkerStateField,
|
||||
NfcWorkerStateReadMifareUl,
|
||||
NfcWorkerStateEmulateMifareUl,
|
||||
NfcWorkerStateReadMifareUltralight,
|
||||
NfcWorkerStateEmulateMifareUltralight,
|
||||
NfcWorkerStateReadMifareClassic,
|
||||
NfcWorkerStateReadMifareDesfire,
|
||||
// Transition
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(¶ms);
|
||||
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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
87
lib/nfc_protocols/emv.h
Executable 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);
|
@ -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);
|
@ -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;
|
||||
|
17
lib/nfc_protocols/mifare_common.c
Normal file
17
lib/nfc_protocols/mifare_common.c
Normal 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;
|
||||
}
|
12
lib/nfc_protocols/mifare_common.h
Normal file
12
lib/nfc_protocols/mifare_common.h
Normal 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);
|
@ -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;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user