[FL-1919] NFC rework with Flipper File Format ()

* nfc: allocate nfc device on heap
* nfc: rework save with flipper file format
* nfc: rework nfc device load with flipper file
* nfc: save AID length and data
* nfc: remove file worker usage
* nfc: format sources
* nfc: rework with flipper file format addons
* assets: update EMV resources with flipper file format
* nfc: rework EMV resources parsing with new file format
* assets: fix EMV AID file format
* nfc: fix nfc_device usage

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
gornekich 2021-11-09 00:55:06 +03:00 committed by GitHub
parent 54dc16134d
commit 90d450368c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1008 additions and 1070 deletions

@ -1,49 +1,80 @@
#include "nfc_emv_parser.h"
#include <lib/flipper_file/flipper_file.h>
#include <file-worker.h>
static const char* nfc_resources_header = "Flipper EMV resources";
static const uint32_t nfc_resources_file_version = 1;
static bool
nfc_emv_parser_get_value(const char* file_path, string_t key, char delimiter, string_t value) {
bool found = false;
FileWorker* file_worker = file_worker_alloc(true);
static bool nfc_emv_parser_search_data(
Storage* storage,
const char* file_name,
string_t key,
string_t data) {
bool parsed = false;
FlipperFile* file = flipper_file_alloc(storage);
string_t temp_str;
string_init(temp_str);
if(file_worker_open(file_worker, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
if(file_worker_get_value_from_key(file_worker, key, delimiter, value)) {
found = true;
}
}
do {
// Open file
if(!flipper_file_open_existing(file, file_name)) break;
// Read file header and version
uint32_t version = 0;
if(!flipper_file_read_header(file, temp_str, &version)) break;
if(string_cmp_str(temp_str, nfc_resources_header) ||
(version != nfc_resources_file_version))
break;
if(!flipper_file_read_string(file, string_get_cstr(key), data)) break;
parsed = true;
} while(false);
file_worker_close(file_worker);
file_worker_free(file_worker);
return found;
string_clear(temp_str);
flipper_file_free(file);
return parsed;
}
bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name) {
bool result = false;
bool nfc_emv_parser_get_aid_name(
Storage* storage,
uint8_t* aid,
uint8_t aid_len,
string_t aid_name) {
furi_assert(storage);
bool parsed = false;
string_t key;
string_init(key);
for(uint8_t i = 0; i < aid_len; i++) {
string_cat_printf(key, "%02X", aid[i]);
}
result = nfc_emv_parser_get_value("/ext/nfc/emv/aid.nfc", key, ' ', aid_name);
if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/aid.nfc", key, aid_name)) {
parsed = true;
}
string_clear(key);
return result;
return parsed;
}
bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name) {
bool result = false;
bool nfc_emv_parser_get_country_name(
Storage* storage,
uint16_t country_code,
string_t country_name) {
bool parsed = false;
string_t key;
string_init_printf(key, "%04X", country_code);
result = nfc_emv_parser_get_value("/ext/nfc/emv/country_code.nfc", key, ' ', country_name);
if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/country_code.nfc", key, country_name)) {
parsed = true;
}
string_clear(key);
return result;
return parsed;
}
bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name) {
bool result = false;
bool nfc_emv_parser_get_currency_name(
Storage* storage,
uint16_t currency_code,
string_t currency_name) {
bool parsed = false;
string_t key;
string_init_printf(key, "%04X", currency_code);
result = nfc_emv_parser_get_value("/ext/nfc/emv/currency_code.nfc", key, ' ', currency_name);
if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/currency_code.nfc", key, currency_name)) {
parsed = true;
}
string_clear(key);
return result;
return parsed;
}

@ -3,25 +3,39 @@
#include <stdint.h>
#include <stdbool.h>
#include <m-string.h>
#include <storage/storage.h>
/** Get EMV application name by number
* @param storage Storage instance
* @param aid - AID number array
* @param aid_len - AID length
* @param aid_name - string to keep AID name
* @return - true if AID found, false otherwies
*/
bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name);
bool nfc_emv_parser_get_aid_name(
Storage* storage,
uint8_t* aid,
uint8_t aid_len,
string_t aid_name);
/** Get country name by country code
* @param storage Storage instance
* @param country_code - ISO 3166 country code
* @param country_name - string to keep country name
* @return - true if country found, false otherwies
*/
bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name);
bool nfc_emv_parser_get_country_name(
Storage* storage,
uint16_t country_code,
string_t country_name);
/** Get currency name by currency code
* @param storage Storage instance
* @param currency_code - ISO 3166 currency code
* @param currency_name - string to keep currency name
* @return - true if currency found, false otherwies
*/
bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name);
bool nfc_emv_parser_get_currency_name(
Storage* storage,
uint16_t currency_code,
string_t currency_name);

