[FL-2605] NFC new design (#1364)
* nfc: add new read scene * lib: refactore nfc library * mifare desfire: add read card fuction * lib nfc: add auto read worker * nfc: add supported cards * nfc: add mifare classic read success scene * nfc: add troyka support * submodule: update protobuf * nfc: mifare classic keys cache * nfc: rework mifare classic key cache * Correct spelling * nfc: add user dictionary * nfc: introduce block read map in fff * nfc: rework dict attack * nfc: improve dict attack * nfc: rework mifare classic format * nfc: rework MFC read with Reader * nfc: add gui for MFC read success scene * nfc: fix dict attack view gui * nfc: add retry and exit confirm scenes * nfc: add retry and exit scenes navigation * nfc: check user dictionary * nfc: remove unused scenes * nfc: rename functions in nfc worker * nfc: rename mf_classic_dict_attack -> dict_attack * nfc: change scenes names * nfc: remove scene tick events * nfc: rework dict calls with buffer streams * nfc: fix notifications * nfc: fix mf desfire navigation * nfc: remove notification from mf classic read success * nfc: fix read sectors calculation * nfc: add fallback for unknown card * nfc: show file name while emulating * nfc: fix build * nfc: fix memory leak * nfc: fix desfire read * nfc: add no dict found navigation * nfc: add read views * nfc: update card fix * nfc: fix access bytes save * nfc: add exit and retry confirm to mf ultralight read success * nfc: introduce detect reader * nfc: change record open arg to macros * nfc: fix start from archive Co-authored-by: Astra <astra@astrra.space> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -9,5 +9,6 @@ enum NfcCustomEvent {
|
||||
NfcCustomEventByteInputDone,
|
||||
NfcCustomEventTextInputDone,
|
||||
NfcCustomEventDictAttackDone,
|
||||
NfcCustomEventDictAttackSkip,
|
||||
NfcCustomEventRpcLoad,
|
||||
};
|
||||
|
@@ -1,166 +0,0 @@
|
||||
#include "nfc_debug_pcap.h"
|
||||
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <stream_buffer.h>
|
||||
|
||||
#define TAG "NfcDebugPcap"
|
||||
|
||||
#define PCAP_MAGIC 0xa1b2c3d4
|
||||
#define PCAP_MAJOR 2
|
||||
#define PCAP_MINOR 4
|
||||
#define DLT_ISO_14443 264
|
||||
|
||||
#define DATA_PICC_TO_PCD 0xFF
|
||||
#define DATA_PCD_TO_PICC 0xFE
|
||||
#define DATA_PICC_TO_PCD_CRC_DROPPED 0xFB
|
||||
#define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA
|
||||
|
||||
#define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.pcap")
|
||||
#define NFC_DEBUG_PCAP_BUFFER_SIZE 64
|
||||
|
||||
struct NfcDebugPcapWorker {
|
||||
bool alive;
|
||||
Storage* storage;
|
||||
File* file;
|
||||
StreamBufferHandle_t stream;
|
||||
FuriThread* thread;
|
||||
};
|
||||
|
||||
static File* nfc_debug_pcap_open(Storage* storage) {
|
||||
File* file = storage_file_alloc(storage);
|
||||
if(!storage_file_open(file, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) {
|
||||
storage_file_free(file);
|
||||
return NULL;
|
||||
}
|
||||
if(!storage_file_tell(file)) {
|
||||
struct {
|
||||
uint32_t magic;
|
||||
uint16_t major, minor;
|
||||
uint32_t reserved[2];
|
||||
uint32_t snaplen;
|
||||
uint32_t link_type;
|
||||
} __attribute__((__packed__)) pcap_hdr = {
|
||||
.magic = PCAP_MAGIC,
|
||||
.major = PCAP_MAJOR,
|
||||
.minor = PCAP_MINOR,
|
||||
.snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE,
|
||||
.link_type = DLT_ISO_14443,
|
||||
};
|
||||
if(storage_file_write(file, &pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) {
|
||||
FURI_LOG_E(TAG, "Failed to write pcap header");
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
static void
|
||||
nfc_debug_pcap_write(NfcDebugPcapWorker* instance, uint8_t event, uint8_t* data, uint16_t len) {
|
||||
FuriHalRtcDateTime datetime;
|
||||
furi_hal_rtc_get_datetime(&datetime);
|
||||
|
||||
struct {
|
||||
// https://wiki.wireshark.org/Development/LibpcapFileFormat#record-packet-header
|
||||
uint32_t ts_sec;
|
||||
uint32_t ts_usec;
|
||||
uint32_t incl_len;
|
||||
uint32_t orig_len;
|
||||
// https://www.kaiser.cx/posts/pcap-iso14443/#_packet_data
|
||||
uint8_t version;
|
||||
uint8_t event;
|
||||
uint16_t len;
|
||||
} __attribute__((__packed__)) pkt_hdr = {
|
||||
.ts_sec = furi_hal_rtc_datetime_to_timestamp(&datetime),
|
||||
.ts_usec = 0,
|
||||
.incl_len = len + 4,
|
||||
.orig_len = len + 4,
|
||||
.version = 0,
|
||||
.event = event,
|
||||
.len = len << 8 | len >> 8,
|
||||
};
|
||||
xStreamBufferSend(instance->stream, &pkt_hdr, sizeof(pkt_hdr), FuriWaitForever);
|
||||
xStreamBufferSend(instance->stream, data, len, FuriWaitForever);
|
||||
}
|
||||
|
||||
static void
|
||||
nfc_debug_pcap_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
|
||||
NfcDebugPcapWorker* instance = context;
|
||||
uint8_t event = crc_dropped ? DATA_PCD_TO_PICC_CRC_DROPPED : DATA_PCD_TO_PICC;
|
||||
nfc_debug_pcap_write(instance, event, data, bits / 8);
|
||||
}
|
||||
|
||||
static void
|
||||
nfc_debug_pcap_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
|
||||
NfcDebugPcapWorker* instance = context;
|
||||
uint8_t event = crc_dropped ? DATA_PICC_TO_PCD_CRC_DROPPED : DATA_PICC_TO_PCD;
|
||||
nfc_debug_pcap_write(instance, event, data, bits / 8);
|
||||
}
|
||||
|
||||
int32_t nfc_debug_pcap_thread(void* context) {
|
||||
NfcDebugPcapWorker* instance = context;
|
||||
uint8_t buffer[NFC_DEBUG_PCAP_BUFFER_SIZE];
|
||||
|
||||
while(instance->alive) {
|
||||
size_t ret =
|
||||
xStreamBufferReceive(instance->stream, buffer, NFC_DEBUG_PCAP_BUFFER_SIZE, 50);
|
||||
if(storage_file_write(instance->file, buffer, ret) != ret) {
|
||||
FURI_LOG_E(TAG, "Failed to write pcap data");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NfcDebugPcapWorker* nfc_debug_pcap_alloc(Storage* storage) {
|
||||
NfcDebugPcapWorker* instance = malloc(sizeof(NfcDebugPcapWorker));
|
||||
|
||||
instance->alive = true;
|
||||
|
||||
instance->storage = storage;
|
||||
|
||||
instance->file = nfc_debug_pcap_open(storage);
|
||||
|
||||
instance->stream = xStreamBufferCreate(4096, 1);
|
||||
|
||||
instance->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(instance->thread, "PcapWorker");
|
||||
furi_thread_set_stack_size(instance->thread, 1024);
|
||||
furi_thread_set_callback(instance->thread, nfc_debug_pcap_thread);
|
||||
furi_thread_set_context(instance->thread, instance);
|
||||
furi_thread_start(instance->thread);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void nfc_debug_pcap_free(NfcDebugPcapWorker* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->alive = false;
|
||||
|
||||
furi_thread_join(instance->thread);
|
||||
furi_thread_free(instance->thread);
|
||||
|
||||
vStreamBufferDelete(instance->stream);
|
||||
|
||||
if(instance->file) storage_file_free(instance->file);
|
||||
|
||||
instance->storage = NULL;
|
||||
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void nfc_debug_pcap_prepare_tx_rx(
|
||||
NfcDebugPcapWorker* instance,
|
||||
FuriHalNfcTxRxContext* tx_rx,
|
||||
bool is_picc) {
|
||||
if(!instance || !instance->file) return;
|
||||
|
||||
if(is_picc) {
|
||||
tx_rx->sniff_tx = nfc_debug_pcap_write_rx;
|
||||
tx_rx->sniff_rx = nfc_debug_pcap_write_tx;
|
||||
} else {
|
||||
tx_rx->sniff_tx = nfc_debug_pcap_write_tx;
|
||||
tx_rx->sniff_rx = nfc_debug_pcap_write_rx;
|
||||
}
|
||||
|
||||
tx_rx->sniff_context = instance;
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal_nfc.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
typedef struct NfcDebugPcapWorker NfcDebugPcapWorker;
|
||||
|
||||
NfcDebugPcapWorker* nfc_debug_pcap_alloc(Storage* storage);
|
||||
|
||||
void nfc_debug_pcap_free(NfcDebugPcapWorker* instance);
|
||||
|
||||
/** Prepare tx/rx context for debug pcap logging, if enabled.
|
||||
*
|
||||
* @param instance NfcDebugPcapWorker* instance, can be NULL
|
||||
* @param tx_rx TX/RX context to log
|
||||
* @param is_picc if true, record Flipper as PICC, else PCD.
|
||||
*/
|
||||
void nfc_debug_pcap_prepare_tx_rx(
|
||||
NfcDebugPcapWorker* instance,
|
||||
FuriHalNfcTxRxContext* tx_rx,
|
||||
bool is_picc);
|
@@ -267,67 +267,67 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) {
|
||||
static const NfcGenerator mf_ul_generator = {
|
||||
.name = "Mifare Ultralight",
|
||||
.generator_func = nfc_generate_mf_ul_orig,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator mf_ul_11_generator = {
|
||||
.name = "Mifare Ultralight EV1 11",
|
||||
.generator_func = nfc_generate_mf_ul_11,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator mf_ul_h11_generator = {
|
||||
.name = "Mifare Ultralight EV1 H11",
|
||||
.generator_func = nfc_generate_mf_ul_h11,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator mf_ul_21_generator = {
|
||||
.name = "Mifare Ultralight EV1 21",
|
||||
.generator_func = nfc_generate_mf_ul_21,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator mf_ul_h21_generator = {
|
||||
.name = "Mifare Ultralight EV1 H21",
|
||||
.generator_func = nfc_generate_mf_ul_h21,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator ntag203_generator = {
|
||||
.name = "NTAG203",
|
||||
.generator_func = nfc_generate_mf_ul_ntag203,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator ntag213_generator = {
|
||||
.name = "NTAG213",
|
||||
.generator_func = nfc_generate_ntag213,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator ntag215_generator = {
|
||||
.name = "NTAG215",
|
||||
.generator_func = nfc_generate_ntag215,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator ntag216_generator = {
|
||||
.name = "NTAG216",
|
||||
.generator_func = nfc_generate_ntag216,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator ntag_i2c_1k_generator = {
|
||||
.name = "NTAG I2C 1k",
|
||||
.generator_func = nfc_generate_ntag_i2c_1k,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator ntag_i2c_2k_generator = {
|
||||
.name = "NTAG I2C 2k",
|
||||
.generator_func = nfc_generate_ntag_i2c_2k,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator ntag_i2c_plus_1k_generator = {
|
||||
.name = "NTAG I2C Plus 1k",
|
||||
.generator_func = nfc_generate_ntag_i2c_plus_1k,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
static const NfcGenerator ntag_i2c_plus_2k_generator = {
|
||||
.name = "NTAG I2C Plus 2k",
|
||||
.generator_func = nfc_generate_ntag_i2c_plus_2k,
|
||||
.next_scene = NfcSceneMifareUlMenu};
|
||||
.next_scene = NfcSceneMfUltralightMenu};
|
||||
|
||||
const NfcGenerator* const nfc_generators[] = {
|
||||
&mf_ul_generator,
|
||||
|
@@ -1,53 +0,0 @@
|
||||
#include "nfc_mf_classic_dict.h"
|
||||
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
|
||||
#define NFC_MF_CLASSIC_DICT_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc")
|
||||
|
||||
#define NFC_MF_CLASSIC_KEY_LEN (13)
|
||||
|
||||
bool nfc_mf_classic_dict_check_presence(Storage* storage) {
|
||||
furi_assert(storage);
|
||||
return storage_common_stat(storage, NFC_MF_CLASSIC_DICT_PATH, NULL) == FSE_OK;
|
||||
}
|
||||
|
||||
bool nfc_mf_classic_dict_open_file(Stream* stream) {
|
||||
furi_assert(stream);
|
||||
return file_stream_open(stream, NFC_MF_CLASSIC_DICT_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
}
|
||||
|
||||
void nfc_mf_classic_dict_close_file(Stream* stream) {
|
||||
furi_assert(stream);
|
||||
file_stream_close(stream);
|
||||
}
|
||||
|
||||
bool nfc_mf_classic_dict_get_next_key(Stream* stream, uint64_t* key) {
|
||||
furi_assert(stream);
|
||||
furi_assert(key);
|
||||
uint8_t key_byte_tmp = 0;
|
||||
string_t next_line;
|
||||
string_init(next_line);
|
||||
*key = 0;
|
||||
|
||||
bool next_key_read = false;
|
||||
while(!next_key_read) {
|
||||
if(!stream_read_line(stream, next_line)) break;
|
||||
if(string_get_char(next_line, 0) == '#') continue;
|
||||
if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
|
||||
for(uint8_t i = 0; i < 12; i += 2) {
|
||||
args_char_to_hex(
|
||||
string_get_char(next_line, i), string_get_char(next_line, i + 1), &key_byte_tmp);
|
||||
*key |= (uint64_t)key_byte_tmp << 8 * (5 - i / 2);
|
||||
}
|
||||
next_key_read = true;
|
||||
}
|
||||
|
||||
string_clear(next_line);
|
||||
return next_key_read;
|
||||
}
|
||||
|
||||
void nfc_mf_classic_dict_reset(Stream* stream) {
|
||||
furi_assert(stream);
|
||||
stream_rewind(stream);
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <storage/storage.h>
|
||||
#include <lib/toolbox/stream/file_stream.h>
|
||||
|
||||
bool nfc_mf_classic_dict_check_presence(Storage* storage);
|
||||
|
||||
bool nfc_mf_classic_dict_open_file(Stream* stream);
|
||||
|
||||
void nfc_mf_classic_dict_close_file(Stream* stream);
|
||||
|
||||
bool nfc_mf_classic_dict_get_next_key(Stream* stream, uint64_t* key);
|
||||
|
||||
void nfc_mf_classic_dict_reset(Stream* stream);
|
@@ -13,12 +13,6 @@ bool nfc_back_event_callback(void* context) {
|
||||
return scene_manager_handle_back_event(nfc->scene_manager);
|
||||
}
|
||||
|
||||
void nfc_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
scene_manager_handle_tick_event(nfc->scene_manager);
|
||||
}
|
||||
|
||||
void nfc_rpc_exit_callback(Nfc* nfc) {
|
||||
if(nfc->rpc_state == NfcRpcStateEmulating) {
|
||||
// Stop worker
|
||||
@@ -36,11 +30,12 @@ void nfc_rpc_exit_callback(Nfc* nfc) {
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_rpc_emulate_callback(NfcWorkerEvent event, void* context) {
|
||||
static bool nfc_rpc_emulate_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
Nfc* nfc = context;
|
||||
|
||||
nfc->rpc_state = NfcRpcStateEmulated;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) {
|
||||
@@ -67,20 +62,20 @@ static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, v
|
||||
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateEmulateMifareUltralight,
|
||||
NfcWorkerStateMfUltralightEmulate,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_rpc_emulate_callback,
|
||||
nfc);
|
||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateEmulateMifareClassic,
|
||||
NfcWorkerStateMfClassicEmulate,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_rpc_emulate_callback,
|
||||
nfc);
|
||||
} else {
|
||||
nfc_worker_start(
|
||||
nfc->worker, NfcWorkerStateEmulate, &nfc->dev->dev_data, NULL, nfc);
|
||||
nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc);
|
||||
}
|
||||
nfc->rpc_state = NfcRpcStateEmulating;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad);
|
||||
@@ -102,7 +97,6 @@ Nfc* nfc_alloc() {
|
||||
view_dispatcher_set_event_callback_context(nfc->view_dispatcher, nfc);
|
||||
view_dispatcher_set_custom_event_callback(nfc->view_dispatcher, nfc_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(nfc->view_dispatcher, nfc_tick_event_callback, 100);
|
||||
|
||||
// Nfc device
|
||||
nfc->dev = nfc_device_alloc();
|
||||
@@ -155,7 +149,7 @@ Nfc* nfc_alloc() {
|
||||
view_dispatcher_add_view(
|
||||
nfc->view_dispatcher, NfcViewBankCard, bank_card_get_view(nfc->bank_card));
|
||||
|
||||
// Dict Attack
|
||||
// Mifare Classic Dict Attack
|
||||
nfc->dict_attack = dict_attack_alloc();
|
||||
view_dispatcher_add_view(
|
||||
nfc->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(nfc->dict_attack));
|
||||
@@ -209,7 +203,7 @@ void nfc_free(Nfc* nfc) {
|
||||
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard);
|
||||
bank_card_free(nfc->bank_card);
|
||||
|
||||
// Dict Attack
|
||||
// Mifare Classic Dict Attack
|
||||
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack);
|
||||
dict_attack_free(nfc->dict_attack);
|
||||
|
||||
@@ -301,9 +295,9 @@ int32_t nfc_app(void* p) {
|
||||
nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen);
|
||||
if(nfc_device_load(nfc->dev, p, true)) {
|
||||
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||
}
|
||||
|
@@ -1,9 +1,10 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <cli/cli.h>
|
||||
#include <toolbox/args.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
|
||||
#include "nfc_types.h"
|
||||
#include <lib/nfc/nfc_types.h>
|
||||
#include <lib/nfc/nfc_device.h>
|
||||
|
||||
static void nfc_cli_print_usage() {
|
||||
printf("Usage:\r\n");
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,91 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#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>
|
||||
|
||||
#define NFC_DEV_NAME_MAX_LEN 22
|
||||
#define NFC_READER_DATA_MAX_SIZE 64
|
||||
|
||||
#define NFC_APP_FOLDER ANY_PATH("nfc")
|
||||
#define NFC_APP_EXTENSION ".nfc"
|
||||
#define NFC_APP_SHADOW_EXTENSION ".shd"
|
||||
|
||||
typedef void (*NfcLoadingCallback)(void* context, bool state);
|
||||
|
||||
typedef enum {
|
||||
NfcDeviceProtocolUnknown,
|
||||
NfcDeviceProtocolEMV,
|
||||
NfcDeviceProtocolMifareUl,
|
||||
NfcDeviceProtocolMifareClassic,
|
||||
NfcDeviceProtocolMifareDesfire,
|
||||
} NfcProtocol;
|
||||
|
||||
typedef enum {
|
||||
NfcDeviceSaveFormatUid,
|
||||
NfcDeviceSaveFormatBankCard,
|
||||
NfcDeviceSaveFormatMifareUl,
|
||||
NfcDeviceSaveFormatMifareClassic,
|
||||
NfcDeviceSaveFormatMifareDesfire,
|
||||
} NfcDeviceSaveFormat;
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[NFC_READER_DATA_MAX_SIZE];
|
||||
uint16_t size;
|
||||
} NfcReaderRequestData;
|
||||
|
||||
typedef struct {
|
||||
FuriHalNfcDevData nfc_data;
|
||||
NfcProtocol protocol;
|
||||
NfcReaderRequestData reader_data;
|
||||
union {
|
||||
EmvData emv_data;
|
||||
MfUltralightData mf_ul_data;
|
||||
MfClassicData mf_classic_data;
|
||||
MifareDesfireData mf_df_data;
|
||||
};
|
||||
} NfcDeviceData;
|
||||
|
||||
typedef struct {
|
||||
Storage* storage;
|
||||
DialogsApp* dialogs;
|
||||
NfcDeviceData dev_data;
|
||||
char dev_name[NFC_DEV_NAME_MAX_LEN + 1];
|
||||
string_t load_path;
|
||||
NfcDeviceSaveFormat format;
|
||||
bool shadow_file_exist;
|
||||
|
||||
NfcLoadingCallback loading_cb;
|
||||
void* loading_cb_ctx;
|
||||
} NfcDevice;
|
||||
|
||||
NfcDevice* nfc_device_alloc();
|
||||
|
||||
void nfc_device_free(NfcDevice* nfc_dev);
|
||||
|
||||
void nfc_device_set_name(NfcDevice* dev, const char* name);
|
||||
|
||||
bool nfc_device_save(NfcDevice* dev, const char* dev_name);
|
||||
|
||||
bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name);
|
||||
|
||||
bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog);
|
||||
|
||||
bool nfc_file_select(NfcDevice* dev);
|
||||
|
||||
void nfc_device_data_clear(NfcDeviceData* dev);
|
||||
|
||||
void nfc_device_clear(NfcDevice* dev);
|
||||
|
||||
bool nfc_device_delete(NfcDevice* dev, bool use_load_path);
|
||||
|
||||
bool nfc_device_restore(NfcDevice* dev, bool use_load_path);
|
||||
|
||||
void nfc_device_set_loading_callback(NfcDevice* dev, NfcLoadingCallback callback, void* context);
|
@@ -1,9 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "nfc.h"
|
||||
#include "nfc_types.h"
|
||||
#include "nfc_worker.h"
|
||||
#include "nfc_device.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
@@ -24,6 +21,11 @@
|
||||
#include <gui/modules/text_box.h>
|
||||
#include <gui/modules/widget.h>
|
||||
|
||||
#include <lib/nfc/nfc_types.h>
|
||||
#include <lib/nfc/nfc_worker.h>
|
||||
#include <lib/nfc/nfc_device.h>
|
||||
#include <lib/nfc/helpers/mf_classic_dict.h>
|
||||
|
||||
#include "views/bank_card.h"
|
||||
#include "views/dict_attack.h"
|
||||
|
||||
@@ -32,8 +34,6 @@
|
||||
|
||||
#include "rpc/rpc_app.h"
|
||||
|
||||
#define NFC_SEND_NOTIFICATION_FALSE (0UL)
|
||||
#define NFC_SEND_NOTIFICATION_TRUE (1UL)
|
||||
#define NFC_TEXT_STORE_SIZE 128
|
||||
|
||||
typedef enum {
|
||||
@@ -56,6 +56,7 @@ struct Nfc {
|
||||
|
||||
char text_store[NFC_TEXT_STORE_SIZE + 1];
|
||||
string_t text_box_store;
|
||||
uint8_t byte_input_store[6];
|
||||
|
||||
void* rpc_ctx;
|
||||
NfcRpcState rpc_state;
|
||||
|
@@ -1,65 +0,0 @@
|
||||
#include "nfc_types.h"
|
||||
|
||||
const char* nfc_get_dev_type(FuriHalNfcType type) {
|
||||
if(type == FuriHalNfcTypeA) {
|
||||
return "NFC-A";
|
||||
} else if(type == FuriHalNfcTypeB) {
|
||||
return "NFC-B";
|
||||
} else if(type == FuriHalNfcTypeF) {
|
||||
return "NFC-F";
|
||||
} else if(type == FuriHalNfcTypeV) {
|
||||
return "NFC-V";
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char* nfc_guess_protocol(NfcProtocol protocol) {
|
||||
if(protocol == NfcDeviceProtocolEMV) {
|
||||
return "EMV bank card";
|
||||
} else if(protocol == NfcDeviceProtocolMifareUl) {
|
||||
return "Mifare Ultral/NTAG";
|
||||
} else if(protocol == NfcDeviceProtocolMifareClassic) {
|
||||
return "Mifare Classic";
|
||||
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
|
||||
return "Mifare DESFire";
|
||||
} else {
|
||||
return "Unrecognized";
|
||||
}
|
||||
}
|
||||
|
||||
const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) {
|
||||
if(type == MfUltralightTypeNTAG213) {
|
||||
return "NTAG213";
|
||||
} else if(type == MfUltralightTypeNTAG215) {
|
||||
return "NTAG215";
|
||||
} else if(type == MfUltralightTypeNTAG216) {
|
||||
return "NTAG216";
|
||||
} else if(type == MfUltralightTypeNTAGI2C1K) {
|
||||
return "NTAG I2C 1K";
|
||||
} else if(type == MfUltralightTypeNTAGI2C2K) {
|
||||
return "NTAG I2C 2K";
|
||||
} else if(type == MfUltralightTypeNTAGI2CPlus1K) {
|
||||
return "NTAG I2C Plus 1K";
|
||||
} else if(type == MfUltralightTypeNTAGI2CPlus2K) {
|
||||
return "NTAG I2C Plus 2K";
|
||||
} else if(type == MfUltralightTypeNTAG203) {
|
||||
return "NTAG203";
|
||||
} else if(type == MfUltralightTypeUL11 && full_name) {
|
||||
return "Mifare Ultralight 11";
|
||||
} else if(type == MfUltralightTypeUL21 && full_name) {
|
||||
return "Mifare Ultralight 21";
|
||||
} else {
|
||||
return "Mifare Ultralight";
|
||||
}
|
||||
}
|
||||
|
||||
const char* nfc_mf_classic_type(MfClassicType type) {
|
||||
if(type == MfClassicType1k) {
|
||||
return "Mifare Classic 1K";
|
||||
} else if(type == MfClassicType4k) {
|
||||
return "Mifare Classic 4K";
|
||||
} else {
|
||||
return "Mifare Classic";
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "nfc_device.h"
|
||||
|
||||
const char* nfc_get_dev_type(FuriHalNfcType type);
|
||||
|
||||
const char* nfc_guess_protocol(NfcProtocol protocol);
|
||||
|
||||
const char* nfc_mf_ul_type(MfUltralightType type, bool full_name);
|
||||
|
||||
const char* nfc_mf_classic_type(MfClassicType type);
|
@@ -1,708 +0,0 @@
|
||||
#include "nfc_worker_i.h"
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <platform.h>
|
||||
|
||||
#define TAG "NfcWorker"
|
||||
|
||||
/***************************** NFC Worker API *******************************/
|
||||
|
||||
NfcWorker* nfc_worker_alloc() {
|
||||
NfcWorker* nfc_worker = malloc(sizeof(NfcWorker));
|
||||
|
||||
// Worker thread attributes
|
||||
nfc_worker->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(nfc_worker->thread, "NfcWorker");
|
||||
furi_thread_set_stack_size(nfc_worker->thread, 8192);
|
||||
furi_thread_set_callback(nfc_worker->thread, nfc_worker_task);
|
||||
furi_thread_set_context(nfc_worker->thread, nfc_worker);
|
||||
|
||||
nfc_worker->callback = NULL;
|
||||
nfc_worker->context = NULL;
|
||||
nfc_worker->storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
// Initialize rfal
|
||||
while(furi_hal_nfc_is_busy()) {
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
nfc_worker->debug_pcap_worker = nfc_debug_pcap_alloc(nfc_worker->storage);
|
||||
}
|
||||
|
||||
return nfc_worker;
|
||||
}
|
||||
|
||||
void nfc_worker_free(NfcWorker* nfc_worker) {
|
||||
furi_assert(nfc_worker);
|
||||
|
||||
furi_thread_free(nfc_worker->thread);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
if(nfc_worker->debug_pcap_worker) nfc_debug_pcap_free(nfc_worker->debug_pcap_worker);
|
||||
|
||||
free(nfc_worker);
|
||||
}
|
||||
|
||||
NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker) {
|
||||
return nfc_worker->state;
|
||||
}
|
||||
|
||||
void nfc_worker_start(
|
||||
NfcWorker* nfc_worker,
|
||||
NfcWorkerState state,
|
||||
NfcDeviceData* dev_data,
|
||||
NfcWorkerCallback callback,
|
||||
void* context) {
|
||||
furi_assert(nfc_worker);
|
||||
furi_assert(dev_data);
|
||||
while(furi_hal_nfc_is_busy()) {
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
|
||||
nfc_worker->callback = callback;
|
||||
nfc_worker->context = context;
|
||||
nfc_worker->dev_data = dev_data;
|
||||
nfc_worker_change_state(nfc_worker, state);
|
||||
furi_thread_start(nfc_worker->thread);
|
||||
}
|
||||
|
||||
void nfc_worker_stop(NfcWorker* nfc_worker) {
|
||||
furi_assert(nfc_worker);
|
||||
if(nfc_worker->state == NfcWorkerStateBroken || nfc_worker->state == NfcWorkerStateReady) {
|
||||
return;
|
||||
}
|
||||
furi_hal_nfc_stop();
|
||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateStop);
|
||||
furi_thread_join(nfc_worker->thread);
|
||||
}
|
||||
|
||||
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state) {
|
||||
nfc_worker->state = state;
|
||||
}
|
||||
|
||||
/***************************** NFC Worker Thread *******************************/
|
||||
|
||||
int32_t nfc_worker_task(void* context) {
|
||||
NfcWorker* nfc_worker = context;
|
||||
|
||||
furi_hal_nfc_exit_sleep();
|
||||
|
||||
if(nfc_worker->state == NfcWorkerStateDetect) {
|
||||
nfc_worker_detect(nfc_worker);
|
||||
} else if(nfc_worker->state == NfcWorkerStateEmulate) {
|
||||
nfc_worker_emulate(nfc_worker);
|
||||
} else if(nfc_worker->state == NfcWorkerStateReadEMVApp) {
|
||||
nfc_worker_read_emv_app(nfc_worker);
|
||||
} 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 == 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 == NfcWorkerStateEmulateMifareClassic) {
|
||||
nfc_worker_emulate_mifare_classic(nfc_worker);
|
||||
} else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
|
||||
nfc_worker_read_mifare_desfire(nfc_worker);
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nfc_worker_detect(NfcWorker* nfc_worker) {
|
||||
nfc_device_data_clear(nfc_worker->dev_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(nfc_data, 1000)) {
|
||||
// Process first found device
|
||||
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(
|
||||
nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
||||
dev_data->protocol = NfcDeviceProtocolMifareClassic;
|
||||
} else if(mf_df_check_card_type(
|
||||
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 {
|
||||
dev_data->protocol = NfcDeviceProtocolUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
// Notify caller and exit
|
||||
if(nfc_worker->callback) {
|
||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||
}
|
||||
break;
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_worker_emulate(NfcWorker* nfc_worker) {
|
||||
FuriHalNfcTxRxContext tx_rx = {};
|
||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
|
||||
FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
|
||||
NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
|
||||
|
||||
while(nfc_worker->state == NfcWorkerStateEmulate) {
|
||||
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) {
|
||||
FuriHalNfcTxRxContext tx_rx = {};
|
||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
|
||||
EmvApplication emv_app = {};
|
||||
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) {
|
||||
if(furi_hal_nfc_detect(nfc_data, 1000)) {
|
||||
// Card was found. Check that it supports EMV
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_W(TAG, "Card doesn't support EMV");
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Can't find any cards");
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
furi_delay_ms(20);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
||||
FuriHalNfcTxRxContext tx_rx = {};
|
||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
|
||||
EmvApplication emv_app = {};
|
||||
NfcDeviceData* result = nfc_worker->dev_data;
|
||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||
nfc_device_data_clear(result);
|
||||
|
||||
while(nfc_worker->state == NfcWorkerStateReadEMVData) {
|
||||
if(furi_hal_nfc_detect(nfc_data, 1000)) {
|
||||
// Card was found. Check that it supports EMV
|
||||
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);
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_W(TAG, "Card doesn't support EMV");
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Can't find any cards");
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
furi_delay_ms(20);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
|
||||
FuriHalNfcTxRxContext tx_rx = {};
|
||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
|
||||
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();
|
||||
furi_delay_ms(20);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) {
|
||||
FuriHalNfcTxRxContext tx_rx = {};
|
||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
|
||||
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 {
|
||||
FURI_LOG_D(TAG, "Failed reading Mifare Ultralight");
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_W(TAG, "Tag is not Mifare Ultralight");
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Can't find any tags");
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
|
||||
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) {
|
||||
mf_ul_reset_emulation(&emulator, true);
|
||||
furi_hal_nfc_emulate_nfca(
|
||||
nfc_data->uid,
|
||||
nfc_data->uid_len,
|
||||
nfc_data->atqa,
|
||||
nfc_data->sak,
|
||||
mf_ul_prepare_emulation_response,
|
||||
&emulator,
|
||||
5000);
|
||||
// Check if data was modified
|
||||
if(emulator.data_changed) {
|
||||
nfc_worker->dev_data->mf_ul_data = emulator.data;
|
||||
if(nfc_worker->callback) {
|
||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||
}
|
||||
emulator.data_changed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
|
||||
furi_assert(nfc_worker->callback);
|
||||
FuriHalNfcTxRxContext tx_rx_ctx = {};
|
||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx_ctx, false);
|
||||
MfClassicAuthContext auth_ctx = {};
|
||||
MfClassicReader reader = {};
|
||||
uint64_t curr_key = 0;
|
||||
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);
|
||||
if(!nfc_mf_classic_dict_open_file(nfc_worker->dict_stream)) {
|
||||
event = NfcWorkerEventNoDictFound;
|
||||
nfc_worker->callback(event, nfc_worker->context);
|
||||
nfc_mf_classic_dict_close_file(nfc_worker->dict_stream);
|
||||
stream_free(nfc_worker->dict_stream);
|
||||
return;
|
||||
}
|
||||
|
||||
// Detect Mifare Classic card
|
||||
while(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
||||
if(furi_hal_nfc_detect(nfc_data, 300)) {
|
||||
if(mf_classic_get_type(
|
||||
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) {
|
||||
event = NfcWorkerEventDetectedClassic1k;
|
||||
} else {
|
||||
event = NfcWorkerEventDetectedClassic4k;
|
||||
}
|
||||
nfc_worker->callback(event, nfc_worker->context);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
event = NfcWorkerEventNoCardDetected;
|
||||
nfc_worker->callback(event, nfc_worker->context);
|
||||
}
|
||||
}
|
||||
|
||||
if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
||||
bool card_removed_notified = false;
|
||||
bool card_found_notified = false;
|
||||
// Seek for mifare classic keys
|
||||
for(curr_sector = 0; curr_sector < total_sectors; curr_sector++) {
|
||||
FURI_LOG_I(TAG, "Sector: %d ...", curr_sector);
|
||||
event = NfcWorkerEventNewSector;
|
||||
nfc_worker->callback(event, nfc_worker->context);
|
||||
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_sleep();
|
||||
if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) {
|
||||
if(!card_found_notified) {
|
||||
if(reader.type == MfClassicType1k) {
|
||||
event = NfcWorkerEventDetectedClassic1k;
|
||||
} else {
|
||||
event = NfcWorkerEventDetectedClassic4k;
|
||||
}
|
||||
nfc_worker->callback(event, nfc_worker->context);
|
||||
card_found_notified = true;
|
||||
card_removed_notified = false;
|
||||
}
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Try to auth to sector %d with key %04lx%08lx",
|
||||
curr_sector,
|
||||
(uint32_t)(curr_key >> 32),
|
||||
(uint32_t)curr_key);
|
||||
if(mf_classic_auth_attempt(&tx_rx_ctx, &auth_ctx, curr_key)) {
|
||||
sector_key_found = true;
|
||||
if((auth_ctx.key_a != MF_CLASSIC_NO_KEY) &&
|
||||
(auth_ctx.key_b != MF_CLASSIC_NO_KEY))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Notify that no tag is availalble
|
||||
FURI_LOG_D(TAG, "Can't find tags");
|
||||
if(!card_removed_notified) {
|
||||
event = NfcWorkerEventNoCardDetected;
|
||||
nfc_worker->callback(event, nfc_worker->context);
|
||||
card_removed_notified = true;
|
||||
card_found_notified = false;
|
||||
}
|
||||
}
|
||||
if(nfc_worker->state != NfcWorkerStateReadMifareClassic) break;
|
||||
furi_delay_tick(1);
|
||||
}
|
||||
if(nfc_worker->state != NfcWorkerStateReadMifareClassic) break;
|
||||
if(sector_key_found) {
|
||||
// Notify that keys were found
|
||||
if(auth_ctx.key_a != MF_CLASSIC_NO_KEY) {
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"Sector %d key A: %04lx%08lx",
|
||||
curr_sector,
|
||||
(uint32_t)(auth_ctx.key_a >> 32),
|
||||
(uint32_t)auth_ctx.key_a);
|
||||
event = NfcWorkerEventFoundKeyA;
|
||||
nfc_worker->callback(event, nfc_worker->context);
|
||||
}
|
||||
if(auth_ctx.key_b != MF_CLASSIC_NO_KEY) {
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"Sector %d key B: %04lx%08lx",
|
||||
curr_sector,
|
||||
(uint32_t)(auth_ctx.key_b >> 32),
|
||||
(uint32_t)auth_ctx.key_b);
|
||||
event = NfcWorkerEventFoundKeyB;
|
||||
nfc_worker->callback(event, nfc_worker->context);
|
||||
}
|
||||
// Add sectors to read sequence
|
||||
mf_classic_reader_add_sector(&reader, curr_sector, auth_ctx.key_a, auth_ctx.key_b);
|
||||
}
|
||||
nfc_mf_classic_dict_reset(nfc_worker->dict_stream);
|
||||
}
|
||||
}
|
||||
|
||||
if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
||||
FURI_LOG_I(TAG, "Found keys to %d sectors. Start reading sectors", reader.sectors_to_read);
|
||||
uint8_t sectors_read =
|
||||
mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data);
|
||||
if(sectors_read) {
|
||||
event = NfcWorkerEventSuccess;
|
||||
nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic;
|
||||
FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read);
|
||||
} else {
|
||||
event = NfcWorkerEventFail;
|
||||
FURI_LOG_W(TAG, "Failed to read any sector");
|
||||
}
|
||||
nfc_worker->callback(event, nfc_worker->context);
|
||||
}
|
||||
|
||||
nfc_mf_classic_dict_close_file(nfc_worker->dict_stream);
|
||||
stream_free(nfc_worker->dict_stream);
|
||||
}
|
||||
|
||||
void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) {
|
||||
FuriHalNfcTxRxContext tx_rx = {};
|
||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
|
||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||
MfClassicEmulator emulator = {
|
||||
.cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4),
|
||||
.data = nfc_worker->dev_data->mf_classic_data,
|
||||
.data_changed = false,
|
||||
};
|
||||
NfcaSignal* nfca_signal = nfca_signal_alloc();
|
||||
tx_rx.nfca_signal = nfca_signal;
|
||||
|
||||
rfal_platform_spi_acquire();
|
||||
|
||||
furi_hal_nfc_listen_start(nfc_data);
|
||||
while(nfc_worker->state == NfcWorkerStateEmulateMifareClassic) {
|
||||
if(furi_hal_nfc_listen_rx(&tx_rx, 300)) {
|
||||
mf_classic_emulator(&emulator, &tx_rx);
|
||||
}
|
||||
}
|
||||
if(emulator.data_changed) {
|
||||
nfc_worker->dev_data->mf_classic_data = emulator.data;
|
||||
if(nfc_worker->callback) {
|
||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||
}
|
||||
emulator.data_changed = false;
|
||||
}
|
||||
|
||||
nfca_signal_free(nfca_signal);
|
||||
|
||||
rfal_platform_spi_release();
|
||||
}
|
||||
|
||||
void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
||||
FuriHalNfcTxRxContext tx_rx = {};
|
||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
|
||||
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_sleep();
|
||||
if(!furi_hal_nfc_detect(nfc_data, 300)) {
|
||||
furi_delay_ms(100);
|
||||
continue;
|
||||
}
|
||||
memset(data, 0, sizeof(MifareDesfireData));
|
||||
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");
|
||||
furi_delay_ms(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
FURI_LOG_D(TAG, "Found DESFire tag");
|
||||
|
||||
result->protocol = NfcDeviceProtocolMifareDesfire;
|
||||
|
||||
// Get DESFire version
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_version(tx_rx.tx_data);
|
||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
||||
FURI_LOG_W(TAG, "Bad exchange getting version");
|
||||
continue;
|
||||
}
|
||||
if(!mf_df_parse_get_version_response(tx_rx.rx_data, tx_rx.rx_bits / 8, &data->version)) {
|
||||
FURI_LOG_W(TAG, "Bad DESFire GET_VERSION response");
|
||||
continue;
|
||||
}
|
||||
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_free_memory(tx_rx.tx_data);
|
||||
if(furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
||||
data->free_memory = malloc(sizeof(MifareDesfireFreeMemory));
|
||||
memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory));
|
||||
if(!mf_df_parse_get_free_memory_response(
|
||||
tx_rx.rx_data, tx_rx.rx_bits / 8, data->free_memory)) {
|
||||
FURI_LOG_D(TAG, "Bad DESFire GET_FREE_MEMORY response (normal for pre-EV1 cards)");
|
||||
free(data->free_memory);
|
||||
data->free_memory = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data);
|
||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
||||
FURI_LOG_D(TAG, "Bad exchange getting key settings");
|
||||
} else {
|
||||
data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings));
|
||||
memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings));
|
||||
if(!mf_df_parse_get_key_settings_response(
|
||||
tx_rx.rx_data, tx_rx.rx_bits / 8, data->master_key_settings)) {
|
||||
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response");
|
||||
free(data->master_key_settings);
|
||||
data->master_key_settings = NULL;
|
||||
} else {
|
||||
MifareDesfireKeyVersion** key_version_head =
|
||||
&data->master_key_settings->key_version_head;
|
||||
for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) {
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id);
|
||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
||||
FURI_LOG_W(TAG, "Bad exchange getting key version");
|
||||
continue;
|
||||
}
|
||||
MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion));
|
||||
memset(key_version, 0, sizeof(MifareDesfireKeyVersion));
|
||||
key_version->id = key_id;
|
||||
if(!mf_df_parse_get_key_version_response(
|
||||
tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) {
|
||||
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response");
|
||||
free(key_version);
|
||||
continue;
|
||||
}
|
||||
*key_version_head = key_version;
|
||||
key_version_head = &key_version->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_application_ids(tx_rx.tx_data);
|
||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
||||
FURI_LOG_W(TAG, "Bad exchange getting application IDs");
|
||||
} else {
|
||||
if(!mf_df_parse_get_application_ids_response(
|
||||
tx_rx.rx_data, tx_rx.rx_bits / 8, &data->app_head)) {
|
||||
FURI_LOG_W(TAG, "Bad DESFire GET_APPLICATION_IDS response");
|
||||
}
|
||||
}
|
||||
|
||||
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_select_application(tx_rx.tx_data, app->id);
|
||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx) ||
|
||||
!mf_df_parse_select_application_response(tx_rx.rx_data, tx_rx.rx_bits / 8)) {
|
||||
FURI_LOG_W(TAG, "Bad exchange selecting application");
|
||||
continue;
|
||||
}
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data);
|
||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
||||
FURI_LOG_W(TAG, "Bad exchange getting key settings");
|
||||
} else {
|
||||
app->key_settings = malloc(sizeof(MifareDesfireKeySettings));
|
||||
memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings));
|
||||
if(!mf_df_parse_get_key_settings_response(
|
||||
tx_rx.rx_data, tx_rx.rx_bits / 8, app->key_settings)) {
|
||||
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response");
|
||||
free(app->key_settings);
|
||||
app->key_settings = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
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_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id);
|
||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
||||
FURI_LOG_W(TAG, "Bad exchange getting key version");
|
||||
continue;
|
||||
}
|
||||
MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion));
|
||||
memset(key_version, 0, sizeof(MifareDesfireKeyVersion));
|
||||
key_version->id = key_id;
|
||||
if(!mf_df_parse_get_key_version_response(
|
||||
tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) {
|
||||
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response");
|
||||
free(key_version);
|
||||
continue;
|
||||
}
|
||||
*key_version_head = key_version;
|
||||
key_version_head = &key_version->next;
|
||||
}
|
||||
}
|
||||
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_file_ids(tx_rx.tx_data);
|
||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
||||
FURI_LOG_W(TAG, "Bad exchange getting file IDs");
|
||||
} else {
|
||||
if(!mf_df_parse_get_file_ids_response(
|
||||
tx_rx.rx_data, tx_rx.rx_bits / 8, &app->file_head)) {
|
||||
FURI_LOG_W(TAG, "Bad DESFire GET_FILE_IDS response");
|
||||
}
|
||||
}
|
||||
|
||||
for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_file_settings(tx_rx.tx_data, file->id);
|
||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
||||
FURI_LOG_W(TAG, "Bad exchange getting file settings");
|
||||
continue;
|
||||
}
|
||||
if(!mf_df_parse_get_file_settings_response(
|
||||
tx_rx.rx_data, tx_rx.rx_bits / 8, file)) {
|
||||
FURI_LOG_W(TAG, "Bad DESFire GET_FILE_SETTINGS response");
|
||||
continue;
|
||||
}
|
||||
switch(file->type) {
|
||||
case MifareDesfireFileTypeStandard:
|
||||
case MifareDesfireFileTypeBackup:
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_read_data(tx_rx.tx_data, file->id, 0, 0);
|
||||
break;
|
||||
case MifareDesfireFileTypeValue:
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_value(tx_rx.tx_data, file->id);
|
||||
break;
|
||||
case MifareDesfireFileTypeLinearRecord:
|
||||
case MifareDesfireFileTypeCyclicRecord:
|
||||
tx_rx.tx_bits = 8 * mf_df_prepare_read_records(tx_rx.tx_data, file->id, 0, 0);
|
||||
break;
|
||||
}
|
||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
||||
FURI_LOG_W(TAG, "Bad exchange reading file %d", file->id);
|
||||
continue;
|
||||
}
|
||||
if(!mf_df_parse_read_data_response(tx_rx.rx_data, tx_rx.rx_bits / 8, file)) {
|
||||
FURI_LOG_W(TAG, "Bad response reading file %d", file->id);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify caller and exit
|
||||
if(nfc_worker->callback) {
|
||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "nfc_device.h"
|
||||
|
||||
typedef struct NfcWorker NfcWorker;
|
||||
|
||||
typedef enum {
|
||||
// Init states
|
||||
NfcWorkerStateNone,
|
||||
NfcWorkerStateBroken,
|
||||
NfcWorkerStateReady,
|
||||
// Main worker states
|
||||
NfcWorkerStateDetect,
|
||||
NfcWorkerStateEmulate,
|
||||
NfcWorkerStateReadEMVApp,
|
||||
NfcWorkerStateReadEMVData,
|
||||
NfcWorkerStateEmulateApdu,
|
||||
NfcWorkerStateField,
|
||||
NfcWorkerStateReadMifareUltralight,
|
||||
NfcWorkerStateEmulateMifareUltralight,
|
||||
NfcWorkerStateReadMifareClassic,
|
||||
NfcWorkerStateEmulateMifareClassic,
|
||||
NfcWorkerStateReadMifareDesfire,
|
||||
// Transition
|
||||
NfcWorkerStateStop,
|
||||
} NfcWorkerState;
|
||||
|
||||
typedef enum {
|
||||
// Reserve first 50 events for application events
|
||||
NfcWorkerEventReserved = 50,
|
||||
|
||||
// Nfc worker common events
|
||||
NfcWorkerEventSuccess,
|
||||
NfcWorkerEventFail,
|
||||
NfcWorkerEventNoCardDetected,
|
||||
// Mifare Classic events
|
||||
NfcWorkerEventNoDictFound,
|
||||
NfcWorkerEventDetectedClassic1k,
|
||||
NfcWorkerEventDetectedClassic4k,
|
||||
NfcWorkerEventNewSector,
|
||||
NfcWorkerEventFoundKeyA,
|
||||
NfcWorkerEventFoundKeyB,
|
||||
NfcWorkerEventStartReading,
|
||||
} NfcWorkerEvent;
|
||||
|
||||
typedef void (*NfcWorkerCallback)(NfcWorkerEvent event, void* context);
|
||||
|
||||
NfcWorker* nfc_worker_alloc();
|
||||
|
||||
NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_free(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_start(
|
||||
NfcWorker* nfc_worker,
|
||||
NfcWorkerState state,
|
||||
NfcDeviceData* dev_data,
|
||||
NfcWorkerCallback callback,
|
||||
void* context);
|
||||
|
||||
void nfc_worker_stop(NfcWorker* nfc_worker);
|
@@ -1,57 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "nfc_worker.h"
|
||||
#include "nfc_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <lib/toolbox/stream/file_stream.h>
|
||||
|
||||
#include <lib/nfc_protocols/nfc_util.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>
|
||||
#include <lib/nfc_protocols/nfca.h>
|
||||
|
||||
#include "helpers/nfc_mf_classic_dict.h"
|
||||
#include "helpers/nfc_debug_pcap.h"
|
||||
|
||||
struct NfcWorker {
|
||||
FuriThread* thread;
|
||||
Storage* storage;
|
||||
Stream* dict_stream;
|
||||
|
||||
NfcDeviceData* dev_data;
|
||||
|
||||
NfcWorkerCallback callback;
|
||||
void* context;
|
||||
|
||||
NfcWorkerState state;
|
||||
|
||||
NfcDebugPcapWorker* debug_pcap_worker;
|
||||
};
|
||||
|
||||
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state);
|
||||
|
||||
int32_t nfc_worker_task(void* context);
|
||||
|
||||
void nfc_worker_read_emv_app(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_read_emv(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_detect(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_emulate(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker);
|
||||
|
||||
void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker);
|
@@ -1,90 +0,0 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexRunApp,
|
||||
SubmenuIndexChooseScript,
|
||||
SubmenuIndexEmulate,
|
||||
SubmenuIndexSave,
|
||||
};
|
||||
|
||||
void nfc_scene_card_menu_submenu_callback(void* context, uint32_t index) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_card_menu_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
if(nfc->dev->dev_data.protocol > NfcDeviceProtocolUnknown) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Run Compatible App",
|
||||
SubmenuIndexRunApp,
|
||||
nfc_scene_card_menu_submenu_callback,
|
||||
nfc);
|
||||
}
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Additional reading scripts",
|
||||
SubmenuIndexChooseScript,
|
||||
nfc_scene_card_menu_submenu_callback,
|
||||
nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Emulate UID", SubmenuIndexEmulate, nfc_scene_card_menu_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Save UID", SubmenuIndexSave, nfc_scene_card_menu_submenu_callback, nfc);
|
||||
submenu_set_selected_item(
|
||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneCardMenu));
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexRunApp) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp);
|
||||
if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
|
||||
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareDesfire) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire);
|
||||
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolEMV) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
|
||||
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexChooseScript) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexChooseScript);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexEmulate) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexEmulate);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexSave) {
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexSave);
|
||||
nfc->dev->format = NfcDeviceSaveFormatUid;
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed =
|
||||
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_card_menu_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
submenu_reset(nfc->submenu);
|
||||
}
|
@@ -1,41 +1,40 @@
|
||||
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, emulate_uid, EmulateUid)
|
||||
ADD_SCENE(nfc, save_name, SaveName)
|
||||
ADD_SCENE(nfc, save_success, SaveSuccess)
|
||||
ADD_SCENE(nfc, file_select, FileSelect)
|
||||
ADD_SCENE(nfc, read, Read)
|
||||
ADD_SCENE(nfc, saved_menu, SavedMenu)
|
||||
ADD_SCENE(nfc, extra_actions, ExtraActions)
|
||||
ADD_SCENE(nfc, set_type, SetType)
|
||||
ADD_SCENE(nfc, set_sak, SetSak)
|
||||
ADD_SCENE(nfc, set_atqa, SetAtqua)
|
||||
ADD_SCENE(nfc, set_uid, SetUid)
|
||||
ADD_SCENE(nfc, scripts_menu, ScriptsMenu)
|
||||
ADD_SCENE(nfc, read_mifare_ul, ReadMifareUl)
|
||||
ADD_SCENE(nfc, read_mifare_ul_success, ReadMifareUlSuccess)
|
||||
ADD_SCENE(nfc, mifare_ul_menu, MifareUlMenu)
|
||||
ADD_SCENE(nfc, emulate_mifare_ul, EmulateMifareUl)
|
||||
ADD_SCENE(nfc, read_emv_app, ReadEmvApp)
|
||||
ADD_SCENE(nfc, read_emv_app_success, ReadEmvAppSuccess)
|
||||
ADD_SCENE(nfc, read_mifare_desfire, ReadMifareDesfire)
|
||||
ADD_SCENE(nfc, read_mifare_desfire_success, ReadMifareDesfireSuccess)
|
||||
ADD_SCENE(nfc, mifare_desfire_menu, MifareDesfireMenu)
|
||||
ADD_SCENE(nfc, mifare_desfire_data, MifareDesfireData)
|
||||
ADD_SCENE(nfc, mifare_desfire_app, MifareDesfireApp)
|
||||
ADD_SCENE(nfc, generate_info, GenerateInfo)
|
||||
ADD_SCENE(nfc, read_card_success, ReadCardSuccess)
|
||||
ADD_SCENE(nfc, save_name, SaveName)
|
||||
ADD_SCENE(nfc, save_success, SaveSuccess)
|
||||
ADD_SCENE(nfc, file_select, FileSelect)
|
||||
ADD_SCENE(nfc, emulate_uid, EmulateUid)
|
||||
ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess)
|
||||
ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu)
|
||||
ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate)
|
||||
ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess)
|
||||
ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu)
|
||||
ADD_SCENE(nfc, mf_desfire_data, MfDesfireData)
|
||||
ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp)
|
||||
ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess)
|
||||
ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu)
|
||||
ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate)
|
||||
ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys)
|
||||
ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd)
|
||||
ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack)
|
||||
ADD_SCENE(nfc, emv_read_success, EmvReadSuccess)
|
||||
ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence)
|
||||
ADD_SCENE(nfc, device_info, DeviceInfo)
|
||||
ADD_SCENE(nfc, delete, Delete)
|
||||
ADD_SCENE(nfc, delete_success, DeleteSuccess)
|
||||
ADD_SCENE(nfc, run_emv_app_confirm, RunEmvAppConfirm)
|
||||
ADD_SCENE(nfc, read_emv_data, ReadEmvData)
|
||||
ADD_SCENE(nfc, read_emv_data_success, ReadEmvDataSuccess)
|
||||
ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence)
|
||||
ADD_SCENE(nfc, restore_original, RestoreOriginal)
|
||||
ADD_SCENE(nfc, debug, Debug)
|
||||
ADD_SCENE(nfc, field, Field)
|
||||
ADD_SCENE(nfc, read_mifare_classic, ReadMifareClassic)
|
||||
ADD_SCENE(nfc, emulate_mifare_classic, EmulateMifareClassic)
|
||||
ADD_SCENE(nfc, mifare_classic_menu, MifareClassicMenu)
|
||||
ADD_SCENE(nfc, dict_not_found, DictNotFound)
|
||||
ADD_SCENE(nfc, rpc, Rpc)
|
||||
ADD_SCENE(nfc, generate_info, GenerateInfo)
|
||||
ADD_SCENE(nfc, exit_confirm, ExitConfirm)
|
||||
ADD_SCENE(nfc, retry_confirm, RetryConfirm)
|
||||
ADD_SCENE(nfc, detect_reader, DetectReader)
|
||||
|
143
applications/nfc/scenes/nfc_scene_detect_reader.c
Normal file
143
applications/nfc/scenes/nfc_scene_detect_reader.c
Normal file
@@ -0,0 +1,143 @@
|
||||
#include "../nfc_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define NFC_SCENE_DETECT_READER_LOG_SIZE_MAX (200)
|
||||
|
||||
enum {
|
||||
NfcSceneDetectReaderStateWidget,
|
||||
NfcSceneDetectReaderStateTextBox,
|
||||
};
|
||||
|
||||
bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||
return true;
|
||||
}
|
||||
|
||||
void nfc_scene_detect_reader_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_detect_reader_textbox_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||
}
|
||||
|
||||
// Add widget with device name or inform that data received
|
||||
static void nfc_scene_detect_reader_widget_config(Nfc* nfc, bool data_received) {
|
||||
Widget* widget = nfc->widget;
|
||||
widget_reset(widget);
|
||||
|
||||
widget_add_icon_element(widget, 0, 14, &I_Reader_detect);
|
||||
widget_add_string_element(
|
||||
widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold near reader");
|
||||
widget_add_string_element(widget, 55, 22, AlignLeft, AlignTop, FontPrimary, "Emulating...");
|
||||
|
||||
if(data_received) {
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeCenter, "Log", nfc_scene_detect_reader_widget_callback, nfc);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_scene_detect_reader_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||
FuriHalNfcDevData nfc_params = {
|
||||
.uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34},
|
||||
.uid_len = 7,
|
||||
.atqa = {0x44, 0x00},
|
||||
.sak = 0x08,
|
||||
.type = FuriHalNfcTypeA,
|
||||
};
|
||||
nfc->dev->dev_data.nfc_data = nfc_params;
|
||||
|
||||
// Setup Widget
|
||||
nfc_scene_detect_reader_widget_config(nfc, false);
|
||||
// Setup TextBox
|
||||
TextBox* text_box = nfc->text_box;
|
||||
text_box_set_font(text_box, TextBoxFontHex);
|
||||
text_box_set_focus(text_box, TextBoxFocusEnd);
|
||||
string_reset(nfc->text_box_store);
|
||||
|
||||
// Set Widget state and view
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||
// Start worker
|
||||
memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateUidEmulate,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_detect_reader_worker_callback,
|
||||
nfc);
|
||||
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data;
|
||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDetectReader);
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventWorkerExit) {
|
||||
// Add data button to widget if data is received for the first time
|
||||
if(!string_size(nfc->text_box_store)) {
|
||||
nfc_scene_detect_reader_widget_config(nfc, true);
|
||||
}
|
||||
// Update TextBox data
|
||||
if(string_size(nfc->text_box_store) < NFC_SCENE_DETECT_READER_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));
|
||||
}
|
||||
memset(reader_data, 0, sizeof(NfcReaderRequestData));
|
||||
consumed = true;
|
||||
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneDetectReaderStateWidget) {
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateTextBox);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcCustomEventViewExit && state == NfcSceneDetectReaderStateTextBox) {
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
if(state == NfcSceneDetectReaderStateTextBox) {
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_detect_reader_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
|
||||
// Clear view
|
||||
widget_reset(nfc->widget);
|
||||
text_box_reset(nfc->text_box);
|
||||
string_reset(nfc->text_box_store);
|
||||
|
||||
nfc_blink_stop(nfc);
|
||||
}
|
@@ -190,7 +190,7 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard);
|
||||
consumed = true;
|
||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireData);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(state == NfcSceneDeviceInfoData && event.event == NfcCustomEventViewExit) {
|
||||
|
@@ -31,12 +31,9 @@ bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneScriptsMenu)) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneScriptsMenu);
|
||||
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneCardMenu)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneCardMenu);
|
||||
nfc->scene_manager, NfcSceneExtraActions);
|
||||
} else {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneStart);
|
||||
|
@@ -8,11 +8,12 @@ enum {
|
||||
NfcSceneEmulateUidStateTextBox,
|
||||
};
|
||||
|
||||
void nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
bool nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||
return true;
|
||||
}
|
||||
|
||||
void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
@@ -76,7 +77,7 @@ void nfc_scene_emulate_uid_on_enter(void* context) {
|
||||
memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateEmulate,
|
||||
NfcWorkerStateUidEmulate,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_emulate_uid_worker_callback,
|
||||
nfc);
|
||||
@@ -90,9 +91,7 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) {
|
||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateUid);
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventWorkerExit) {
|
||||
// Add data button to widget if data is received for the first time
|
||||
if(!string_size(nfc->text_box_store)) {
|
||||
|
36
applications/nfc/scenes/nfc_scene_read_emv_data_success.c → applications/nfc/scenes/nfc_scene_emv_read_success.c
Executable file → Normal file
36
applications/nfc/scenes/nfc_scene_read_emv_data_success.c → applications/nfc/scenes/nfc_scene_emv_read_success.c
Executable file → Normal file
@@ -2,7 +2,7 @@
|
||||
#include "../helpers/nfc_emv_parser.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void nfc_scene_read_emv_data_success_widget_callback(
|
||||
void nfc_scene_emv_read_success_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
@@ -12,7 +12,7 @@ void nfc_scene_read_emv_data_success_widget_callback(
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
||||
void nfc_scene_emv_read_success_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
|
||||
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
|
||||
@@ -23,17 +23,9 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
||||
widget_add_frame_element(nfc->widget, 0, 0, 128, 64, 6);
|
||||
// Add buttons
|
||||
widget_add_button_element(
|
||||
nfc->widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Back",
|
||||
nfc_scene_read_emv_data_success_widget_callback,
|
||||
nfc);
|
||||
nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc);
|
||||
widget_add_button_element(
|
||||
nfc->widget,
|
||||
GuiButtonTypeRight,
|
||||
"Save",
|
||||
nfc_scene_read_emv_data_success_widget_callback,
|
||||
nfc);
|
||||
nfc->widget, GuiButtonTypeRight, "Save", nfc_scene_emv_read_success_widget_callback, nfc);
|
||||
// Add card name
|
||||
widget_add_string_element(
|
||||
nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name);
|
||||
@@ -103,25 +95,17 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
||||
widget_add_string_element(nfc->widget, 7, 32, AlignLeft, AlignTop, FontSecondary, exp_str);
|
||||
}
|
||||
|
||||
// Send notification
|
||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvDataSuccess) ==
|
||||
NFC_SEND_NOTIFICATION_TRUE) {
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_FALSE);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) {
|
||||
bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
|
||||
consumed = true;
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
// Clear device name
|
||||
nfc_device_set_name(nfc->dev, "");
|
||||
@@ -130,13 +114,13 @@ bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent e
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_emv_data_success_on_exit(void* context) {
|
||||
void nfc_scene_emv_read_success_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear view
|
47
applications/nfc/scenes/nfc_scene_exit_confirm.c
Normal file
47
applications/nfc/scenes/nfc_scene_exit_confirm.c
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
void nfc_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void nfc_scene_exit_confirm_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Exit");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Stay");
|
||||
dialog_ex_set_header(dialog_ex, "Exit to NFC menu?", 64, 11, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "All unsaved data\nwill be lost.", 64, 25, AlignCenter, AlignTop);
|
||||
dialog_ex_set_context(dialog_ex, nfc);
|
||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_exit_confirm_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||
}
|
||||
|
||||
bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == DialogExResultRight) {
|
||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||
} else if(event.event == DialogExResultLeft) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneStart);
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_exit_confirm_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clean view
|
||||
dialog_ex_reset(nfc->dialog_ex);
|
||||
}
|
48
applications/nfc/scenes/nfc_scene_extra_actions.c
Normal file
48
applications/nfc/scenes/nfc_scene_extra_actions.c
Normal file
@@ -0,0 +1,48 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexMfClassicKeys,
|
||||
};
|
||||
|
||||
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_extra_actions_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Mf Classic Keys",
|
||||
SubmenuIndexMfClassicKeys,
|
||||
nfc_scene_extra_actions_submenu_callback,
|
||||
nfc);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexMfClassicKeys) {
|
||||
if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeys);
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_extra_actions_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
submenu_reset(nfc->submenu);
|
||||
}
|
137
applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c
Normal file
137
applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
typedef enum {
|
||||
DictAttackStateIdle,
|
||||
DictAttackStateUserDictInProgress,
|
||||
DictAttackStateFlipperDictInProgress,
|
||||
} DictAttackState;
|
||||
|
||||
bool nfc_dict_attack_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
|
||||
return true;
|
||||
}
|
||||
|
||||
void nfc_dict_attack_dict_attack_result_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackSkip);
|
||||
}
|
||||
|
||||
static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) {
|
||||
MfClassicData* data = &nfc->dev->dev_data.mf_classic_data;
|
||||
uint8_t sectors_read = 0;
|
||||
uint8_t keys_found = 0;
|
||||
|
||||
// Calculate found keys and read sectors
|
||||
mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found);
|
||||
dict_attack_set_keys_found(nfc->dict_attack, keys_found);
|
||||
dict_attack_set_sector_read(nfc->dict_attack, sectors_read);
|
||||
}
|
||||
|
||||
static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) {
|
||||
MfClassicData* data = &nfc->dev->dev_data.mf_classic_data;
|
||||
NfcWorkerState worker_state = NfcWorkerStateReady;
|
||||
|
||||
// Identify scene state
|
||||
if(state == DictAttackStateIdle) {
|
||||
if(mf_classic_dict_check_presence(MfClassicDictTypeUser)) {
|
||||
state = DictAttackStateUserDictInProgress;
|
||||
} else {
|
||||
state = DictAttackStateFlipperDictInProgress;
|
||||
}
|
||||
} else if(state == DictAttackStateUserDictInProgress) {
|
||||
state = DictAttackStateFlipperDictInProgress;
|
||||
}
|
||||
|
||||
// Setup view
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
worker_state = NfcWorkerStateMfClassicUserDictAttack;
|
||||
dict_attack_set_header(nfc->dict_attack, "Mf Classic User Dict.");
|
||||
} else if(state == DictAttackStateFlipperDictInProgress) {
|
||||
worker_state = NfcWorkerStateMfClassicFlipperDictAttack;
|
||||
dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict.");
|
||||
}
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state);
|
||||
dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc);
|
||||
dict_attack_set_current_sector(nfc->dict_attack, 0);
|
||||
dict_attack_set_card_detected(nfc->dict_attack, data->type);
|
||||
nfc_scene_mf_classic_dict_attack_update_view(nfc);
|
||||
nfc_worker_start(
|
||||
nfc->worker, worker_state, &nfc->dev->dev_data, nfc_dict_attack_worker_callback, nfc);
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_dict_attack_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack);
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
MfClassicData* data = &nfc->dev->dev_data.mf_classic_data;
|
||||
bool consumed = false;
|
||||
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack);
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcWorkerEventSuccess) {
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
nfc_worker_stop(nfc->worker);
|
||||
nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state);
|
||||
consumed = true;
|
||||
} else {
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.event == NfcWorkerEventAborted) {
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state);
|
||||
consumed = true;
|
||||
} else {
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.event == NfcWorkerEventCardDetected) {
|
||||
dict_attack_set_card_detected(nfc->dict_attack, data->type);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventNoCardDetected) {
|
||||
dict_attack_set_card_removed(nfc->dict_attack);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventFoundKeyA) {
|
||||
dict_attack_inc_keys_found(nfc->dict_attack);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventFoundKeyB) {
|
||||
dict_attack_inc_keys_found(nfc->dict_attack);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventNewSector) {
|
||||
nfc_scene_mf_classic_dict_attack_update_view(nfc);
|
||||
dict_attack_inc_current_sector(nfc->dict_attack);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcCustomEventDictAttackSkip) {
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
nfc_worker_stop(nfc->worker);
|
||||
consumed = true;
|
||||
} else if(state == DictAttackStateFlipperDictInProgress) {
|
||||
nfc_worker_stop(nfc->worker);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
dict_attack_reset(nfc->dict_attack);
|
||||
nfc_blink_stop(nfc);
|
||||
}
|
@@ -4,51 +4,52 @@
|
||||
#define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL)
|
||||
#define NFC_MF_CLASSIC_DATA_CHANGED (1UL)
|
||||
|
||||
void nfc_emulate_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
Nfc* nfc = context;
|
||||
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneEmulateMifareClassic, NFC_MF_CLASSIC_DATA_CHANGED);
|
||||
nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_CHANGED);
|
||||
return true;
|
||||
}
|
||||
|
||||
void nfc_scene_emulate_mifare_classic_on_enter(void* context) {
|
||||
void nfc_scene_mf_classic_emulate_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = nfc->popup;
|
||||
if(strcmp(nfc->dev->dev_name, "")) {
|
||||
nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
|
||||
nfc_text_store_set(nfc, "Emulating\n%s", nfc->dev->dev_name);
|
||||
} else {
|
||||
nfc_text_store_set(nfc, "Emulating\nMf Classic", nfc->dev->dev_name);
|
||||
}
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||
popup_set_header(popup, "Emulating\nMf Classic", 56, 31, AlignLeft, AlignTop);
|
||||
popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop);
|
||||
|
||||
// Setup and start worker
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateEmulateMifareClassic,
|
||||
NfcWorkerStateMfClassicEmulate,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_emulate_mifare_classic_worker_callback,
|
||||
nfc_mf_classic_emulate_worker_callback,
|
||||
nfc);
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_emulate_mifare_classic_on_event(void* context, SceneManagerEvent event) {
|
||||
bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
// Check if data changed and save in shadow file
|
||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateMifareClassic) ==
|
||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicEmulate) ==
|
||||
NFC_MF_CLASSIC_DATA_CHANGED) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneEmulateMifareClassic, NFC_MF_CLASSIC_DATA_NOT_CHANGED);
|
||||
nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_NOT_CHANGED);
|
||||
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
|
||||
}
|
||||
consumed = false;
|
||||
@@ -56,7 +57,7 @@ bool nfc_scene_emulate_mifare_classic_on_event(void* context, SceneManagerEvent
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_emulate_mifare_classic_on_exit(void* context) {
|
||||
void nfc_scene_mf_classic_emulate_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear view
|
59
applications/nfc/scenes/nfc_scene_mf_classic_keys.c
Normal file
59
applications/nfc/scenes/nfc_scene_mf_classic_keys.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
void nfc_scene_mf_classic_keys_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_mf_classic_keys_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Load flipper dict keys total
|
||||
uint32_t flipper_dict_keys_total = 0;
|
||||
MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper);
|
||||
if(dict) {
|
||||
flipper_dict_keys_total = mf_classic_dict_get_total_keys(dict);
|
||||
mf_classic_dict_free(dict);
|
||||
}
|
||||
// Load user dict keys total
|
||||
uint32_t user_dict_keys_total = 0;
|
||||
dict = mf_classic_dict_alloc(MfClassicDictTypeUser);
|
||||
if(dict) {
|
||||
user_dict_keys_total = mf_classic_dict_get_total_keys(dict);
|
||||
mf_classic_dict_free(dict);
|
||||
}
|
||||
|
||||
widget_add_string_element(
|
||||
nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MF Classic Keys");
|
||||
char temp_str[32];
|
||||
snprintf(temp_str, sizeof(temp_str), "Flipper dict: %ld", flipper_dict_keys_total);
|
||||
widget_add_string_element(nfc->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, temp_str);
|
||||
snprintf(temp_str, sizeof(temp_str), "User dict: %ld", user_dict_keys_total);
|
||||
widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str);
|
||||
widget_add_button_element(
|
||||
nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc);
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeCenter) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
widget_reset(nfc->widget);
|
||||
}
|
57
applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c
Normal file
57
applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_add_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = nfc->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter the key in hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
nfc_scene_mf_classic_keys_add_byte_input_callback,
|
||||
NULL,
|
||||
nfc,
|
||||
nfc->byte_input_store,
|
||||
6);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventByteInputDone) {
|
||||
// Add key to dict
|
||||
bool key_added = false;
|
||||
MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser);
|
||||
if(dict) {
|
||||
if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) {
|
||||
key_added = true;
|
||||
}
|
||||
}
|
||||
if(key_added) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||
}
|
||||
mf_classic_dict_free(dict);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_add_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear view
|
||||
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(nfc->byte_input, "");
|
||||
}
|
22
applications/nfc/scenes/nfc_scene_mifare_ul_menu.c → applications/nfc/scenes/nfc_scene_mf_classic_menu.c
Executable file → Normal file
22
applications/nfc/scenes/nfc_scene_mifare_ul_menu.c → applications/nfc/scenes/nfc_scene_mf_classic_menu.c
Executable file → Normal file
@@ -5,43 +5,43 @@ enum SubmenuIndex {
|
||||
SubmenuIndexEmulate,
|
||||
};
|
||||
|
||||
void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) {
|
||||
void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_ul_menu_on_enter(void* context) {
|
||||
void nfc_scene_mf_classic_menu_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_ul_menu_submenu_callback, nfc);
|
||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mifare_ul_menu_submenu_callback, nfc);
|
||||
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc);
|
||||
submenu_set_selected_item(
|
||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareUlMenu));
|
||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu));
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexSave) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave);
|
||||
nfc->dev->format = NfcDeviceSaveFormatMifareUl;
|
||||
nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexSave);
|
||||
nfc->dev->format = NfcDeviceSaveFormatMifareClassic;
|
||||
// Clear device name
|
||||
nfc_device_set_name(nfc->dev, "");
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||
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);
|
||||
nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
@@ -52,7 +52,7 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_ul_menu_on_exit(void* context) {
|
||||
void nfc_scene_mf_classic_menu_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear view
|
104
applications/nfc/scenes/nfc_scene_mf_classic_read_success.c
Normal file
104
applications/nfc/scenes/nfc_scene_mf_classic_read_success.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "../nfc_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void nfc_scene_mf_classic_read_success_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_read_success_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
NfcDeviceData* dev_data = &nfc->dev->dev_data;
|
||||
MfClassicData* mf_data = &dev_data->mf_classic_data;
|
||||
string_t str_tmp;
|
||||
string_init(str_tmp);
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||
|
||||
// Setup view
|
||||
Widget* widget = nfc->widget;
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_classic_read_success_widget_callback, nfc);
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc);
|
||||
|
||||
if(string_size(nfc->dev->dev_data.parsed_data)) {
|
||||
widget_add_text_box_element(
|
||||
nfc->widget,
|
||||
0,
|
||||
0,
|
||||
128,
|
||||
32,
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
string_get_cstr(nfc->dev->dev_data.parsed_data),
|
||||
true);
|
||||
} else {
|
||||
widget_add_string_element(
|
||||
widget,
|
||||
0,
|
||||
0,
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
mf_classic_get_type_str(mf_data->type));
|
||||
widget_add_string_element(
|
||||
widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)");
|
||||
string_printf(str_tmp, "UID:");
|
||||
for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) {
|
||||
string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]);
|
||||
}
|
||||
widget_add_string_element(
|
||||
widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
|
||||
uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type);
|
||||
uint8_t keys_total = sectors_total * 2;
|
||||
uint8_t keys_found = 0;
|
||||
uint8_t sectors_read = 0;
|
||||
mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found);
|
||||
string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total);
|
||||
widget_add_string_element(
|
||||
widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
|
||||
string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total);
|
||||
widget_add_string_element(
|
||||
widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
|
||||
}
|
||||
|
||||
string_clear(str_tmp);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
|
||||
consumed = true;
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
// Clear device name
|
||||
nfc_device_set_name(nfc->dev, "");
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicMenu);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_read_success_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear view
|
||||
widget_reset(nfc->widget);
|
||||
}
|
@@ -1,15 +1,15 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
#define TAG "NfcSceneMifareDesfireApp"
|
||||
#define TAG "NfcSceneMfDesfireApp"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexAppInfo,
|
||||
SubmenuIndexDynamic, // dynamic indexes start here
|
||||
};
|
||||
|
||||
MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) {
|
||||
uint32_t app_idx =
|
||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp) >> 1;
|
||||
MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(Nfc* nfc) {
|
||||
uint32_t app_idx = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >>
|
||||
1;
|
||||
MifareDesfireApplication* app = nfc->dev->dev_data.mf_df_data.app_head;
|
||||
for(uint32_t i = 0; i < app_idx && app; i++) {
|
||||
app = app->next;
|
||||
@@ -17,16 +17,16 @@ MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) {
|
||||
return app;
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) {
|
||||
void nfc_scene_mf_desfire_app_submenu_callback(void* context, uint32_t index) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_desfire_app_on_enter(void* context) {
|
||||
void nfc_scene_mf_desfire_app_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc);
|
||||
MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc);
|
||||
if(!app) {
|
||||
popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42);
|
||||
popup_set_header(nfc->popup, "Internal Error!", 55, 12, AlignLeft, AlignBottom);
|
||||
@@ -45,11 +45,7 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) {
|
||||
text_box_set_font(nfc->text_box, TextBoxFontHex);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"App info",
|
||||
SubmenuIndexAppInfo,
|
||||
nfc_scene_mifare_desfire_app_submenu_callback,
|
||||
nfc);
|
||||
submenu, "App info", SubmenuIndexAppInfo, nfc_scene_mf_desfire_app_submenu_callback, nfc);
|
||||
|
||||
uint16_t cap = NFC_TEXT_STORE_SIZE;
|
||||
char* buf = nfc->text_store;
|
||||
@@ -65,20 +61,19 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) {
|
||||
char* label = buf;
|
||||
cap -= size + 1;
|
||||
buf += size + 1;
|
||||
submenu_add_item(
|
||||
submenu, label, idx++, nfc_scene_mifare_desfire_app_submenu_callback, nfc);
|
||||
submenu_add_item(submenu, label, idx++, nfc_scene_mf_desfire_app_submenu_callback, nfc);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) {
|
||||
bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp);
|
||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp);
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc);
|
||||
MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc);
|
||||
TextBox* text_box = nfc->text_box;
|
||||
string_reset(nfc->text_box_store);
|
||||
if(event.event == SubmenuIndexAppInfo) {
|
||||
@@ -95,14 +90,13 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even
|
||||
mf_df_cat_file(file, nfc->text_box_store);
|
||||
}
|
||||
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1);
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state | 1);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||
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);
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state & ~1);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
@@ -110,7 +104,7 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_desfire_app_on_exit(void* context) {
|
||||
void nfc_scene_mf_desfire_app_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear views
|
@@ -1,6 +1,6 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
#define TAG "NfcSceneMifareDesfireData"
|
||||
#define TAG "NfcSceneMfDesfireData"
|
||||
|
||||
enum {
|
||||
MifareDesfireDataStateMenu,
|
||||
@@ -12,16 +12,16 @@ enum SubmenuIndex {
|
||||
SubmenuIndexDynamic, // dynamic indexes start here
|
||||
};
|
||||
|
||||
void nfc_scene_mifare_desfire_data_submenu_callback(void* context, uint32_t index) {
|
||||
void nfc_scene_mf_desfire_data_submenu_callback(void* context, uint32_t index) {
|
||||
Nfc* nfc = (Nfc*)context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_desfire_data_on_enter(void* context) {
|
||||
void nfc_scene_mf_desfire_data_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
|
||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData);
|
||||
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
||||
|
||||
text_box_set_font(nfc->text_box, TextBoxFontHex);
|
||||
@@ -30,7 +30,7 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) {
|
||||
submenu,
|
||||
"Card info",
|
||||
SubmenuIndexCardInfo,
|
||||
nfc_scene_mifare_desfire_data_submenu_callback,
|
||||
nfc_scene_mf_desfire_data_submenu_callback,
|
||||
nfc);
|
||||
|
||||
uint16_t cap = NFC_TEXT_STORE_SIZE;
|
||||
@@ -46,24 +46,23 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) {
|
||||
char* label = buf;
|
||||
cap -= size + 1;
|
||||
buf += size + 1;
|
||||
submenu_add_item(
|
||||
submenu, label, idx++, nfc_scene_mifare_desfire_data_submenu_callback, nfc);
|
||||
submenu_add_item(submenu, label, idx++, nfc_scene_mf_desfire_data_submenu_callback, nfc);
|
||||
}
|
||||
|
||||
if(state >= MifareDesfireDataStateItem) {
|
||||
submenu_set_selected_item(
|
||||
nfc->submenu, state - MifareDesfireDataStateItem + SubmenuIndexDynamic);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu);
|
||||
nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) {
|
||||
bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
|
||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData);
|
||||
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
@@ -75,23 +74,22 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager,
|
||||
NfcSceneMifareDesfireData,
|
||||
NfcSceneMfDesfireData,
|
||||
MifareDesfireDataStateItem + SubmenuIndexCardInfo);
|
||||
consumed = true;
|
||||
} else {
|
||||
uint16_t index = event.event - SubmenuIndexDynamic;
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateItem + index);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp);
|
||||
nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateItem + index);
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, index << 1);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp);
|
||||
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);
|
||||
nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
@@ -99,7 +97,7 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_desfire_data_on_exit(void* context) {
|
||||
void nfc_scene_mf_desfire_data_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear views
|
@@ -4,33 +4,32 @@ enum SubmenuIndex {
|
||||
SubmenuIndexSave,
|
||||
};
|
||||
|
||||
void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) {
|
||||
void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
|
||||
void nfc_scene_mf_desfire_menu_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_desfire_menu_submenu_callback, nfc);
|
||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc);
|
||||
submenu_set_selected_item(
|
||||
nfc->submenu,
|
||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireMenu));
|
||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu));
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexSave) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneMifareDesfireMenu, SubmenuIndexSave);
|
||||
nfc->scene_manager, NfcSceneMfDesfireMenu, SubmenuIndexSave);
|
||||
nfc->dev->format = NfcDeviceSaveFormatMifareDesfire;
|
||||
// Clear device name
|
||||
nfc_device_set_name(nfc->dev, "");
|
||||
@@ -42,7 +41,7 @@ bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent eve
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_desfire_menu_on_exit(void* context) {
|
||||
void nfc_scene_mf_desfire_menu_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear view
|
@@ -4,22 +4,22 @@
|
||||
#define NFC_SCENE_READ_SUCCESS_SHIFT " "
|
||||
|
||||
enum {
|
||||
ReadMifareDesfireSuccessStateShowUID,
|
||||
ReadMifareDesfireSuccessStateShowData,
|
||||
MfDesfireReadSuccessStateShowUID,
|
||||
MfDesfireReadSuccessStateShowData,
|
||||
};
|
||||
|
||||
void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) {
|
||||
void nfc_scene_mf_desfire_read_success_dialog_callback(DialogExResult result, void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
|
||||
void nfc_scene_mf_desfire_read_success_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
||||
dialog_ex_set_center_button_text(dialog_ex, "Data");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "More");
|
||||
dialog_ex_set_icon(dialog_ex, 8, 16, &I_Medium_chip_22x21);
|
||||
@@ -55,41 +55,40 @@ void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
|
||||
n_files == 1 ? "" : "s");
|
||||
dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 6, AlignLeft, AlignTop);
|
||||
dialog_ex_set_context(dialog_ex, nfc);
|
||||
dialog_ex_set_result_callback(
|
||||
dialog_ex, nfc_scene_read_mifare_desfire_success_dialog_callback);
|
||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_desfire_read_success_dialog_callback);
|
||||
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager,
|
||||
NfcSceneReadMifareDesfireSuccess,
|
||||
ReadMifareDesfireSuccessStateShowUID);
|
||||
nfc->scene_manager, NfcSceneMfDesfireReadSuccess, MfDesfireReadSuccessStateShowUID);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) {
|
||||
bool nfc_scene_mf_desfire_read_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);
|
||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireReadSuccess);
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) {
|
||||
scene_manager_previous_scene(nfc->scene_manager);
|
||||
if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultLeft) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
|
||||
consumed = true;
|
||||
} else if(
|
||||
state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultCenter) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireData);
|
||||
} else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultCenter) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData);
|
||||
consumed = true;
|
||||
} else if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultRight) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireMenu);
|
||||
} else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultRight) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireMenu);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
if(state == ReadMifareDesfireSuccessStateShowData) {
|
||||
if(state == MfDesfireReadSuccessStateShowData) {
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager,
|
||||
NfcSceneReadMifareDesfireSuccess,
|
||||
ReadMifareDesfireSuccessStateShowUID);
|
||||
NfcSceneMfDesfireReadSuccess,
|
||||
MfDesfireReadSuccessStateShowUID);
|
||||
consumed = true;
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
@@ -97,7 +96,7 @@ bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerE
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_mifare_desfire_success_on_exit(void* context) {
|
||||
void nfc_scene_mf_desfire_read_success_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clean dialog
|
@@ -4,51 +4,52 @@
|
||||
#define NFC_MF_UL_DATA_NOT_CHANGED (0UL)
|
||||
#define NFC_MF_UL_DATA_CHANGED (1UL)
|
||||
|
||||
void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
Nfc* nfc = context;
|
||||
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
|
||||
nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_CHANGED);
|
||||
return true;
|
||||
}
|
||||
|
||||
void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
|
||||
void nfc_scene_mf_ultralight_emulate_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = nfc->popup;
|
||||
if(strcmp(nfc->dev->dev_name, "")) {
|
||||
nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
|
||||
nfc_text_store_set(nfc, "Emulating\n%s", nfc->dev->dev_name);
|
||||
} else {
|
||||
nfc_text_store_set(nfc, "Emulating\nMf Ultralight", nfc->dev->dev_name);
|
||||
}
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||
popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop);
|
||||
popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop);
|
||||
|
||||
// Setup and start worker
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateEmulateMifareUltralight,
|
||||
NfcWorkerStateMfUltralightEmulate,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_emulate_mifare_ul_worker_callback,
|
||||
nfc_mf_ultralight_emulate_worker_callback,
|
||||
nfc);
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) {
|
||||
bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
// Check if data changed and save in shadow file
|
||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateMifareUl) ==
|
||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate) ==
|
||||
NFC_MF_UL_DATA_CHANGED) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED);
|
||||
nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_NOT_CHANGED);
|
||||
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
|
||||
}
|
||||
consumed = false;
|
||||
@@ -56,7 +57,7 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_emulate_mifare_ul_on_exit(void* context) {
|
||||
void nfc_scene_mf_ultralight_emulate_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear view
|
@@ -5,47 +5,47 @@ enum SubmenuIndex {
|
||||
SubmenuIndexEmulate,
|
||||
};
|
||||
|
||||
void nfc_scene_mifare_classic_menu_submenu_callback(void* context, uint32_t index) {
|
||||
void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_classic_menu_on_enter(void* context) {
|
||||
void nfc_scene_mf_ultralight_menu_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_classic_menu_submenu_callback, nfc);
|
||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Emulate",
|
||||
SubmenuIndexEmulate,
|
||||
nfc_scene_mifare_classic_menu_submenu_callback,
|
||||
nfc_scene_mf_ultralight_menu_submenu_callback,
|
||||
nfc);
|
||||
submenu_set_selected_item(
|
||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareUlMenu));
|
||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu));
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_mifare_classic_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexSave) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave);
|
||||
nfc->dev->format = NfcDeviceSaveFormatMifareClassic;
|
||||
nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexSave);
|
||||
nfc->dev->format = NfcDeviceSaveFormatMifareUl;
|
||||
// Clear device name
|
||||
nfc_device_set_name(nfc->dev, "");
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexEmulate) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic);
|
||||
nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexEmulate);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
@@ -56,7 +56,7 @@ bool nfc_scene_mifare_classic_menu_on_event(void* context, SceneManagerEvent eve
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mifare_classic_menu_on_exit(void* context) {
|
||||
void nfc_scene_mf_ultralight_menu_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear view
|
@@ -8,19 +8,16 @@ enum {
|
||||
ReadMifareUlStateShowData,
|
||||
};
|
||||
|
||||
void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) {
|
||||
void nfc_scene_mf_ultralight_read_success_dialog_callback(DialogExResult result, void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
|
||||
void nfc_scene_mf_ultralight_read_success_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||
|
||||
// Send notification
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
|
||||
// Setup dialog view
|
||||
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
|
||||
@@ -48,7 +45,7 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
|
||||
data->uid[6]);
|
||||
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_mifare_ul_success_dialog_callback);
|
||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_read_success_dialog_callback);
|
||||
|
||||
// Setup TextBox view
|
||||
TextBox* text_box = nfc->text_box;
|
||||
@@ -63,34 +60,37 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
|
||||
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
|
||||
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID);
|
||||
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) {
|
||||
bool nfc_scene_mf_ultralight_read_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);
|
||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
|
||||
scene_manager_previous_scene(nfc->scene_manager);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
|
||||
consumed = true;
|
||||
} else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultRight) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareUlMenu);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu);
|
||||
consumed = true;
|
||||
} else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultCenter) {
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowData);
|
||||
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowData);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
if(state == ReadMifareUlStateShowData) {
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID);
|
||||
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID);
|
||||
consumed = true;
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_mifare_ul_success_on_exit(void* context) {
|
||||
void nfc_scene_mf_ultralight_read_success_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clean views
|
108
applications/nfc/scenes/nfc_scene_read.c
Normal file
108
applications/nfc/scenes/nfc_scene_read.c
Normal file
@@ -0,0 +1,108 @@
|
||||
#include "../nfc_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
typedef enum {
|
||||
NfcSceneReadStateIdle,
|
||||
NfcSceneReadStateDetecting,
|
||||
NfcSceneReadStateReading,
|
||||
} NfcSceneReadState;
|
||||
|
||||
bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
if(event == NfcWorkerEventReadMfClassicLoadKeyCache) {
|
||||
consumed = nfc_device_load_key_cache(nfc->dev);
|
||||
} else {
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) {
|
||||
uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneRead);
|
||||
if(curr_state != state) {
|
||||
if(state == NfcSceneReadStateDetecting) {
|
||||
popup_set_header(nfc->popup, "Detecting\nNFC card", 90, 24, AlignCenter, AlignTop);
|
||||
popup_set_icon(nfc->popup, 5, 7, &I_NFC_manual);
|
||||
} else if(state == NfcSceneReadStateReading) {
|
||||
popup_set_header(
|
||||
nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop);
|
||||
popup_set_icon(nfc->popup, 19, 23, &A_Loading_24);
|
||||
}
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, state);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_scene_read_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||
|
||||
nfc_device_clear(nfc->dev);
|
||||
// Setup view
|
||||
nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
// Start worker
|
||||
nfc_worker_start(
|
||||
nfc->worker, NfcWorkerStateRead, &nfc->dev->dev_data, nfc_scene_read_worker_callback, nfc);
|
||||
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if((event.event == NfcWorkerEventReadUidNfcB) ||
|
||||
(event.event == NfcWorkerEventReadUidNfcF) ||
|
||||
(event.event == NfcWorkerEventReadUidNfcV) ||
|
||||
(event.event == NfcWorkerEventReadUidNfcA)) {
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventReadMfUltralight) {
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventReadMfClassicDone) {
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventReadMfDesfire) {
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventReadBankCard) {
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) {
|
||||
if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack);
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventCardDetected) {
|
||||
nfc_scene_read_set_state(nfc, NfcSceneReadStateReading);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventNoCardDetected) {
|
||||
nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
// Clear view
|
||||
popup_reset(nfc->popup);
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, NfcSceneReadStateIdle);
|
||||
|
||||
nfc_blink_stop(nfc);
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
#include "../nfc_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||
}
|
||||
|
||||
void nfc_scene_read_card_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = nfc->popup;
|
||||
popup_set_header(popup, "Detecting\nNFC card", 70, 34, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
||||
|
||||
// Start worker
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
nfc_worker_start(
|
||||
nfc->worker, NfcWorkerStateDetect, &nfc->dev->dev_data, nfc_read_card_worker_callback, nfc);
|
||||
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventWorkerExit) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_card_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
// Clear view
|
||||
popup_reset(nfc->popup);
|
||||
|
||||
nfc_blink_stop(nfc);
|
||||
}
|
@@ -22,9 +22,6 @@ void nfc_scene_read_card_success_on_enter(void* context) {
|
||||
string_init(uid_str);
|
||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||
|
||||
// Send notification
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
|
||||
// Setup view
|
||||
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||
Widget* widget = nfc->widget;
|
||||
@@ -38,18 +35,12 @@ void nfc_scene_read_card_success_on_enter(void* context) {
|
||||
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc);
|
||||
if(data->type == FuriHalNfcTypeA) {
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc);
|
||||
widget, GuiButtonTypeRight, "Save", nfc_scene_read_card_success_widget_callback, nfc);
|
||||
widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21);
|
||||
string_cat_printf(data_str, " may be:");
|
||||
widget_add_string_element(
|
||||
widget, 37, 12, AlignLeft, AlignBottom, FontPrimary, string_get_cstr(data_str));
|
||||
string_printf(
|
||||
data_str,
|
||||
"%s\nATQA: %02X%02X SAK: %02X",
|
||||
nfc_guess_protocol(nfc->dev->dev_data.protocol),
|
||||
data->atqa[0],
|
||||
data->atqa[1],
|
||||
data->sak);
|
||||
data_str, "ATQA: %02X%02X\nSAK: %02X", data->atqa[0], data->atqa[1], data->sak);
|
||||
widget_add_string_multiline_element(
|
||||
widget, 37, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str));
|
||||
widget_add_string_element(
|
||||
@@ -69,16 +60,15 @@ void nfc_scene_read_card_success_on_enter(void* context) {
|
||||
|
||||
bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) {
|
||||
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->type == FuriHalNfcTypeA && event.event == GuiButtonTypeRight) {
|
||||
// Clear device name
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
nfc->dev->format = NfcDeviceSaveFormatUid;
|
||||
nfc_device_set_name(nfc->dev, "");
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
@@ -1,58 +0,0 @@
|
||||
#include "../nfc_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||
}
|
||||
|
||||
void nfc_scene_read_emv_app_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = nfc->popup;
|
||||
popup_set_header(popup, "Reading\nbank card", 70, 34, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
// Start worker
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateReadEMVApp,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_read_emv_app_worker_callback,
|
||||
nfc);
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) {
|
||||
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);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_emv_app_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
|
||||
// Clear view
|
||||
popup_reset(nfc->popup);
|
||||
|
||||
nfc_blink_stop(nfc);
|
||||
}
|
@@ -1,83 +0,0 @@
|
||||
#include "../nfc_i.h"
|
||||
#include "../helpers/nfc_emv_parser.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
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 = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||
|
||||
// Setup view
|
||||
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 =
|
||||
nfc_emv_parser_get_aid_name(nfc->dev->storage, emv_data->aid, emv_data->aid_len, aid);
|
||||
if(!aid_found) {
|
||||
for(uint8_t i = 0; i < emv_data->aid_len; i++) {
|
||||
string_cat_printf(aid, "%02X", emv_data->aid[i]);
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
// Send notification
|
||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) ==
|
||||
NFC_SEND_NOTIFICATION_TRUE) {
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
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);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_emv_app_success_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear views
|
||||
widget_reset(nfc->widget);
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
#include "../nfc_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||
}
|
||||
|
||||
void nfc_scene_read_emv_data_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = nfc->popup;
|
||||
popup_set_header(popup, "Reading\nbank card", 70, 34, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
// Clear emv data
|
||||
memset(&nfc->dev->dev_data.emv_data, 0, sizeof(nfc->dev->dev_data.emv_data));
|
||||
// Start worker
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateReadEMVData,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_read_emv_data_worker_callback,
|
||||
nfc);
|
||||
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) {
|
||||
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);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_emv_data_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
// Clear view
|
||||
popup_reset(nfc->popup);
|
||||
|
||||
nfc_blink_stop(nfc);
|
||||
}
|
@@ -1,96 +0,0 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
enum {
|
||||
NfcSceneReadMifareClassicStateInProgress,
|
||||
NfcSceneReadMifareClassicStateDone,
|
||||
};
|
||||
|
||||
void nfc_read_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void nfc_read_mifare_classic_dict_attack_result_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackDone);
|
||||
}
|
||||
|
||||
void nfc_scene_read_mifare_classic_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Setup and start worker
|
||||
memset(&nfc->dev->dev_data.mf_classic_data, 0, sizeof(MfClassicData));
|
||||
dict_attack_set_result_callback(
|
||||
nfc->dict_attack, nfc_read_mifare_classic_dict_attack_result_callback, nfc);
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateInProgress);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack);
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateReadMifareClassic,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_read_mifare_classic_worker_callback,
|
||||
nfc);
|
||||
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_mifare_classic_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventDictAttackDone) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareClassicMenu);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventDetectedClassic1k) {
|
||||
dict_attack_card_detected(nfc->dict_attack, MfClassicType1k);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventDetectedClassic4k) {
|
||||
dict_attack_card_detected(nfc->dict_attack, MfClassicType4k);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventNewSector) {
|
||||
dict_attack_inc_curr_sector(nfc->dict_attack);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventFoundKeyA) {
|
||||
dict_attack_inc_found_key(nfc->dict_attack, MfClassicKeyA);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventFoundKeyB) {
|
||||
dict_attack_inc_found_key(nfc->dict_attack, MfClassicKeyB);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventNoCardDetected) {
|
||||
dict_attack_card_removed(nfc->dict_attack);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventSuccess) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateDone);
|
||||
nfc_blink_stop(nfc);
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
dict_attack_set_result(nfc->dict_attack, true);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventFail) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateDone);
|
||||
nfc_blink_stop(nfc);
|
||||
dict_attack_set_result(nfc->dict_attack, false);
|
||||
consumed = true;
|
||||
} else if(event.event == NfcWorkerEventNoDictFound) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_mifare_classic_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
dict_attack_reset(nfc->dict_attack);
|
||||
|
||||
nfc_blink_stop(nfc);
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
#include "../nfc_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||
}
|
||||
|
||||
void nfc_scene_read_mifare_desfire_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = nfc->popup;
|
||||
popup_set_header(popup, "Reading\nDESFire", 70, 34, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
// Start worker
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateReadMifareDesfire,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_read_mifare_desfire_worker_callback,
|
||||
nfc);
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventWorkerExit) {
|
||||
notification_message(nfc->notifications, &sequence_success);
|
||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_mifare_desfire_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
// Clear view
|
||||
popup_reset(nfc->popup);
|
||||
|
||||
nfc_blink_stop(nfc);
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
#include "../nfc_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void nfc_read_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
|
||||
UNUSED(event);
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||
}
|
||||
|
||||
void nfc_scene_read_mifare_ul_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||
|
||||
// Setup view
|
||||
Popup* popup = nfc->popup;
|
||||
popup_set_header(popup, "Detecting\nultralight", 70, 34, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
// Start worker
|
||||
nfc_worker_start(
|
||||
nfc->worker,
|
||||
NfcWorkerStateReadMifareUltralight,
|
||||
&nfc->dev->dev_data,
|
||||
nfc_read_mifare_ul_worker_callback,
|
||||
nfc);
|
||||
nfc_blink_start(nfc);
|
||||
}
|
||||
|
||||
bool nfc_scene_read_mifare_ul_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventWorkerExit) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_read_mifare_ul_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Stop worker
|
||||
nfc_worker_stop(nfc->worker);
|
||||
// Clear view
|
||||
popup_reset(nfc->popup);
|
||||
|
||||
nfc_blink_stop(nfc);
|
||||
}
|
47
applications/nfc/scenes/nfc_scene_retry_confirm.c
Normal file
47
applications/nfc/scenes/nfc_scene_retry_confirm.c
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
void nfc_scene_retry_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void nfc_scene_retry_confirm_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Stay");
|
||||
dialog_ex_set_header(dialog_ex, "Retry reading?", 64, 11, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "All unsaved data will be\nlost.", 64, 25, AlignCenter, AlignTop);
|
||||
dialog_ex_set_context(dialog_ex, nfc);
|
||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||
}
|
||||
|
||||
bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == DialogExResultRight) {
|
||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||
} else if(event.event == DialogExResultLeft) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneRead);
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_retry_confirm_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clean view
|
||||
dialog_ex_reset(nfc->dialog_ex);
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* 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 = context;
|
||||
|
||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Run");
|
||||
dialog_ex_set_header(dialog_ex, "Run EMV app?", 64, 8, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex,
|
||||
"It will try to run card's app\nand detect unencrypted\ndata",
|
||||
64,
|
||||
18,
|
||||
AlignCenter,
|
||||
AlignTop);
|
||||
dialog_ex_set_context(dialog_ex, nfc);
|
||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_run_emv_app_confirm_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||
}
|
||||
|
||||
bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == DialogExResultLeft) {
|
||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||
} else if(event.event == DialogExResultRight) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_run_emv_app_confirm_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clean view
|
||||
dialog_ex_reset(nfc->dialog_ex);
|
||||
}
|
@@ -27,13 +27,9 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneCardMenu)) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfDesfireMenu)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneCardMenu);
|
||||
} else if(scene_manager_has_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMifareDesfireMenu)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMifareDesfireMenu);
|
||||
nfc->scene_manager, NfcSceneMfDesfireMenu);
|
||||
} else {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneStart);
|
||||
|
@@ -61,9 +61,9 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event);
|
||||
if(event.event == SubmenuIndexEmulate) {
|
||||
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||
}
|
||||
|
@@ -1,82 +0,0 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexBankCard,
|
||||
SubmenuIndexMifareUltralight,
|
||||
SubmenuIdexReadMfClassic,
|
||||
SubmenuIndexMifareDesfire,
|
||||
};
|
||||
|
||||
void nfc_scene_scripts_menu_submenu_callback(void* context, uint32_t index) {
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_scripts_menu_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Read Bank Card",
|
||||
SubmenuIndexBankCard,
|
||||
nfc_scene_scripts_menu_submenu_callback,
|
||||
nfc);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Read Mifare Ultral/Ntag",
|
||||
SubmenuIndexMifareUltralight,
|
||||
nfc_scene_scripts_menu_submenu_callback,
|
||||
nfc);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Read Mifare Classic",
|
||||
SubmenuIdexReadMfClassic,
|
||||
nfc_scene_scripts_menu_submenu_callback,
|
||||
nfc);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Read Mifare DESFire",
|
||||
SubmenuIndexMifareDesfire,
|
||||
nfc_scene_scripts_menu_submenu_callback,
|
||||
nfc);
|
||||
submenu_set_selected_item(
|
||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneScriptsMenu));
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_scripts_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexBankCard) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexBankCard);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexMifareUltralight) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexMifareUltralight);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIdexReadMfClassic) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIdexReadMfClassic);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexMifareDesfire) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexMifareDesfire);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_scripts_menu_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
submenu_reset(nfc->submenu);
|
||||
}
|
@@ -2,8 +2,9 @@
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexRead,
|
||||
SubmenuIndexRunScript,
|
||||
SubmenuIndexDetectReader,
|
||||
SubmenuIndexSaved,
|
||||
SubmenuIndexExtraAction,
|
||||
SubmenuIndexAddManualy,
|
||||
SubmenuIndexDebug,
|
||||
};
|
||||
@@ -18,15 +19,12 @@ void nfc_scene_start_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Read Card", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Run Special Action",
|
||||
SubmenuIndexRunScript,
|
||||
nfc_scene_start_submenu_callback,
|
||||
nfc);
|
||||
submenu, "Detect Reader", SubmenuIndexDetectReader, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(submenu, "Saved", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Extra Actions", SubmenuIndexExtraAction, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Add Manually", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc);
|
||||
|
||||
@@ -48,14 +46,17 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexRead) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCard);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexRunScript) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu);
|
||||
} else if(event.event == SubmenuIndexDetectReader) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexSaved) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexExtraAction) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexAddManualy) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType);
|
||||
consumed = true;
|
||||
|
@@ -1,83 +1,60 @@
|
||||
#include "dict_attack.h"
|
||||
#include <m-string.h>
|
||||
|
||||
#include <m-string.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
typedef enum {
|
||||
DictAttackStateSearchCard,
|
||||
DictAttackStateSearchKeys,
|
||||
DictAttackStateRead,
|
||||
DictAttackStateCardRemoved,
|
||||
DictAttackStateSuccess,
|
||||
DictAttackStateFail,
|
||||
} DictAttackState;
|
||||
|
||||
struct DictAttack {
|
||||
View* view;
|
||||
DictAttackResultCallback callback;
|
||||
DictAttackCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
DictAttackState state;
|
||||
MfClassicType type;
|
||||
uint8_t current_sector;
|
||||
uint8_t total_sectors;
|
||||
uint8_t keys_a_found;
|
||||
uint8_t keys_a_total;
|
||||
uint8_t keys_b_found;
|
||||
uint8_t keys_b_total;
|
||||
string_t header;
|
||||
uint8_t sectors_total;
|
||||
uint8_t sectors_read;
|
||||
uint8_t sector_current;
|
||||
uint8_t keys_total;
|
||||
uint8_t keys_found;
|
||||
} DictAttackViewModel;
|
||||
|
||||
static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
DictAttackViewModel* m = model;
|
||||
if(m->state == DictAttackStateSearchCard) {
|
||||
if(m->state == DictAttackStateCardRemoved) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 32, AlignCenter, AlignCenter, "Detecting Mifare Classic");
|
||||
} else if(m->state == DictAttackStateCardRemoved) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 32, AlignCenter, AlignTop, "Place card back to flipper");
|
||||
} else {
|
||||
char draw_str[32];
|
||||
if(m->state == DictAttackStateSearchKeys) {
|
||||
snprintf(
|
||||
draw_str, sizeof(draw_str), "Searching keys for sector %d", m->current_sector);
|
||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, draw_str);
|
||||
} else if(m->state == DictAttackStateSuccess) {
|
||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Complete!");
|
||||
elements_button_right(canvas, "More");
|
||||
} else if(m->state == DictAttackStateFail) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 2, AlignCenter, AlignTop, "Failed to read any sector");
|
||||
}
|
||||
uint16_t keys_found = m->keys_a_found + m->keys_b_found;
|
||||
uint16_t keys_total = m->keys_a_total + m->keys_b_total;
|
||||
float progress = (float)(m->current_sector) / (float)(m->total_sectors);
|
||||
elements_progress_bar(canvas, 5, 12, 120, progress);
|
||||
canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(draw_str, sizeof(draw_str), "Total keys found: %d/%d", keys_found, keys_total);
|
||||
canvas_draw_str_aligned(canvas, 1, 23, AlignLeft, AlignTop, draw_str);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly.");
|
||||
} else if(m->state == DictAttackStateRead) {
|
||||
char draw_str[32] = {};
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, string_get_cstr(m->header));
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
float progress =
|
||||
m->sectors_total == 0 ? 0 : (float)(m->sector_current) / (float)(m->sectors_total);
|
||||
elements_progress_bar(canvas, 5, 15, 120, progress);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total);
|
||||
canvas_draw_str_aligned(canvas, 1, 28, AlignLeft, AlignTop, draw_str);
|
||||
snprintf(
|
||||
draw_str, sizeof(draw_str), "A keys found: %d/%d", m->keys_a_found, m->keys_a_total);
|
||||
canvas_draw_str_aligned(canvas, 1, 34, AlignLeft, AlignTop, draw_str);
|
||||
snprintf(
|
||||
draw_str, sizeof(draw_str), "B keys found: %d/%d", m->keys_b_found, m->keys_b_total);
|
||||
canvas_draw_str_aligned(canvas, 1, 45, AlignLeft, AlignTop, draw_str);
|
||||
draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total);
|
||||
canvas_draw_str_aligned(canvas, 1, 40, AlignLeft, AlignTop, draw_str);
|
||||
}
|
||||
elements_button_center(canvas, "Skip");
|
||||
}
|
||||
|
||||
static bool dict_attack_input_callback(InputEvent* event, void* context) {
|
||||
DictAttack* dict_attack = context;
|
||||
bool consumed = false;
|
||||
DictAttackState state;
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
state = model->state;
|
||||
return false;
|
||||
});
|
||||
if(state == DictAttackStateSuccess && event->type == InputTypeShort &&
|
||||
event->key == InputKeyRight) {
|
||||
if(event->type == InputTypeShort && event->key == InputKeyOk) {
|
||||
if(dict_attack->callback) {
|
||||
dict_attack->callback(dict_attack->context);
|
||||
}
|
||||
@@ -93,11 +70,21 @@ DictAttack* dict_attack_alloc() {
|
||||
view_set_draw_callback(dict_attack->view, dict_attack_draw_callback);
|
||||
view_set_input_callback(dict_attack->view, dict_attack_input_callback);
|
||||
view_set_context(dict_attack->view, dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
string_init(model->header);
|
||||
return false;
|
||||
});
|
||||
return dict_attack;
|
||||
}
|
||||
|
||||
void dict_attack_free(DictAttack* dict_attack) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
string_clear(model->header);
|
||||
return false;
|
||||
});
|
||||
view_free(dict_attack->view);
|
||||
free(dict_attack);
|
||||
}
|
||||
@@ -106,8 +93,15 @@ void dict_attack_reset(DictAttack* dict_attack) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
memset(model, 0, sizeof(DictAttackViewModel));
|
||||
return true;
|
||||
model->state = DictAttackStateRead;
|
||||
model->type = MfClassicType1k;
|
||||
model->sectors_total = 0;
|
||||
model->sectors_read = 0;
|
||||
model->sector_current = 0;
|
||||
model->keys_total = 0;
|
||||
model->keys_found = 0;
|
||||
string_reset(model->header);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -116,78 +110,88 @@ View* dict_attack_get_view(DictAttack* dict_attack) {
|
||||
return dict_attack->view;
|
||||
}
|
||||
|
||||
void dict_attack_set_result_callback(
|
||||
DictAttack* dict_attack,
|
||||
DictAttackResultCallback callback,
|
||||
void* context) {
|
||||
void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context) {
|
||||
furi_assert(dict_attack);
|
||||
furi_assert(callback);
|
||||
dict_attack->callback = callback;
|
||||
dict_attack->context = context;
|
||||
}
|
||||
|
||||
void dict_attack_card_detected(DictAttack* dict_attack, MfClassicType type) {
|
||||
void dict_attack_set_header(DictAttack* dict_attack, const char* header) {
|
||||
furi_assert(dict_attack);
|
||||
furi_assert(header);
|
||||
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
string_set_str(model->header, header);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
model->state = DictAttackStateSearchKeys;
|
||||
if(type == MfClassicType1k) {
|
||||
model->total_sectors = 16;
|
||||
model->keys_a_total = 16;
|
||||
model->keys_b_total = 16;
|
||||
} else if(type == MfClassicType4k) {
|
||||
model->total_sectors = 40;
|
||||
model->keys_a_total = 40;
|
||||
model->keys_b_total = 40;
|
||||
model->state = DictAttackStateRead;
|
||||
model->sectors_total = mf_classic_get_total_sectors_num(type);
|
||||
model->keys_total = model->sectors_total * 2;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_set_card_removed(DictAttack* dict_attack) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
model->state = DictAttackStateCardRemoved;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
model->sectors_read = sec_read;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
model->keys_found = keys_found;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
model->sector_current = curr_sec;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_inc_current_sector(DictAttack* dict_attack) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
if(model->sector_current < model->sectors_total) {
|
||||
model->sector_current++;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_card_removed(DictAttack* dict_attack) {
|
||||
void dict_attack_inc_keys_found(DictAttack* dict_attack) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
if(model->state == DictAttackStateSearchKeys) {
|
||||
model->state = DictAttackStateCardRemoved;
|
||||
} else {
|
||||
model->state = DictAttackStateSearchCard;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_inc_curr_sector(DictAttack* dict_attack) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
model->current_sector++;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_inc_found_key(DictAttack* dict_attack, MfClassicKey key) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
model->state = DictAttackStateSearchKeys;
|
||||
if(key == MfClassicKeyA) {
|
||||
model->keys_a_found++;
|
||||
} else if(key == MfClassicKeyB) {
|
||||
model->keys_b_found++;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void dict_attack_set_result(DictAttack* dict_attack, bool success) {
|
||||
furi_assert(dict_attack);
|
||||
with_view_model(
|
||||
dict_attack->view, (DictAttackViewModel * model) {
|
||||
if(success) {
|
||||
model->state = DictAttackStateSuccess;
|
||||
} else {
|
||||
model->state = DictAttackStateFail;
|
||||
if(model->keys_found < model->keys_total) {
|
||||
model->keys_found++;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
@@ -3,11 +3,11 @@
|
||||
#include <gui/view.h>
|
||||
#include <gui/modules/widget.h>
|
||||
|
||||
#include <lib/nfc_protocols/mifare_classic.h>
|
||||
#include <lib/nfc/protocols/mifare_classic.h>
|
||||
|
||||
typedef struct DictAttack DictAttack;
|
||||
|
||||
typedef void (*DictAttackResultCallback)(void* context);
|
||||
typedef void (*DictAttackCallback)(void* context);
|
||||
|
||||
DictAttack* dict_attack_alloc();
|
||||
|
||||
@@ -17,17 +17,20 @@ void dict_attack_reset(DictAttack* dict_attack);
|
||||
|
||||
View* dict_attack_get_view(DictAttack* dict_attack);
|
||||
|
||||
void dict_attack_set_result_callback(
|
||||
DictAttack* dict_attack,
|
||||
DictAttackResultCallback callback,
|
||||
void* context);
|
||||
void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context);
|
||||
|
||||
void dict_attack_card_detected(DictAttack* dict_attack, MfClassicType type);
|
||||
void dict_attack_set_header(DictAttack* dict_attack, const char* header);
|
||||
|
||||
void dict_attack_card_removed(DictAttack* dict_attack);
|
||||
void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type);
|
||||
|
||||
void dict_attack_inc_curr_sector(DictAttack* dict_attack);
|
||||
void dict_attack_set_card_removed(DictAttack* dict_attack);
|
||||
|
||||
void dict_attack_inc_found_key(DictAttack* dict_attack, MfClassicKey key);
|
||||
void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read);
|
||||
|
||||
void dict_attack_set_result(DictAttack* dict_attack, bool success);
|
||||
void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found);
|
||||
|
||||
void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec);
|
||||
|
||||
void dict_attack_inc_current_sector(DictAttack* dict_attack);
|
||||
|
||||
void dict_attack_inc_keys_found(DictAttack* dict_attack);
|
||||
|
Reference in New Issue
Block a user