@ -31,6 +31,9 @@ Nfc* nfc_alloc() {
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();
// Open GUI record
nfc->gui = furi_record_open("gui");
view_dispatcher_attach_to_gui(nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen);
@ -82,6 +85,9 @@ Nfc* nfc_alloc() {
void nfc_free(Nfc* nfc) {
furi_assert(nfc);
// Nfc device
nfc_device_free(nfc->dev);
// Submenu
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu);
submenu_free(nfc->submenu);
@ -154,8 +160,8 @@ int32_t nfc_app(void* p) {
char* args = p;
// Check argument and run corresponding scene
if((*args != '\0') && nfc_device_load(&nfc->dev, p)) {
if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
if((*args != '\0') && nfc_device_load(nfc->dev, p)) {
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);

@ -1,45 +1,38 @@
#include "nfc_device_i.h"
#include "nfc_device.h"
#include <file-worker.h>
#include <lib/toolbox/path.h>
#include <lib/toolbox/hex.h>
#define NFC_DEVICE_MAX_DATA_LEN 14
#include <lib/flipper_file/flipper_file.h>
static const char* nfc_app_folder = "/any/nfc";
static const char* nfc_app_extension = ".nfc";
static const char* nfc_app_shadow_extension = ".shd";
static const char* nfc_file_header = "Flipper NFC device";
static const uint32_t nfc_file_version = 2;
static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len, uint8_t delim_len) {
string_strim(str);
uint8_t nibble_high = 0;
uint8_t nibble_low = 0;
bool parsed = true;
for(uint16_t i = 0; i < len; i++) {
if(hex_char_to_hex_nibble(string_get_char(str, 0), &nibble_high) &&
hex_char_to_hex_nibble(string_get_char(str, 1), &nibble_low)) {
buff[i] = (nibble_high << 4) | nibble_low;
string_right(str, delim_len + 2);
} else {
parsed = false;
break;
}
}
return parsed;
NfcDevice* nfc_device_alloc() {
NfcDevice* nfc_dev = furi_alloc(sizeof(NfcDevice));
nfc_dev->storage = furi_record_open("storage");
nfc_dev->dialogs = furi_record_open("dialogs");
return nfc_dev;
}
uint16_t nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) {
void nfc_device_free(NfcDevice* nfc_dev) {
furi_assert(nfc_dev);
furi_record_close("storage");
furi_record_close("dialogs");
free(nfc_dev);
}
void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) {
if(dev->format == NfcDeviceSaveFormatUid) {
string_set_str(format_string, "UID\n");
string_set_str(format_string, "UID");
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
string_set_str(format_string, "Bank card\n");
string_set_str(format_string, "Bank card");
} else if(dev->format == NfcDeviceSaveFormatMifareUl) {
string_set_str(format_string, "Mifare Ultralight\n");
string_set_str(format_string, "Mifare Ultralight");
} else {
string_set_str(format_string, "Unknown\n");
string_set_str(format_string, "Unknown");
}
return string_size(format_string);
}
bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
@ -59,228 +52,166 @@ bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
return false;
}
uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string) {
NfcDeviceCommonData* uid_data = &dev->dev_data.nfc_data;
string_printf(uid_string, "UID len: %02X UID: ", dev->dev_data.nfc_data.uid_len);
for(uint8_t i = 0; i < uid_data->uid_len; i++) {
string_cat_printf(uid_string, "%02X ", uid_data->uid[i]);
}
string_cat_printf(
uid_string,
"ATQA: %02X %02X SAK: %02X\n",
uid_data->atqa[0],
uid_data->atqa[1],
uid_data->sak);
return string_size(uid_string);
}
bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string) {
NfcDeviceCommonData* uid_data = &dev->dev_data.nfc_data;
bool parsed = false;
do {
// strlen("UID len: ") = 9
string_right(uid_string, 9);
if(!nfc_device_read_hex(uid_string, &uid_data->uid_len, 1, 1)) {
break;
}
// strlen("UID: ") = 5
string_right(uid_string, 5);
if(!nfc_device_read_hex(uid_string, uid_data->uid, uid_data->uid_len, 1)) {
break;
}
// strlen("ATQA: ") = 6
string_right(uid_string, 6);
if(!nfc_device_read_hex(uid_string, uid_data->atqa, 2, 1)) {
break;
}
// strlen("SAK: ") = 5
string_right(uid_string, 5);
if(!nfc_device_read_hex(uid_string, &uid_data->sak, 1, 1)) {
break;
}
parsed = true;
} while(0);
return parsed;
}
uint16_t nfc_device_prepare_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string) {
static bool nfc_device_save_mifare_ul_data(FlipperFile* file, NfcDevice* dev) {
bool saved = false;
MifareUlData* data = &dev->dev_data.mf_ul_data;
string_printf(mifare_ul_string, "Signature:");
for(uint8_t i = 0; i < sizeof(data->signature); i++) {
string_cat_printf(mifare_ul_string, " %02X", data->signature[i]);
}
string_cat_printf(mifare_ul_string, "\nVersion:");
uint8_t* version = (uint8_t*)&data->version;
for(uint8_t i = 0; i < sizeof(data->version); i++) {
string_cat_printf(mifare_ul_string, " %02X", version[i]);
}
for(uint8_t i = 0; i < 3; i++) {
string_cat_printf(
mifare_ul_string,
"\nCounter %d: %lu Tearing flag %d: %02X",
i,
data->counter[i],
i,
data->tearing[i]);
}
string_cat_printf(mifare_ul_string, "\nData size: %d\n", data->data_size);
for(uint16_t i = 0; i < data->data_size; i += 4) {
string_cat_printf(
mifare_ul_string,
"%02X %02X %02X %02X\n",
data->data[i],
data->data[i + 1],
data->data[i + 2],
data->data[i + 3]);
}
return string_size(mifare_ul_string);
}
bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string) {
MifareUlData* data = &dev->dev_data.mf_ul_data;
uint16_t tearing_tmp = 0;
uint16_t cnt_num = 0;
size_t ws = 0;
int res = 0;
bool parsed = false;
string_t temp_str;
string_init(temp_str);
// Save Mifare Ultralight specific data
do {
// strlen("Signature: ") = 11
string_right(mifare_ul_string, 11);
if(!nfc_device_read_hex(mifare_ul_string, data->signature, sizeof(data->signature), 1)) {
if(!flipper_file_write_comment_cstr(file, "Mifare Ultralight specific data")) break;
if(!flipper_file_write_hex(file, "Signature", data->signature, sizeof(data->signature)))
break;
}
// strlen("Version: ") = 9
string_right(mifare_ul_string, 9);
if(!nfc_device_read_hex(
mifare_ul_string, (uint8_t*)&data->version, sizeof(data->version), 1)) {
if(!flipper_file_write_hex(
file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version)))
break;
}
string_strim(mifare_ul_string);
// Read counters and tearing flags
// Write conters and tearing flags data
bool counters_saved = true;
for(uint8_t i = 0; i < 3; i++) {
res = sscanf(
string_get_cstr(mifare_ul_string),
"Counter %hX: %lu Tearing flag %hX: %02hX",
&cnt_num,
&data->counter[i],
&cnt_num,
&tearing_tmp);
if(res != 4) {
string_printf(temp_str, "Counter %d", i);
if(!flipper_file_write_uint32(file, string_get_cstr(temp_str), &data->counter[i], 1)) {
counters_saved = false;
break;
}
string_printf(temp_str, "Tearing %d", i);
if(!flipper_file_write_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) {
counters_saved = false;
break;
}
data->tearing[i] = tearing_tmp;
ws = string_search_char(mifare_ul_string, '\n');
string_right(mifare_ul_string, ws + 1);
}
// Read data size
res = sscanf(string_get_cstr(mifare_ul_string), "Data size: %hu", &data->data_size);
if(res != 1) {
break;
}
ws = string_search_char(mifare_ul_string, '\n');
string_right(mifare_ul_string, ws + 1);
// Read data
if(!counters_saved) break;
// Write pages data
uint32_t pages_total = data->data_size / 4;
if(!flipper_file_write_uint32(file, "Pages total", &pages_total, 1)) break;
bool pages_saved = true;
for(uint16_t i = 0; i < data->data_size; i += 4) {
if(!nfc_device_read_hex(mifare_ul_string, &data->data[i], 4, 1)) {
string_printf(temp_str, "Page %d", i / 4);
if(!flipper_file_write_hex(file, string_get_cstr(temp_str), &data->data[i], 4)) {
pages_saved = false;
break;
}
}
parsed = true;
} while(0);
if(!pages_saved) break;
saved = true;
} while(false);
string_clear(temp_str);
return saved;
}
bool nfc_device_load_mifare_ul_data(FlipperFile* file, NfcDevice* dev) {
bool parsed = false;
MifareUlData* data = &dev->dev_data.mf_ul_data;
string_t temp_str;
string_init(temp_str);
do {
// Read signature
if(!flipper_file_read_hex(file, "Signature", data->signature, sizeof(data->signature)))
break;
// Read Mifare version
if(!flipper_file_read_hex(
file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version)))
break;
// Read counters and tearing flags
bool counters_parsed = true;
for(uint8_t i = 0; i < 3; i++) {
string_printf(temp_str, "Counter %d", i);
if(!flipper_file_read_uint32(file, string_get_cstr(temp_str), &data->counter[i], 1)) {
counters_parsed = false;
break;
}
string_printf(temp_str, "Tearing %d", i);
if(!flipper_file_read_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) {
counters_parsed = false;
break;
}
}
if(!counters_parsed) break;
// Read pages
uint32_t pages = 0;
if(!flipper_file_read_uint32(file, "Pages total", &pages, 1)) break;
data->data_size = pages * 4;
bool pages_parsed = true;
for(uint16_t i = 0; i < pages; i++) {
string_printf(temp_str, "Page %d", i);
if(!flipper_file_read_hex(file, string_get_cstr(temp_str), &data->data[i * 4], 4)) {
pages_parsed = false;
break;
}
}
if(!pages_parsed) break;
parsed = true;
} while(false);
string_clear(temp_str);
return parsed;
}
uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_string) {
static bool nfc_device_save_bank_card_data(FlipperFile* file, NfcDevice* dev) {
bool saved = false;
NfcEmvData* data = &dev->dev_data.emv_data;
string_printf(bank_card_string, "AID len: %d, AID:", data->aid_len);
for(uint8_t i = 0; i < data->aid_len; i++) {
string_cat_printf(bank_card_string, " %02X", data->aid[i]);
}
string_cat_printf(
bank_card_string, "\nName: %s\nNumber len: %d\nNumber:", data->name, data->number_len);
for(uint8_t i = 0; i < data->number_len; i++) {
string_cat_printf(bank_card_string, " %02X", data->number[i]);
}
if(data->exp_mon) {
string_cat_printf(
bank_card_string, "\nExp date: %02X/%02X", data->exp_mon, data->exp_year);
}
if(data->country_code) {
string_cat_printf(bank_card_string, "\nCountry code: %04X", data->country_code);
}
if(data->currency_code) {
string_cat_printf(bank_card_string, "\nCurrency code: %04X", data->currency_code);
}
return string_size(bank_card_string);
}
bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string) {
NfcEmvData* data = &dev->dev_data.emv_data;
bool parsed = false;
int res = 0;
uint8_t code[2] = {};
memset(data, 0, sizeof(NfcEmvData));
uint32_t data_temp = 0;
do {
res = sscanf(string_get_cstr(bank_card_string), "AID len: %hu", &data->aid_len);
if(res != 1) {
break;
// Write Bank card specific data
if(!flipper_file_write_comment_cstr(file, "Bank card specific data")) break;
if(!flipper_file_write_hex(file, "AID", data->aid, data->aid_len)) break;
if(!flipper_file_write_string_cstr(file, "Name", data->name)) break;
if(!flipper_file_write_hex(file, "Number", data->number, data->number_len)) break;
if(data->exp_mon) {
uint8_t exp_data[2] = {data->exp_mon, data->exp_year};
if(!flipper_file_write_hex(file, "Exp data", exp_data, sizeof(exp_data))) break;
}
// strlen("AID len: ") = 9
string_right(bank_card_string, 9);
size_t ws = string_search_char(bank_card_string, ':');
string_right(bank_card_string, ws + 1);
if(!nfc_device_read_hex(bank_card_string, data->aid, data->aid_len, 1)) {
break;
if(data->country_code) {
data_temp = data->country_code;
if(!flipper_file_write_uint32(file, "Country code", &data_temp, 1)) break;
}
res = sscanf(string_get_cstr(bank_card_string), "Name: %s\n", data->name);
if(res != 1) {
break;
if(data->currency_code) {
data_temp = data->currency_code;
if(!flipper_file_write_uint32(file, "Currency code", &data_temp, 1)) break;
}
ws = string_search_char(bank_card_string, '\n');
string_right(bank_card_string, ws + 1);
res = sscanf(string_get_cstr(bank_card_string), "Number len: %hhu", &data->number_len);
if(res != 1) {
break;
}
ws = string_search_char(bank_card_string, '\n');
string_right(bank_card_string, ws + 1);
// strlen("Number: ") = 8
string_right(bank_card_string, 8);
if(!nfc_device_read_hex(bank_card_string, data->number, data->number_len, 1)) {
break;
}
parsed = true;
// Check expiration date presence
ws = string_search_str(bank_card_string, "Exp date: ");
if(ws != STRING_FAILURE) {
// strlen("Exp date: ") = 10
string_right(bank_card_string, 10);
nfc_device_read_hex(bank_card_string, &data->exp_mon, 1, 1);
nfc_device_read_hex(bank_card_string, &data->exp_year, 1, 1);
}
// Check country code presence
ws = string_search_str(bank_card_string, "Country code: ");
if(ws != STRING_FAILURE) {
// strlen("Country code: ") = 14
string_right(bank_card_string, 14);
nfc_device_read_hex(bank_card_string, code, 2, 0);
data->country_code = code[0] << 8 | code[1];
}
// Check currency code presence
ws = string_search_str(bank_card_string, "Currency code: ");
if(ws != STRING_FAILURE) {
// strlen("Currency code: ") = 15
string_right(bank_card_string, 15);
nfc_device_read_hex(bank_card_string, code, 2, 0);
data->currency_code = code[0] << 8 | code[1];
}
} while(0);
saved = true;
} while(false);
return saved;
}
bool nfc_device_load_bank_card_data(FlipperFile* file, NfcDevice* dev) {
bool parsed = false;
NfcEmvData* data = &dev->dev_data.emv_data;
memset(data, 0, sizeof(NfcEmvData));
uint32_t data_cnt = 0;
string_t temp_str;
string_init(temp_str);
do {
// Load essential data
if(!flipper_file_get_value_count(file, "AID", &data_cnt)) break;
data->aid_len = data_cnt;
if(!flipper_file_read_hex(file, "AID", data->aid, data->aid_len)) break;
if(!flipper_file_read_string(file, "Name", temp_str)) break;
strlcpy(data->name, string_get_cstr(temp_str), sizeof(data->name));
if(!flipper_file_get_value_count(file, "Number", &data_cnt)) break;
data->number_len = data_cnt;
if(!flipper_file_read_hex(file, "Number", data->number, data->number_len)) break;
parsed = true;
// Load optional data
uint8_t exp_data[2] = {};
if(flipper_file_read_hex(file, "Exp data", exp_data, 2)) {
data->exp_mon = exp_data[0];
data->exp_year = exp_data[1];
}
if(flipper_file_read_uint32(file, "Country code", &data_cnt, 1)) {
data->country_code = data_cnt;
}
if(flipper_file_read_uint32(file, "Currency code", &data_cnt, 1)) {
data->currency_code = data_cnt;
}
} while(false);
string_clear(temp_str);
return parsed;
}
@ -297,58 +228,49 @@ static bool nfc_device_save_file(
const char* extension) {
furi_assert(dev);
FileWorker* file_worker = file_worker_alloc(false);
string_t dev_file_name;
string_init(dev_file_name);
bool saved = false;
FlipperFile* file = flipper_file_alloc(dev->storage);
NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
string_t temp_str;
string_init(temp_str);
uint16_t string_len = 0;
do {
// Create nfc directory if necessary
if(!file_worker_mkdir(file_worker, nfc_app_folder)) {
break;
};
if(!storage_simply_mkdir(dev->storage, nfc_app_folder)) break;
// First remove nfc device file if it was saved
string_printf(dev_file_name, "%s/%s%s", folder, dev_name, extension);
if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) {
break;
};
string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
// Open file
if(!file_worker_open(
file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
if(!flipper_file_open_always(file, string_get_cstr(temp_str))) break;
// Write header
if(!flipper_file_write_header_cstr(file, nfc_file_header, nfc_file_version)) break;
// Write nfc device type
if(!flipper_file_write_comment_cstr(
file, "Nfc device type can be UID, Mifare Ultralight, Bank card"))
break;
}
// Prepare and write format name on 1st line
string_len = nfc_device_prepare_format_string(dev, temp_str);
if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) {
nfc_device_prepare_format_string(dev, temp_str);
if(!flipper_file_write_string(file, "Device type", temp_str)) break;
// Write UID, ATQA, SAK
if(!flipper_file_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
break;
}
// Prepare and write UID data on 2nd line
string_len = nfc_device_prepare_uid_string(dev, temp_str);
if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) {
break;
}
if(!flipper_file_write_hex(file, "UID", data->uid, data->uid_len)) break;
if(!flipper_file_write_hex(file, "ATQA", data->atqa, 2)) break;
if(!flipper_file_write_hex(file, "SAK", &data->sak, 1)) break;
// Save more data if necessary
if(dev->format == NfcDeviceSaveFormatMifareUl) {
string_len = nfc_device_prepare_mifare_ul_string(dev, temp_str);
if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) {
break;
}
if(!nfc_device_save_mifare_ul_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
string_len = nfc_device_prepare_bank_card_string(dev, temp_str);
if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) {
break;
}
if(!nfc_device_save_bank_card_data(file, dev)) break;
}
saved = true;
} while(0);
if(!saved) {
dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file");
}
string_clear(temp_str);
string_clear(dev_file_name);
file_worker_close(file_worker);
file_worker_free(file_worker);
return true;
flipper_file_close(file);
flipper_file_free(file);
return saved;
}
bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
@ -360,73 +282,64 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_shadow_extension);
}
static bool nfc_device_load_data(FileWorker* file_worker, string_t path, NfcDevice* dev) {
string_t temp_string;
string_init(temp_string);
static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
bool parsed = false;
FlipperFile* file = flipper_file_alloc(dev->storage);
NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
uint32_t data_cnt = 0;
string_t temp_str;
string_init(temp_str);
bool depricated_version = false;
do {
// Check existance of shadow file
size_t ext_start = string_search_str(path, nfc_app_extension);
string_set_n(temp_string, path, 0, ext_start);
string_cat_printf(temp_string, "%s", nfc_app_shadow_extension);
if(!file_worker_is_file_exist(
file_worker, string_get_cstr(temp_string), &dev->shadow_file_exist)) {
break;
}
string_set_n(temp_str, path, 0, ext_start);
string_cat_printf(temp_str, "%s", nfc_app_shadow_extension);
dev->shadow_file_exist =
storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) == FSE_OK;
// Open shadow file if it exists. If not - open original
if(dev->shadow_file_exist) {
if(!file_worker_open(
file_worker, string_get_cstr(temp_string), FSAM_READ, FSOM_OPEN_EXISTING)) {
break;
}
if(!flipper_file_open_existing(file, string_get_cstr(temp_str))) break;
} else {
if(!file_worker_open(
file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
break;
}
if(!flipper_file_open_existing(file, string_get_cstr(path))) break;
}
// Read and parse format from 1st line
if(!file_worker_read_until(file_worker, temp_string, '\n')) {
break;
}
if(!nfc_device_parse_format_string(dev, temp_string)) {
break;
}
// Read and parse UID data from 2nd line
if(!file_worker_read_until(file_worker, temp_string, '\n')) {
break;
}
if(!nfc_device_parse_uid_string(dev, temp_string)) {
// Read and verify file header
uint32_t version = 0;
if(!flipper_file_read_header(file, temp_str, &version)) break;
if(string_cmp_str(temp_str, nfc_file_header) || (version != nfc_file_version)) {
depricated_version = true;
break;
}
// Read Nfc device type
if(!flipper_file_read_string(file, "Device type", temp_str)) break;
if(!nfc_device_parse_format_string(dev, temp_str)) break;
// Read and parse UID, ATQA and SAK
if(!flipper_file_get_value_count(file, "UID", &data_cnt)) break;
data->uid_len = data_cnt;
if(!flipper_file_read_hex(file, "UID", data->uid, data->uid_len)) break;
if(!flipper_file_read_hex(file, "ATQA", data->atqa, 2)) break;
if(!flipper_file_read_hex(file, "SAK", &data->sak, 1)) break;
// Parse other data
if(dev->format == NfcDeviceSaveFormatMifareUl) {
// Read until EOF
if(!file_worker_read_until(file_worker, temp_string, 0x05)) {
break;
}
if(!nfc_device_parse_mifare_ul_string(dev, temp_string)) {
break;
}
if(!nfc_device_load_mifare_ul_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
// Read until EOF
if(!file_worker_read_until(file_worker, temp_string, 0x05)) {
break;
}
if(!nfc_device_parse_bank_card_string(dev, temp_string)) {
break;
}
if(!nfc_device_load_bank_card_data(file, dev)) break;
}
parsed = true;
} while(0);
} while(false);
if(!parsed) {
file_worker_show_error(file_worker, "Can not parse\nfile");
if(depricated_version) {
dialog_message_show_storage_error(dev->dialogs, "File format depricated");
} else {
dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile");
}
}
string_clear(temp_string);
string_clear(temp_str);
flipper_file_close(file);
flipper_file_free(file);
return parsed;
}
@ -434,19 +347,16 @@ bool nfc_device_load(NfcDevice* dev, const char* file_path) {
furi_assert(dev);
furi_assert(file_path);
FileWorker* file_worker = file_worker_alloc(false);
// Load device data
string_t path;
string_init_set_str(path, file_path);
bool dev_load = nfc_device_load_data(file_worker, path, dev);
bool dev_load = nfc_device_load_data(dev, path);
if(dev_load) {
// Set device name
path_extract_filename_no_ext(file_path, path);
nfc_device_set_name(dev, string_get_cstr(path));
}
string_clear(path);
file_worker_close(file_worker);
file_worker_free(file_worker);
return dev_load;
}
@ -454,10 +364,9 @@ bool nfc_device_load(NfcDevice* dev, const char* file_path) {
bool nfc_file_select(NfcDevice* dev) {
furi_assert(dev);
FileWorker* file_worker = file_worker_alloc(false);
// Input events and views are managed by file_select
bool res = file_worker_file_select(
file_worker,
bool res = dialog_file_select_show(
dev->dialogs,
nfc_app_folder,
nfc_app_extension,
dev->file_name,
@ -465,18 +374,14 @@ bool nfc_file_select(NfcDevice* dev) {
dev->dev_name);
if(res) {
string_t dev_str;
// Get key file path
string_init_printf(dev_str, "%s/%s%s", nfc_app_folder, dev->file_name, nfc_app_extension);
res = nfc_device_load_data(file_worker, dev_str, dev);
res = nfc_device_load_data(dev, dev_str);
if(res) {
nfc_device_set_name(dev, dev->file_name);
}
string_clear(dev_str);
}
file_worker_close(file_worker);
file_worker_free(file_worker);
return res;
}
@ -491,61 +396,48 @@ void nfc_device_clear(NfcDevice* dev) {
bool nfc_device_delete(NfcDevice* dev) {
furi_assert(dev);
bool result = true;
FileWorker* file_worker = file_worker_alloc(false);
bool deleted = false;
string_t file_path;
string_init(file_path);
do {
// Delete original file
string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
if(!file_worker_remove(file_worker, string_get_cstr(file_path))) {
result = false;
break;
}
if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
// Delete shadow file if it exists
if(dev->shadow_file_exist) {
string_clean(file_path);
string_printf(
file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension);
if(!file_worker_remove(file_worker, string_get_cstr(file_path))) {
result = false;
break;
}
if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
}
deleted = true;
} while(0);
if(!deleted) {
dialog_message_show_storage_error(dev->dialogs, "Can not remove file");
}
string_clear(file_path);
file_worker_close(file_worker);
file_worker_free(file_worker);
return result;
return deleted;
}
bool nfc_device_restore(NfcDevice* dev) {
furi_assert(dev);
furi_assert(dev->shadow_file_exist);
bool result = true;
FileWorker* file_worker = file_worker_alloc(false);
bool restored = false;
string_t path;
do {
string_init_printf(
path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension);
if(!file_worker_remove(file_worker, string_get_cstr(path))) {
result = false;
break;
}
if(!storage_simply_remove(dev->storage, string_get_cstr(path))) break;
dev->shadow_file_exist = false;
string_clean(path);
string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
if(!nfc_device_load_data(file_worker, path, dev)) {
result = false;
break;
}
if(!nfc_device_load_data(dev, path)) break;
restored = true;
} while(0);
string_clear(path);
file_worker_close(file_worker);
file_worker_free(file_worker);
return result;
return restored;
}

@ -2,6 +2,8 @@
#include <stdint.h>
#include <stdbool.h>
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include "mifare_ultralight.h"
@ -57,6 +59,8 @@ typedef struct {
} NfcDeviceData;
typedef struct {
Storage* storage;
DialogsApp* dialogs;
NfcDeviceData dev_data;
char dev_name[NFC_DEV_NAME_MAX_LEN + 1];
char file_name[NFC_FILE_NAME_MAX_LEN];
@ -64,6 +68,10 @@ typedef struct {
bool shadow_file_exist;
} 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);

@ -1,16 +0,0 @@
#pragma once
#include "nfc_device.h"
#include <m-string.h>
uint16_t nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string);
bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string);
uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string);
bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string);
uint16_t nfc_device_prepare_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string);
bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string);
uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_string);
bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string);

@ -36,7 +36,7 @@ struct Nfc {
Gui* gui;
NotificationApp* notifications;
SceneManager* scene_manager;
NfcDevice dev;
NfcDevice* dev;
NfcDeviceCommonData dev_edit_data;
char text_store[NFC_TEXT_STORE_SIZE + 1];

@ -248,6 +248,8 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
NFC_WORKER_TAG, "Select PPSE response received. Start parsing response");
if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) {
FURI_LOG_I(NFC_WORKER_TAG, "Select PPSE responce parced");
result->emv_data.aid_len = emv_app.aid_len;
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
} else {
FURI_LOG_E(NFC_WORKER_TAG, "Can't find pay application");
furi_hal_nfc_deactivate();

@ -17,7 +17,7 @@ void nfc_scene_card_menu_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Submenu* submenu = nfc->submenu;
if(nfc->dev.dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) {
if(nfc->dev->dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) {
submenu_add_item(
submenu,
"Run compatible app",
@ -48,9 +48,9 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
if(event.event == SubmenuIndexRunApp) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp);
if(nfc->dev.dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) {
if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
} else if(nfc->dev.dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) {
} else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
}
return true;
@ -66,7 +66,7 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
return true;
} else if(event.event == SubmenuIndexSave) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexSave);
nfc->dev.format = NfcDeviceSaveFormatUid;
nfc->dev->format = NfcDeviceSaveFormatUid;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true;
}

@ -12,14 +12,14 @@ void nfc_scene_delete_on_enter(void* context) {
// Setup Custom Widget view
char delete_str[64];
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s\e#", nfc->dev.dev_name);
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s\e#", nfc->dev->dev_name);
widget_add_text_box_element(nfc->widget, 0, 0, 128, 24, AlignCenter, AlignCenter, delete_str);
widget_add_button_element(
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc);
widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc);
char uid_str[32];
NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data;
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
if(data->uid_len == 4) {
snprintf(
uid_str,
@ -73,7 +73,7 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
if(event.event == GuiButtonTypeLeft) {
return scene_manager_previous_scene(nfc->scene_manager);
} else if(event.event == GuiButtonTypeRight) {
if(nfc_device_delete(&nfc->dev)) {
if(nfc_device_delete(nfc->dev)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess);
} else {
scene_manager_search_and_switch_to_previous_scene(

@ -1,4 +1,5 @@
#include "../nfc_i.h"
#include "../helpers/nfc_emv_parser.h"
#define NFC_SCENE_DEVICE_INFO_BACK_EVENT (0UL)
@ -36,13 +37,13 @@ void nfc_scene_device_info_on_enter(void* context) {
// Setup Custom Widget view
widget_add_text_box_element(
nfc->widget, 0, 0, 128, 24, AlignCenter, AlignCenter, nfc->dev.dev_name);
nfc->widget, 0, 0, 128, 24, AlignCenter, AlignCenter, nfc->dev->dev_name);
widget_add_button_element(
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc);
widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc);
char uid_str[32];
NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data;
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
if(data->uid_len == 4) {
snprintf(
uid_str,
@ -87,14 +88,14 @@ void nfc_scene_device_info_on_enter(void* context) {
widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, atqa_str);
// Setup Data View
if(nfc->dev.format == NfcDeviceSaveFormatUid) {
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Back");
dialog_ex_set_text(dialog_ex, "No data", 64, 32, AlignCenter, AlignCenter);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback);
} else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
MifareUlData* mf_ul_data = (MifareUlData*)&nfc->dev.dev_data.mf_ul_data;
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
TextBox* text_box = nfc->text_box;
text_box_set_context(text_box, nfc);
text_box_set_exit_callback(text_box, nfc_scene_device_info_text_box_callback);
@ -107,8 +108,8 @@ void nfc_scene_device_info_on_enter(void* context) {
nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]);
}
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
} else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) {
NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data;
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
BankCard* bank_card = nfc->bank_card;
bank_card_set_name(bank_card, emv_data->name);
bank_card_set_number(bank_card, emv_data->number, emv_data->number_len);
@ -116,12 +117,29 @@ void nfc_scene_device_info_on_enter(void* context) {
if(emv_data->exp_mon) {
bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year);
}
string_t display_str;
string_init(display_str);
if(emv_data->country_code) {
bank_card_set_country_name(bank_card, emv_data->country_code);
string_t country_name;
string_init(country_name);
if(nfc_emv_parser_get_country_name(
nfc->dev->storage, emv_data->country_code, country_name)) {
string_printf(display_str, "Reg:%s", string_get_cstr(country_name));
bank_card_set_country_name(bank_card, string_get_cstr(display_str));
}
string_clear(country_name);
}
if(emv_data->currency_code) {
bank_card_set_currency_name(bank_card, emv_data->currency_code);
string_t currency_name;
string_init(currency_name);
if(nfc_emv_parser_get_currency_name(
nfc->dev->storage, emv_data->country_code, currency_name)) {
string_printf(display_str, "Cur:%s", string_get_cstr(currency_name));
bank_card_set_currency_name(bank_card, string_get_cstr(display_str));
}
string_clear(currency_name);
}
string_clear(display_str);
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
@ -136,17 +154,17 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeLeft)) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
} else if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeRight)) {
if(nfc->dev.format == NfcDeviceSaveFormatUid) {
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
consumed = true;
} else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
consumed = true;
} else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) {
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard);
@ -168,7 +186,7 @@ void nfc_scene_device_info_on_exit(void* context) {
// Clear Custom Widget
widget_clear(nfc->widget);
if(nfc->dev.format == NfcDeviceSaveFormatUid) {
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
// Clear Dialog
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
@ -179,11 +197,11 @@ void nfc_scene_device_info_on_exit(void* context) {
dialog_ex_set_center_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
} else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
// Clear TextBox
text_box_clean(nfc->text_box);
string_clean(nfc->text_box_store);
} else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) {
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
// Clear Bank Card
bank_card_clear(nfc->bank_card);
}

@ -11,7 +11,7 @@ void nfc_scene_emulate_apdu_sequence_on_enter(void* context) {
// Setup and start worker
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev.dev_data, NULL, nfc);
nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc);
}
bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) {

@ -14,8 +14,8 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
// Setup view
Popup* popup = nfc->popup;
if(strcmp(nfc->dev.dev_name, "")) {
nfc_text_store_set(nfc, "%s", nfc->dev.dev_name);
if(strcmp(nfc->dev->dev_name, "")) {
nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
}
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop);
@ -25,7 +25,7 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
nfc_worker_start(
nfc->worker,
NfcWorkerStateEmulateMifareUl,
&nfc->dev.dev_data,
&nfc->dev->dev_data,
nfc_emulate_mifare_ul_worker_callback,
nfc);
}
@ -45,7 +45,7 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event
NFC_MF_UL_DATA_CHANGED) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED);
nfc_device_save_shadow(&nfc->dev, nfc->dev.dev_name);
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
}
consumed = false;
}

@ -5,10 +5,10 @@ void nfc_scene_emulate_uid_on_enter(void* context) {
// Setup view
Popup* popup = nfc->popup;
NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data;
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
if(strcmp(nfc->dev.dev_name, "")) {
nfc_text_store_set(nfc, "%s", nfc->dev.dev_name);
if(strcmp(nfc->dev->dev_name, "")) {
nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
} else if(data->uid_len == 4) {
nfc_text_store_set(
nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]);
@ -32,7 +32,7 @@ void nfc_scene_emulate_uid_on_enter(void* context) {
// Setup and start worker
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
nfc_worker_start(nfc->worker, NfcWorkerStateEmulate, &nfc->dev.dev_data, NULL, nfc);
nfc_worker_start(nfc->worker, NfcWorkerStateEmulate, &nfc->dev->dev_data, NULL, nfc);
}
bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) {

@ -3,7 +3,7 @@
void nfc_scene_file_select_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
// Process file_select return
if(nfc_file_select(&nfc->dev)) {
if(nfc_file_select(nfc->dev)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
} else {
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);

@ -32,9 +32,9 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
if(event.event == SubmenuIndexSave) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave);
nfc->dev.format = NfcDeviceSaveFormatMifareUl;
nfc->dev->format = NfcDeviceSaveFormatMifareUl;
// Clear device name
nfc_device_set_name(&nfc->dev, "");
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true;
} else if(event.event == SubmenuIndexEmulate) {

@ -18,7 +18,7 @@ void nfc_scene_read_card_on_enter(void* context) {
// 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->worker, NfcWorkerStateDetect, &nfc->dev->dev_data, nfc_read_card_worker_callback, nfc);
}
bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {

@ -15,7 +15,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
notification_message(nfc->notifications, &sequence_success);
// Setup view
NfcDeviceCommonData* data = (NfcDeviceCommonData*)&nfc->dev.dev_data.nfc_data;
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
@ -68,7 +68,7 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event
return scene_manager_previous_scene(nfc->scene_manager);
} else if(event.event == DialogExResultRight) {
// Clear device name
nfc_device_set_name(&nfc->dev, "");
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu);
return true;
}

@ -20,7 +20,7 @@ void nfc_scene_read_emv_app_on_enter(void* context) {
nfc_worker_start(
nfc->worker,
NfcWorkerStateReadEMVApp,
&nfc->dev.dev_data,
&nfc->dev->dev_data,
nfc_read_emv_app_worker_callback,
nfc);
}

@ -13,8 +13,8 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
// Setup view
NfcDeviceCommonData* nfc_data = &nfc->dev.dev_data.nfc_data;
NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data;
NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data;
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "Run app");
@ -23,7 +23,8 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
// Display UID and AID
string_t aid;
string_init(aid);
bool aid_found = nfc_emv_parser_get_aid_name(emv_data->aid, emv_data->aid_len, 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]);

@ -17,12 +17,12 @@ void nfc_scene_read_emv_data_on_enter(void* context) {
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));
memset(&nfc->dev->dev_data.emv_data, 0, sizeof(nfc->dev->dev_data.emv_data));
// Start worker
nfc_worker_start(
nfc->worker,
NfcWorkerStateReadEMV,
&nfc->dev.dev_data,
&nfc->dev->dev_data,
nfc_read_emv_data_worker_callback,
nfc);
}

@ -13,8 +13,8 @@ void nfc_scene_read_emv_data_success_widget_callback(
void nfc_scene_read_emv_data_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data;
NfcDeviceCommonData* nfc_data = &nfc->dev.dev_data.nfc_data;
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data;
// Setup Custom Widget view
// Add frame
@ -34,7 +34,7 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
nfc);
// Add card name
widget_add_string_element(
nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev.dev_data.emv_data.name);
nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name);
// Add cad number
string_t pan_str;
string_init(pan_str);
@ -49,7 +49,7 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
string_t country_name;
string_init(country_name);
if((emv_data->country_code) &&
nfc_emv_parser_get_country_name(emv_data->country_code, country_name)) {
nfc_emv_parser_get_country_name(nfc->dev->storage, emv_data->country_code, country_name)) {
string_t disp_country;
string_init_printf(disp_country, "Reg:%s", country_name);
widget_add_string_element(
@ -61,7 +61,8 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
string_t currency_name;
string_init(currency_name);
if((emv_data->currency_code) &&
nfc_emv_parser_get_currency_name(emv_data->currency_code, currency_name)) {
nfc_emv_parser_get_currency_name(
nfc->dev->storage, emv_data->currency_code, currency_name)) {
string_t disp_currency;
string_init_printf(disp_currency, "Cur:%s", currency_name);
widget_add_string_element(
@ -122,8 +123,8 @@ bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent e
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
} else if(event.event == GuiButtonTypeRight) {
// Clear device name
nfc_device_set_name(&nfc->dev, "");
nfc->dev.format = NfcDeviceSaveFormatBankCard;
nfc_device_set_name(nfc->dev, "");
nfc->dev->format = NfcDeviceSaveFormatBankCard;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true;
}

@ -20,7 +20,7 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) {
nfc_worker_start(
nfc->worker,
NfcWorkerStateReadMifareUl,
&nfc->dev.dev_data,
&nfc->dev->dev_data,
nfc_read_mifare_ul_worker_callback,
nfc);
}

@ -27,7 +27,7 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
notification_message(nfc->notifications, &sequence_success);
// Setup dialog view
NfcDeviceCommonData* data = (NfcDeviceCommonData*)&nfc->dev.dev_data.nfc_data;
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
@ -54,7 +54,7 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback);
// Setup TextBox view
MifareUlData* mf_ul_data = (MifareUlData*)&nfc->dev.dev_data.mf_ul_data;
MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
TextBox* text_box = nfc->text_box;
text_box_set_context(text_box, nfc);
text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback);

@ -15,11 +15,11 @@ void nfc_scene_save_name_on_enter(void* context) {
// Setup view
TextInput* text_input = nfc->text_input;
bool dev_name_empty = false;
if(!strcmp(nfc->dev.dev_name, "")) {
if(!strcmp(nfc->dev->dev_name, "")) {
set_random_name(nfc->text_store, sizeof(nfc->text_store));
dev_name_empty = true;
} else {
nfc_text_store_set(nfc, nfc->dev.dev_name);
nfc_text_store_set(nfc, nfc->dev->dev_name);
}
text_input_set_header_text(text_input, "Name the card");
text_input_set_result_callback(
@ -37,14 +37,14 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) {
if(strcmp(nfc->dev.dev_name, "")) {
nfc_device_delete(&nfc->dev);
if(strcmp(nfc->dev->dev_name, "")) {
nfc_device_delete(nfc->dev);
}
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) {
nfc->dev.dev_data.nfc_data = nfc->dev_edit_data;
nfc->dev->dev_data.nfc_data = nfc->dev_edit_data;
}
strlcpy(nfc->dev.dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
if(nfc_device_save(&nfc->dev, nfc->text_store)) {
strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
if(nfc_device_save(nfc->dev, nfc->text_store)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
return true;
} else {

@ -18,7 +18,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Submenu* submenu = nfc->submenu;
if(nfc->dev.format != NfcDeviceSaveFormatBankCard) {
if(nfc->dev->format != NfcDeviceSaveFormatBankCard) {
submenu_add_item(
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc);
}
@ -30,7 +30,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc);
submenu_set_selected_item(
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu));
if(nfc->dev.shadow_file_exist) {
if(nfc->dev->shadow_file_exist) {
submenu_add_item(
submenu,
"Restore original",
@ -49,7 +49,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event);
if(event.event == SubmenuIndexEmulate) {
if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
@ -65,7 +65,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
consumed = true;
} else if(event.event == SubmenuIndexRestoreOriginal) {
if(!nfc_device_restore(&nfc->dev)) {
if(!nfc_device_restore(nfc->dev)) {
scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart);
} else {

@ -19,7 +19,7 @@ void nfc_scene_set_atqa_on_enter(void* context) {
nfc_scene_set_atqa_byte_input_callback,
NULL,
nfc,
nfc->dev.dev_data.nfc_data.atqa,
nfc->dev->dev_data.nfc_data.atqa,
2);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
}

@ -19,7 +19,7 @@ void nfc_scene_set_sak_on_enter(void* context) {
nfc_scene_set_sak_byte_input_callback,
NULL,
nfc,
&nfc->dev.dev_data.nfc_data.sak,
&nfc->dev->dev_data.nfc_data.sak,
1);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
}

@ -15,7 +15,7 @@ void nfc_scene_set_type_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
Submenu* submenu = nfc->submenu;
// Clear device name
nfc_device_set_name(&nfc->dev, "");
nfc_device_set_name(nfc->dev, "");
submenu_add_item(
submenu, "NFC-A 7-bytes UID", SubmenuIndexNFCA7, nfc_scene_set_type_submenu_callback, nfc);
submenu_add_item(
@ -28,13 +28,13 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexNFCA7) {
nfc->dev.dev_data.nfc_data.uid_len = 7;
nfc->dev.format = NfcDeviceSaveFormatUid;
nfc->dev->dev_data.nfc_data.uid_len = 7;
nfc->dev->format = NfcDeviceSaveFormatUid;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
return true;
} else if(event.event == SubmenuIndexNFCA4) {
nfc->dev.dev_data.nfc_data.uid_len = 4;
nfc->dev.format = NfcDeviceSaveFormatUid;
nfc->dev->dev_data.nfc_data.uid_len = 4;
nfc->dev->format = NfcDeviceSaveFormatUid;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
return true;
}

@ -14,7 +14,7 @@ void nfc_scene_set_uid_on_enter(void* context) {
// Setup view
ByteInput* byte_input = nfc->byte_input;
byte_input_set_header_text(byte_input, "Enter uid in hex");
nfc->dev_edit_data = nfc->dev.dev_data.nfc_data;
nfc->dev_edit_data = nfc->dev->dev_data.nfc_data;
byte_input_set_result_callback(
byte_input,
nfc_scene_set_uid_byte_input_callback,

@ -34,7 +34,7 @@ void nfc_scene_start_on_enter(void* context) {
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart));
nfc_device_clear(&nfc->dev);
nfc_device_clear(nfc->dev);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}

@ -67,42 +67,14 @@ void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) {
bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str);
}
void bank_card_set_country_name(BankCard* bank_card, uint16_t country_code) {
void bank_card_set_country_name(BankCard* bank_card, const char* country_name) {
furi_assert(bank_card);
string_t country_name;
string_init(country_name);
if(nfc_emv_parser_get_country_name(country_code, country_name)) {
string_t disp_country;
string_init_printf(disp_country, "Reg:%s", country_name);
widget_add_string_element(
bank_card->widget,
120,
18,
AlignRight,
AlignTop,
FontSecondary,
string_get_cstr(disp_country));
string_clear(disp_country);
}
string_clear(country_name);
widget_add_string_element(
bank_card->widget, 120, 18, AlignRight, AlignTop, FontSecondary, country_name);
}
void bank_card_set_currency_name(BankCard* bank_card, uint16_t currency_code) {
void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name) {
furi_assert(bank_card);
string_t currency_name;
string_init(currency_name);
if(nfc_emv_parser_get_currency_name(currency_code, currency_name)) {
string_t disp_currency;
string_init_printf(disp_currency, "Cur:%s", currency_name);
widget_add_string_element(
bank_card->widget,
31,
18,
AlignLeft,
AlignTop,
FontSecondary,
string_get_cstr(disp_currency));
string_clear(disp_currency);
}
string_clear(currency_name);
widget_add_string_element(
bank_card->widget, 31, 18, AlignLeft, AlignTop, FontSecondary, currency_name);
}

@ -21,6 +21,6 @@ void bank_card_set_number(BankCard* bank_card, uint8_t* number, uint8_t len);
void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year);
void bank_card_set_country_name(BankCard* bank_card, uint16_t country_code);
void bank_card_set_country_name(BankCard* bank_card, const char* country_name);
void bank_card_set_currency_name(BankCard* bank_card, uint16_t currency_code);
void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name);

@ -1,148 +1,151 @@
A00000000305076010 VISA ELO Credit
A0000000031010 VISA Debit/Credit (Classic)
A000000003101001 VISA Credit
A000000003101002 VISA Debit
A0000000032010 VISA Electron
A0000000032020 VISA
A0000000033010 VISA Interlink
A0000000034010 VISA Specific
A0000000035010 VISA Specific
A0000000036010 Domestic Visa Cash
A0000000036020 International Visa Cash
A0000000038002 VISA Auth EMV-CAP (DPA)
A0000000038010 VISA Plus
A0000000039010 VISA Loyalty
A000000003999910 VISA Proprietary ATM
A00000000401 MasterCard PayPass
A0000000041010 MasterCard Global
A00000000410101213 MasterCard Credit
A00000000410101215 MasterCard Credit
A0000000042010 MasterCard Specific
A0000000043010 MasterCard Specific
A0000000043060 Maestro (Debit)
A000000004306001 Maestro (Debit)
A0000000044010 MasterCard Specific
A0000000045010 MasterCard Specific
A0000000046000 Cirrus
A0000000048002 SecureCode EMV-CAP
A0000000049999 MasterCard PayPass
A0000000050001 Maestro UK
A0000000050002 Solo
A00000002401 Self Service
A000000025 American Express
A0000000250000 American Express
A00000002501 American Express
A000000025010402 American Express
A000000025010701 ExpressPay
A000000025010801 American Express
A0000000291010 Link / American Express
A0000000421010 Cartes Bancaire EMV Card
A0000000426010 Apple Pay
A00000006510 JCB
A0000000651010 JCB J Smart Credit
A00000006900 Moneo
A000000077010000021000000000003B Visa AEPN
A000000098 Debit Card
A0000000980848 Debit Card
A0000001211010 Dankort VISA GEM Vision
A0000001410001 PagoBANCOMAT
A0000001523010 Discover, Pulse D Pas
A0000001524010 Discover
A0000001544442 Banricompras Debito
A000000172950001 BAROC Taiwan
A0000002281010 SPAN (M/Chip)
A0000002282010 SPAN (VIS)
A0000002771010 INTERAC
A00000031510100528 Currence PuC
A0000003156020 Chipknip
A0000003591010028001 Girocard EAPS
A0000003710001 InterSwitch Verve Card
A0000004540010 Etranzact Genesis Card
A0000004540011 Etranzact Genesis Card 2
A0000004766C GOOGLE_PAYMENT
A0000005241010 RuPay
A0000006723010 TROY chip credit card
A0000006723020 TROY chip debit card
A0000007705850 XTRAPOWER
B012345678 Maestro TEST
D27600002545500100 Girocard
D5780000021010 Bankaxept
F0000000030001 BRADESCO
A000000003000000 (VISA) Card Manager
A000000003534441 Schlumberger SD
A0000000035350 Security Domain
A000000003535041 Security Domain
A0000000040000 MasterCard Card Manager
A000000018434D Gemplus card manager
A000000018434D00 Gemplus Security Domain
A0000000960200 Proton WISD
A0000001510000 Global Platform SD
A00000015153504341534400 CASD_AID
A000000476A010 GSD_MANAGER_AID
A000000476A110 GSD_MANAGER_AID
315041592E5359532E4444463031 Visa PSE
325041592E5359532E4444463031 Visa PPSE
A0000000042203 MasterCard Specific
A0000000045555 APDULogger
A0000000090001FF44FF1289 Orange
A0000000101030 Maestro-CH
A00000001800 Gemplus
A0000000181001 gemplus util packages
A000000025010104 American Express
A00000002949034010100001 HSBC
A00000002949282010100000 Barclay
A00000005945430100 Girocard Electronic Cash
A0000000980840 Visa Common Debit
A0000001570010 AMEX
A0000001570020 MasterCard
A0000001570021 Maestro
A0000001570022 Maestro
A0000001570023 CASH
A0000001570030 VISA
A0000001570031 VISA
A0000001570040 JCB
A0000001570050 Postcard
A0000001570051 Postcard
A0000001570100 MCard
A0000001570104 MyOne
A000000157010C WIRCard
A000000157010D Power Card
A0000001574443 DINERS CLUB
A0000001574444 Supercard Plus
A00000022820101010 SPAN
A000000308000010000100 ID-ONE PIV BIO
A0000003241010 Discover Zip
A000000333010101 UnionPay Debit
A000000333010102 UnionPay Credit
A000000333010103 UnionPay Quasi Credit
A000000333010106 UnionPay Electronic Cash
A000000333010108 U.S. UnionPay Common Debit
A000000337102000 Classic
A000000337101001 Prepaye Online
A000000337102001 Prepaye Possibile Offiline
A000000337601001 Porte Monnaie Electronique
A0000006581010 MIR Credit
A0000006581011 MIR Credit
A0000006582010 MIR Debit
D040000001000002 Paylife Quick IEP
D040000002000002 RFU
D040000003000002 POS
D040000004000002 ATM
D04000000B000002 Retail
D04000000C000002 Bank_Data
D04000000D000002 Shopping
D040000013000001 DF_UNI_Kepler1
D040000013000001 DF_Schüler1
D040000013000002 DF_UNI_Kepler2
D040000013000002 DF_Schüler2
D040000014000001 DF_Mensa
D040000015000001 DF_UNI_Ausweis
D040000015000001 DF_Ausweis
D0400000190001 EMV ATM Maestro
D0400000190002 EMV POS Maestro
D0400000190003 EMV ATM MasterCard
D0400000190004 EMV POS MasterCard
D276000025 Girocard
D27600002547410100 Girocard ATM
D7560000010101 Reka Card
D7560000300101 M Budget
Filetype: Flipper EMV resources
Version: 1
# EMV Application ID code: Application ID name
A00000000305076010: VISA ELO Credit
A0000000031010: VISA Debit/Credit (Classic)
A000000003101001: VISA Credit
A000000003101002: VISA Debit
A0000000032010: VISA Electron
A0000000032020: VISA
A0000000033010: VISA Interlink
A0000000034010: VISA Specific
A0000000035010: VISA Specific
A0000000036010: Domestic Visa Cash
A0000000036020: International Visa Cash
A0000000038002: VISA Auth EMV-CAP (DPA)
A0000000038010: VISA Plus
A0000000039010: VISA Loyalty
A000000003999910: VISA Proprietary ATM
A00000000401: MasterCard PayPass
A0000000041010: MasterCard Global
A00000000410101213: MasterCard Credit
A00000000410101215: MasterCard Credit
A0000000042010: MasterCard Specific
A0000000043010: MasterCard Specific
A0000000043060: Maestro (Debit)
A000000004306001: Maestro (Debit)
A0000000044010: MasterCard Specific
A0000000045010: MasterCard Specific
A0000000046000: Cirrus
A0000000048002: SecureCode EMV-CAP
A0000000049999: MasterCard PayPass
A0000000050001: Maestro UK
A0000000050002: Solo
A00000002401: Self Service
A000000025: American Express
A0000000250000: American Express
A00000002501: American Express
A000000025010402: American Express
A000000025010701: ExpressPay
A000000025010801: American Express
A0000000291010: Link / American Express
A0000000421010: Cartes Bancaire EMV Card
A0000000426010: Apple Pay
A00000006510: JCB
A0000000651010: JCB J Smart Credit
A00000006900: Moneo
A000000077010000021000000000003B: Visa AEPN
A000000098: Debit Card
A0000000980848: Debit Card
A0000001211010: Dankort VISA GEM Vision
A0000001410001: PagoBANCOMAT
A0000001523010: Discover, Pulse D Pas
A0000001524010: Discover
A0000001544442: Banricompras Debito
A000000172950001: BAROC Taiwan
A0000002281010: SPAN (M/Chip)
A0000002282010: SPAN (VIS)
A0000002771010: INTERAC
A00000031510100528: Currence PuC
A0000003156020: Chipknip
A0000003591010028001: Girocard EAPS
A0000003710001: InterSwitch Verve Card
A0000004540010: Etranzact Genesis Card
A0000004540011: Etranzact Genesis Card 2
A0000004766C: GOOGLE_PAYMENT
A0000005241010: RuPay
A0000006723010: TROY chip credit card
A0000006723020: TROY chip debit card
A0000007705850: XTRAPOWER
B012345678: Maestro TEST
D27600002545500100: Girocard
D5780000021010: Bankaxept
F0000000030001: BRADESCO
A000000003000000: (VISA) Card Manager
A000000003534441: Schlumberger SD
A0000000035350: Security Domain
A000000003535041: Security Domain
A0000000040000: MasterCard Card Manager
A000000018434D: Gemplus card manager
A000000018434D00: Gemplus Security Domain
A0000000960200: Proton WISD
A0000001510000: Global Platform SD
A00000015153504341534400: CASD_AID
A000000476A010: GSD_MANAGER_AID
A000000476A110: GSD_MANAGER_AID
315041592E5359532E4444463031: Visa PSE
325041592E5359532E4444463031: Visa PPSE
A0000000042203: MasterCard Specific
A0000000045555: APDULogger
A0000000090001FF44FF1289: Orange
A0000000101030: Maestro-CH
A00000001800: Gemplus
A0000000181001: gemplus util packages
A000000025010104: American Express
A00000002949034010100001: HSBC
A00000002949282010100000: Barclay
A00000005945430100: Girocard Electronic Cash
A0000000980840: Visa Common Debit
A0000001570010: AMEX
A0000001570020: MasterCard
A0000001570021: Maestro
A0000001570022: Maestro
A0000001570023: CASH
A0000001570030: VISA
A0000001570031: VISA
A0000001570040: JCB
A0000001570050: Postcard
A0000001570051: Postcard
A0000001570100: MCard
A0000001570104: MyOne
A000000157010C: WIRCard
A000000157010D: Power Card
A0000001574443: DINERS CLUB
A0000001574444: Supercard Plus
A00000022820101010: SPAN
A000000308000010000100: ID-ONE PIV BIO
A0000003241010: Discover Zip
A000000333010101: UnionPay Debit
A000000333010102: UnionPay Credit
A000000333010103: UnionPay Quasi Credit
A000000333010106: UnionPay Electronic Cash
A000000333010108: U.S. UnionPay Common Debit
A000000337102000: Classic
A000000337101001: Prepaye Online
A000000337102001: Prepaye Possibile Offiline
A000000337601001: Porte Monnaie Electronique
A0000006581010: MIR Credit
A0000006581011: MIR Credit
A0000006582010: MIR Debit
D040000001000002: Paylife Quick IEP
D040000002000002: RFU
D040000003000002: POS
D040000004000002: ATM
D04000000B000002: Retail
D04000000C000002: Bank_Data
D04000000D000002: Shopping
D040000013000001: DF_UNI_Kepler1
D040000013000001: DF_Schüler1
D040000013000002: DF_UNI_Kepler2
D040000013000002: DF_Schüler2
D040000014000001: DF_Mensa
D040000015000001: DF_UNI_Ausweis
D040000015000001: DF_Ausweis
D0400000190001: EMV ATM Maestro
D0400000190002: EMV POS Maestro
D0400000190003: EMV ATM MasterCard
D0400000190004: EMV POS MasterCard
D276000025: Girocard
D27600002547410100: Girocard ATM
D7560000010101: Reka Card
D7560000300101: M Budget

@ -1,249 +1,252 @@
0004 AFG
0008 ALB
0010 ATA
0012 DZA
0016 ASM
0020 AND
0024 AGO
0028 ATG
0031 AZE
0032 ARG
0036 AUS
0040 AUT
0044 BHS
0048 BHR
0050 BGD
0051 ARM
0052 BRB
0056 BEL
0060 BMU
0064 BTN
0068 BOL
0070 BIH
0072 BWA
0074 BVT
0076 BRA
0084 BLZ
0086 IOT
0090 SLB
0092 VGB
0096 BRN
0100 BGR
0104 MMR
0108 BDI
0112 BLR
0116 KHM
0120 CMR
0124 CAN
0132 CPV
0136 CYM
0140 CAF
0144 LKA
0148 TCD
0152 CHL
0156 CHN
0158 TWN
0162 CXR
0166 CCK
0170 COL
0174 COM
0175 MYT
0178 COG
0180 COD
0184 COK
0188 CRI
0191 HRV
0192 CUB
0196 CYP
0203 CZE
0204 BEN
0208 DNK
0212 DMA
0214 DOM
0218 ECU
0222 SLV
0226 GNQ
0231 ETH
0232 ERI
0233 EST
0234 FRO
0238 FLK
0239 SGS
0242 FJI
0246 FIN
0248 ALA
0250 FRA
0254 GUF
0258 PYF
0260 ATF
0262 DJI
0266 GAB
0268 GEO
0270 GMB
0275 PSE
0276 DEU
0288 GHA
0292 GIB
0296 KIR
0300 GRC
0304 GRL
0308 GRD
0312 GLP
0316 GUM
0320 GTM
0324 GIN
0328 GUY
0332 HTI
0334 HMD
0336 VAT
0340 HND
0344 HKG
0348 HUN
0352 ISL
0356 IND
0360 IDN
0364 IRN
0368 IRQ
0372 IRL
0376 ISR
0380 ITA
0384 CIV
0388 JAM
0392 JPN
0398 KAZ
0400 JOR
0404 KEN
0408 PRK
0410 KOR
0414 KWT
0417 KGZ
0418 LAO
0422 LBN
0426 LSO
0428 LVA
0430 LBR
0434 LBY
0438 LIE
0440 LTU
0442 LUX
0446 MAC
0450 MDG
0454 MWI
0458 MYS
0462 MDV
0466 MLI
0470 MLT
0474 MTQ
0478 MRT
0480 MUS
0484 MEX
0492 MCO
0496 MNG
0498 MDA
0499 MNE
0500 MSR
0504 MAR
0508 MOZ
0512 OMN
0516 NAM
0520 NRU
0524 NPL
0528 NLD
0531 CUW
0533 ABW
0534 SXM
0535 BES
0540 NCL
0548 VUT
0554 NZL
0558 NIC
0562 NER
0566 NGA
0570 NIU
0574 NFK
0578 NOR
0580 MNP
0581 UMI
0583 FSM
0584 MHL
0585 PLW
0586 PAK
0591 PAN
0598 PNG
0600 PRY
0604 PER
0608 PHL
0612 PCN
0616 POL
0620 PRT
0624 GNB
0626 TLS
0630 PRI
0634 QAT
0638 REU
0642 ROU
0643 RUS
0646 RWA
0652 BLM
0654 SHN
0659 KNA
0660 AIA
0662 LCA
0663 MAF
0666 SPM
0670 VCT
0674 SMR
0678 STP
0682 SAU
0686 SEN
0688 SRB
0690 SYC
0694 SLE
0702 SGP
0703 SVK
0704 VNM
0705 SVN
0706 SOM
0710 ZAF
0716 ZWE
0724 ESP
0728 SSD
0729 SDN
0732 ESH
0740 SUR
0744 SJM
0748 SWZ
0752 SWE
0756 CHE
0760 SYR
0762 TJK
0764 THA
0768 TGO
0772 TKL
0776 TON
0780 TTO
0784 ARE
0788 TUN
0792 TUR
0795 TKM
0796 TCA
0798 TUV
0800 UGA
0804 UKR
0807 MKD
0818 EGY
0826 GBR
0831 GGY
0832 JEY
0833 IMN
0834 TZA
0840 USA
0850 VIR
0854 BFA
0858 URY
0860 UZB
0862 VEN
0876 WLF
0882 WSM
0887 YEM
0894 ZMB
Filetype: Flipper EMV resources
Version: 1
# EMV country code: country name
0004: AFG
0008: ALB
0010: ATA
0012: DZA
0016: ASM
0020: AND
0024: AGO
0028: ATG
0031: AZE
0032: ARG
0036: AUS
0040: AUT
0044: BHS
0048: BHR
0050: BGD
0051: ARM
0052: BRB
0056: BEL
0060: BMU
0064: BTN
0068: BOL
0070: BIH
0072: BWA
0074: BVT
0076: BRA
0084: BLZ
0086: IOT
0090: SLB
0092: VGB
0096: BRN
0100: BGR
0104: MMR
0108: BDI
0112: BLR
0116: KHM
0120: CMR
0124: CAN
0132: CPV
0136: CYM
0140: CAF
0144: LKA
0148: TCD
0152: CHL
0156: CHN
0158: TWN
0162: CXR
0166: CCK
0170: COL
0174: COM
0175: MYT
0178: COG
0180: COD
0184: COK
0188: CRI
0191: HRV
0192: CUB
0196: CYP
0203: CZE
0204: BEN
0208: DNK
0212: DMA
0214: DOM
0218: ECU
0222: SLV
0226: GNQ
0231: ETH
0232: ERI
0233: EST
0234: FRO
0238: FLK
0239: SGS
0242: FJI
0246: FIN
0248: ALA
0250: FRA
0254: GUF
0258: PYF
0260: ATF
0262: DJI
0266: GAB
0268: GEO
0270: GMB
0275: PSE
0276: DEU
0288: GHA
0292: GIB
0296: KIR
0300: GRC
0304: GRL
0308: GRD
0312: GLP
0316: GUM
0320: GTM
0324: GIN
0328: GUY
0332: HTI
0334: HMD
0336: VAT
0340: HND
0344: HKG
0348: HUN
0352: ISL
0356: IND
0360: IDN
0364: IRN
0368: IRQ
0372: IRL
0376: ISR
0380: ITA
0384: CIV
0388: JAM
0392: JPN
0398: KAZ
0400: JOR
0404: KEN
0408: PRK
0410: KOR
0414: KWT
0417: KGZ
0418: LAO
0422: LBN
0426: LSO
0428: LVA
0430: LBR
0434: LBY
0438: LIE
0440: LTU
0442: LUX
0446: MAC
0450: MDG
0454: MWI
0458: MYS
0462: MDV
0466: MLI
0470: MLT
0474: MTQ
0478: MRT
0480: MUS
0484: MEX
0492: MCO
0496: MNG
0498: MDA
0499: MNE
0500: MSR
0504: MAR
0508: MOZ
0512: OMN
0516: NAM
0520: NRU
0524: NPL
0528: NLD
0531: CUW
0533: ABW
0534: SXM
0535: BES
0540: NCL
0548: VUT
0554: NZL
0558: NIC
0562: NER
0566: NGA
0570: NIU
0574: NFK
0578: NOR
0580: MNP
0581: UMI
0583: FSM
0584: MHL
0585: PLW
0586: PAK
0591: PAN
0598: PNG
0600: PRY
0604: PER
0608: PHL
0612: PCN
0616: POL
0620: PRT
0624: GNB
0626: TLS
0630: PRI
0634: QAT
0638: REU
0642: ROU
0643: RUS
0646: RWA
0652: BLM
0654: SHN
0659: KNA
0660: AIA
0662: LCA
0663: MAF
0666: SPM
0670: VCT
0674: SMR
0678: STP
0682: SAU
0686: SEN
0688: SRB
0690: SYC
0694: SLE
0702: SGP
0703: SVK
0704: VNM
0705: SVN
0706: SOM
0710: ZAF
0716: ZWE
0724: ESP
0728: SSD
0729: SDN
0732: ESH
0740: SUR
0744: SJM
0748: SWZ
0752: SWE
0756: CHE
0760: SYR
0762: TJK
0764: THA
0768: TGO
0772: TKL
0776: TON
0780: TTO
0784: ARE
0788: TUN
0792: TUR
0795: TKM
0796: TCA
0798: TUV
0800: UGA
0804: UKR
0807: MKD
0818: EGY
0826: GBR
0831: GGY
0832: JEY
0833: IMN
0834: TZA
0840: USA
0850: VIR
0854: BFA
0858: URY
0860: UZB
0862: VEN
0876: WLF
0882: WSM
0887: YEM
0894: ZMB

@ -1,168 +1,171 @@
0997 USN
0994 XSU
0990 CLF
0986 BRL
0985 PLN
0984 BOV
0981 GEL
0980 UAH
0979 MXV
0978 EUR
0977 BAM
0976 CDF
0975 BGN
0973 AOA
0972 TJS
0971 AFN
0970 COU
0969 MGA
0968 SRD
0967 ZMW
0965 XUA
0960 XDR
0953 XPF
0952 XOF
0951 XCD
0950 XAF
0949 TRY
0948 CHW
0947 CHE
0946 RON
0944 AZN
0943 MZN
0941 RSD
0940 UYI
0938 SDG
0937 VEF
0936 GHS
0934 TMT
0933 BYN
0932 ZWL
0931 CUC
0930 STN
0929 MRU
0901 TWD
0886 YER
0882 WST
0860 UZS
0858 UYU
0840 USD
0834 TZS
0826 GBP
0818 EGP
0807 MKD
0800 UGX
0788 TND
0784 AED
0780 TTD
0776 TOP
0764 THB
0760 SYP
0756 CHF
0752 SEK
0748 SZL
0728 SSP
0710 ZAR
0706 SOS
0704 VND
0702 SGD
0694 SLL
0690 SCR
0682 SAR
0654 SHP
0646 RWF
0643 RUB
0634 QAR
0608 PHP
0604 PEN
0600 PYG
0598 PGK
0590 PAB
0586 PKR
0578 NOK
0566 NGN
0558 NIO
0554 NZD
0548 VUV
0533 AWG
0532 ANG
0524 NPR
0516 NAD
0512 OMR
0504 MAD
0498 MDL
0496 MNT
0484 MXN
0480 MUR
0462 MVR
0458 MYR
0454 MWK
0446 MOP
0434 LYD
0430 LRD
0426 LSL
0422 LBP
0418 LAK
0417 KGS
0414 KWD
0410 KRW
0408 KPW
0404 KES
0400 JOD
0398 KZT
0392 JPY
0388 JMD
0376 ILS
0368 IQD
0364 IRR
0360 IDR
0356 INR
0352 ISK
0348 HUF
0344 HKD
0340 HNL
0332 HTG
0328 GYD
0324 GNF
0320 GTQ
0292 GIP
0270 GMD
0262 DJF
0242 FJD
0238 FKP
0232 ERN
0230 ETB
0222 SVC
0214 DOP
0208 DKK
0203 CZK
0192 CUP
0191 HRK
0188 CRC
0174 KMF
0170 COP
0156 CNY
0152 CLP
0144 LKR
0136 KYD
0132 CVE
0124 CAD
0116 KHR
0108 BIF
0104 MMK
0096 BND
0090 SBD
0084 BZD
0072 BWP
0068 BOB
0064 BTN
0060 BMD
0052 BBD
0051 AMD
0050 BDT
0048 BHD
0044 BSD
0036 AUD
0032 ARS
0012 DZD
0008 ALL
Filetype: Flipper EMV resources
Version: 1
# EMV currency code: currency name
0997: USN
0994: XSU
0990: CLF
0986: BRL
0985: PLN
0984: BOV
0981: GEL
0980: UAH
0979: MXV
0978: EUR
0977: BAM
0976: CDF
0975: BGN
0973: AOA
0972: TJS
0971: AFN
0970: COU
0969: MGA
0968: SRD
0967: ZMW
0965: XUA
0960: XDR
0953: XPF
0952: XOF
0951: XCD
0950: XAF
0949: TRY
0948: CHW
0947: CHE
0946: RON
0944: AZN
0943: MZN
0941: RSD
0940: UYI
0938: SDG
0937: VEF
0936: GHS
0934: TMT
0933: BYN
0932: ZWL
0931: CUC
0930: STN
0929: MRU
0901: TWD
0886: YER
0882: WST
0860: UZS
0858: UYU
0840: USD
0834: TZS
0826: GBP
0818: EGP
0807: MKD
0800: UGX
0788: TND
0784: AED
0780: TTD
0776: TOP
0764: THB
0760: SYP
0756: CHF
0752: SEK
0748: SZL
0728: SSP
0710: ZAR
0706: SOS
0704: VND
0702: SGD
0694: SLL
0690: SCR
0682: SAR
0654: SHP
0646: RWF
0643: RUB
0634: QAR
0608: PHP
0604: PEN
0600: PYG
0598: PGK
0590: PAB
0586: PKR
0578: NOK
0566: NGN
0558: NIO
0554: NZD
0548: VUV
0533: AWG
0532: ANG
0524: NPR
0516: NAD
0512: OMR
0504: MAD
0498: MDL
0496: MNT
0484: MXN
0480: MUR
0462: MVR
0458: MYR
0454: MWK
0446: MOP
0434: LYD
0430: LRD
0426: LSL
0422: LBP
0418: LAK
0417: KGS
0414: KWD
0410: KRW
0408: KPW
0404: KES
0400: JOD
0398: KZT
0392: JPY
0388: JMD
0376: ILS
0368: IQD
0364: IRR
0360: IDR
0356: INR
0352: ISK
0348: HUF
0344: HKD
0340: HNL
0332: HTG
0328: GYD
0324: GNF
0320: GTQ
0292: GIP
0270: GMD
0262: DJF
0242: FJD
0238: FKP
0232: ERN
0230: ETB
0222: SVC
0214: DOP
0208: DKK
0203: CZK
0192: CUP
0191: HRK
0188: CRC
0174: KMF
0170: COP
0156: CNY
0152: CLP
0144: LKR
0136: KYD
0132: CVE
0124: CAD
0116: KHR
0108: BIF
0104: MMK
0096: BND
0090: SBD
0084: BZD
0072: BWP
0068: BOB
0064: BTN
0060: BMD
0052: BBD
0051: AMD
0050: BDT
0048: BHD
0044: BSD
0036: AUD
0032: ARS
0012: DZD
0008: ALL