diff --git a/lib/UI/navigation/NFC/NFCNavigation.cpp b/lib/UI/navigation/NFC/NFCNavigation.cpp index 292bba9..171d663 100644 --- a/lib/UI/navigation/NFC/NFCNavigation.cpp +++ b/lib/UI/navigation/NFC/NFCNavigation.cpp @@ -31,6 +31,7 @@ #include "pages/NFC/NFCPollingWaitingPage.hpp" #include "pages/NFC/NFCWriteResultPage.hpp" #include "pages/NFC/NFCEmulateTagPage.hpp" +#include "pages/NFC/NFCEMVReadPage.hpp" #include "posixsd.hpp" #include "sdcard_helper.hpp" @@ -46,6 +47,7 @@ static NFCFelicaPollingResultPage *nfc_felica_polling_result_page = nullptr; static FileBrowserPage *nfc_dump_file_browser_page = nullptr; static NFCWriteResultPage *nfc_write_result_page = nullptr; static NFCEmulateTagPage *nfc_emulate_tag_page = nullptr; +static NFCEMVReadPage *nfc_emv_read_page = nullptr; std::list nfc_dumps_files; // NFC Dumps files @@ -57,7 +59,7 @@ std::list nfc_dumps_files; // NFC Dumps files void goto_nfc_gui() { gui->reset(); - nfc_main_page = new NFCMainPage(2, 0, 1, gui->get_screen()); + nfc_main_page = new NFCMainPage(3, 0, 1, gui->get_screen()); gui->set_current_page(nfc_main_page); } @@ -94,6 +96,8 @@ void nfc_cleanup() { if (!nfc_dumps_files.empty()) { nfc_dumps_files.clear(); } + nfc_emulate_tag_page = nullptr; + nfc_emv_read_page = nullptr; } bool emulating = false; @@ -103,6 +107,8 @@ void goto_home() { stop_emulate(); emulating = false; } + + destroy_tasks(nfc_attacks); reset_uid(); reset_felica(); nfc_cleanup(); @@ -277,6 +283,29 @@ void set_unwritable_sectors(size_t val) { nfc_write_result_page->set_unwritable_sectors(val); } +void read_emv_card() { + gui->reset(); + nfc_emv_read_page = new NFCEMVReadPage(5, 5, 0, gui->get_screen()); + gui->set_current_page(nfc_emv_read_page); + read_emv_card_attack(gui, nfc_attacks); +} + +void set_emv_type(String type) { + nfc_emv_read_page->set_card_type(type); +} + +void set_emv_pan(String pan) { + nfc_emv_read_page->set_card_pan(pan); +} + +void set_emv_issue_date(String issuedate) { + nfc_emv_read_page->set_card_issue_date("ValidFrom: " + issuedate); +} + +void set_emv_expire_date(String expiredate) { + nfc_emv_read_page->set_card_expire_date("ValidTo: " + expiredate); +} + static bool nfc_initialized = false; void init_nfc_navigation(Gui *_gui) { diff --git a/lib/UI/navigation/NFC/NFCNavigation.hpp b/lib/UI/navigation/NFC/NFCNavigation.hpp index 45de7fe..d478ea6 100644 --- a/lib/UI/navigation/NFC/NFCNavigation.hpp +++ b/lib/UI/navigation/NFC/NFCNavigation.hpp @@ -20,21 +20,23 @@ #include "gui.hpp" -void init_nfc_navigation(Gui *_gui); -void goto_nfc_gui(); + void stop_nfc_polling(); void save_dump_to_sd(); void nfc_mifare_polling(); -void nfc_felica_polling(); void format_nfc_tag(); -void goto_home(); -void nfc_return_back(); void open_nfc_dump_browser(); void bruteforce_a_tag(); void init_nfc_felica_polling_result_gui(uint8_t *idm, uint8_t *pmm, uint16_t sys_code); + + +// Emulator void emulate_iso14443a(); void emulate_iso18092(); + +// GUI function +void goto_nfc_gui(); void set_dumped_sectors(int sectors); void set_unreadable_sectors(int sectors); void set_unauthenticated_sectors(int sectors); @@ -47,7 +49,22 @@ void nfc_bruteforce_set_tried_key(uint8_t attemps); void goto_nfc_dump_result_gui(); void goto_nfc_polling_result_gui(uint8_t *uid, uint8_t len, const char *tag_name); +void goto_home(); +void nfc_return_back(); +void set_emv_type(String type); +void set_emv_pan(String pan); +void set_emv_issue_date(String issuedate); +void set_emv_expire_date(String expiredate); + +// FeliCa feature void felica_dump(); +void nfc_felica_polling(); + +// EMV feature +void read_emv_card(); + +// Misc +void init_nfc_navigation(Gui *_gui); void nfc_cleanup(); String get_current_pn532_version(); #endif \ No newline at end of file diff --git a/lib/UI/pages/NFC/NFCEMVReadPage.cpp b/lib/UI/pages/NFC/NFCEMVReadPage.cpp new file mode 100644 index 0000000..ab11540 --- /dev/null +++ b/lib/UI/pages/NFC/NFCEMVReadPage.cpp @@ -0,0 +1,45 @@ +/* + * This file is part of the Capibara zero (https://github.com/CapibaraZero/fw or + * https://capibarazero.github.io/). Copyright (c) 2025 Andrea Canale. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "NFCEMVReadPage.hpp" +#include "../../navigation/NFC/NFCNavigation.hpp" + +#include "gui.hpp" + +NFCEMVReadPage::~NFCEMVReadPage() { + delete card_type; + delete card_number; + delete issue_date; + delete expire; +} + +void NFCEMVReadPage::display() { + grid = new Grid(screen, 5, 1); + card_type = new Text(screen, ST77XX_WHITE, "Scanning EMV..."); + card_number = new Text(screen, ST77XX_WHITE, ""); + issue_date = new Text(screen, ST77XX_WHITE, ""); + expire = new Text(screen, ST77XX_WHITE, ""); + exit_page = new List(screen, "Exit", 2, ST77XX_WHITE, 20, ST77XX_BLUE, goto_home); + grid->add(card_type); + grid->add(card_number); + grid->add(issue_date); + grid->add(expire); + grid->add(exit_page); + grid->set_y_spacing(20); + grid->set_selected(4, true); + grid->display(); +} diff --git a/lib/UI/pages/NFC/NFCEMVReadPage.hpp b/lib/UI/pages/NFC/NFCEMVReadPage.hpp new file mode 100644 index 0000000..90198e9 --- /dev/null +++ b/lib/UI/pages/NFC/NFCEMVReadPage.hpp @@ -0,0 +1,60 @@ +/* + * This file is part of the Capibara zero (https://github.com/CapibaraZero/fw or + * https://capibarazero.github.io/). Copyright (c) 2025 Andrea Canale. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../../i18n.hpp" +#include "../../i18n/NFC/nfc_format_page_keys.h" +#include "../Page.hpp" +#include "Grid.hpp" +#include "List.hpp" +#include "Text.hpp" + +#ifndef NFC_EMV_READ_PAGE_H +#define NFC_EMV_READ_PAGE_H + +class NFCEMVReadPage : public Page { + private: + Text *card_type; + Text *card_number; + Text *issue_date; + Text *expire; + List *exit_page; + + public: + NFCEMVReadPage(uint8_t _position_limit, uint8_t _lower_limit, + uint8_t _position_increment, GFXForms *screen) + : Page(_position_limit, _lower_limit, _position_increment, screen) { + }; + ~NFCEMVReadPage(); + void display(); + + void click(int pos, void callback()) { grid->click(pos, callback); }; + void set_selected(int pos, bool status) { grid->set_selected(pos, status); }; + void set_card_type(String type) { + card_type->set_text(type); + } + void set_card_pan(String pan) { + card_number->set_text(pan); + } + void set_card_issue_date(String issuedate) { + issue_date->set_text(issuedate); + } + void set_card_expire_date(String expiredate) { + expire->set_text(expiredate); + } +}; + +#endif diff --git a/lib/UI/pages/NFC/NFCMainPage.cpp b/lib/UI/pages/NFC/NFCMainPage.cpp index 68d64cb..2cbf156 100644 --- a/lib/UI/pages/NFC/NFCMainPage.cpp +++ b/lib/UI/pages/NFC/NFCMainPage.cpp @@ -1,6 +1,6 @@ /* * This file is part of the Capibara zero (https://github.com/CapibaraZero/fw or - * https://capibarazero.github.io/). Copyright (c) 2024 Andrea Canale. + * https://capibarazero.github.io/). Copyright (c) 2025 Andrea Canale. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +25,7 @@ NFCMainPage::~NFCMainPage() { delete polling_iso14443_a; delete polling_felica; + delete read_emv; delete go_back; } @@ -35,10 +36,13 @@ void NFCMainPage::display() { ST77XX_WHITE, 20, ST77XX_BLACK, nfc_mifare_polling); polling_felica = new List(screen, english_words->at(POLLING_ISO18092_KEY), 2, ST77XX_WHITE, 20, ST77XX_BLACK, nfc_felica_polling); + read_emv = new List(screen, "Read EMV", 2, + ST77XX_WHITE, 20, ST77XX_BLACK, read_emv_card); go_back = new List(screen, english_words->at(NFC_POLLING_GO_BACK_KEY), 2, ST77XX_WHITE, 20, ST77XX_BLACK, goto_home); grid->add(polling_iso14443_a); grid->add(polling_felica); + grid->add(read_emv); grid->add(go_back); grid->set_selected(0, true); grid->display(); diff --git a/lib/UI/pages/NFC/NFCMainPage.hpp b/lib/UI/pages/NFC/NFCMainPage.hpp index 29827c8..29c6cc2 100644 --- a/lib/UI/pages/NFC/NFCMainPage.hpp +++ b/lib/UI/pages/NFC/NFCMainPage.hpp @@ -1,6 +1,6 @@ /* * This file is part of the Capibara zero (https://github.com/CapibaraZero/fw or - * https://capibarazero.github.io/). Copyright (c) 2024 Andrea Canale. + * https://capibarazero.github.io/). Copyright (c) 2025 Andrea Canale. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ class NFCMainPage : public Page { private: List *polling_iso14443_a; List *polling_felica; + List *read_emv; List *go_back; public: diff --git a/lib/nfc_attacks/nfc_attacks.cpp b/lib/nfc_attacks/nfc_attacks.cpp index 2d3e882..f13941b 100644 --- a/lib/nfc_attacks/nfc_attacks.cpp +++ b/lib/nfc_attacks/nfc_attacks.cpp @@ -26,6 +26,8 @@ #include "fm.hpp" #include "helper.hpp" #include "posixsd.hpp" +#include "BerTlv.h" +#include using namespace std; @@ -570,4 +572,102 @@ bool NFCAttacks::emulate_tag(uint8_t *uid) { bool NFCAttacks::emulate_tag(uint8_t *idm, uint8_t *pmm, uint8_t *sys_code) { return nfc_framework.emulate_tag(idm, pmm, sys_code); -}; \ No newline at end of file +}; + +void NFCAttacks::parse_pan(std::vector *afl_content, EMVCard *card) { + auto pos = find(afl_content->begin(), afl_content->end(), 0x5A); + uint8_t len = *(pos+1); + uint8_t pan_begin = distance(afl_content->begin(), pos) + 2; + card->pan = (uint8_t *)malloc(len); + memcpy(card->pan, &afl_content->data()[pan_begin], len); + card->pan_len = len; +} + +void NFCAttacks::parse_validfrom(std::vector *afl_content, EMVCard *card) { + bool found = false; + for (size_t i = 0; i < afl_content->size() && !found; i++) { + if(afl_content->at(i) == 0x5F && afl_content->at(i+1) == 0x25) { + size_t begin = i+3; // The format is 0x5F 0x25 SIZE DATA so skip 3 bytes + card->validfrom = (uint8_t *) malloc(2); + // The format in card is YEAR/MONTH but I want MONTH/YEAR since is the standard format + card->validfrom[0] = afl_content->at(begin+1); + card->validfrom[1] = afl_content->at(begin); + found = true; + } + } +} + +void NFCAttacks::parse_validto(std::vector *afl_content, EMVCard *card) { + bool found = false; + for (size_t i = 0; i < afl_content->size() && !found; i++) { + if(afl_content->at(i) == 0x5F && afl_content->at(i+1) == 0x24) { + size_t begin = i+3; // The format is 0x5F 0x24 SIZE DATA so skip 3 bytes + card->validto = (uint8_t *) malloc(2); + // The format in card is YEAR/MONTH but I want MONTH/YEAR since is the standard format + card->validto[0] = afl_content->at(begin+1); + card->validto[1] = afl_content->at(begin); + found = true; + } + } +} + +void NFCAttacks::get_afl(EMVCard *card, uint8_t *afl) { + uint8_t P2 = (afl[0] >> 3) <<3 | 0b00000100; // Calculate P2 from afl + std::vector afl_content = nfc_framework.emv_read_afl(P2); + if(!afl_content.empty()) { + BerTlv Tlv; + Tlv.SetTlv(afl_content); + std::vector container; + if(Tlv.GetValue("5A", &container) != OK) { // Get PAN(Credit Card Number). If TLV is corrupted(happens often with PN532 fallback to a workaround to find information) + parse_pan(&afl_content, card); + parse_validfrom(&afl_content, card); + parse_validto(&afl_content, card); + } else { + memcpy(card->pan, container.data(), container.size()); // Copy data from TLV to struct + container.clear(); + if(Tlv.GetValue("5F25", &container) != OK) { // Get ValidFrom date + parse_validfrom(&afl_content, card); + parse_validto(&afl_content, card); + } else { + memcpy(card->validfrom, container.data(), container.size()); + if(Tlv.GetValue("5F24", &container) != OK) { // Get ValidTo date + parse_validto(&afl_content, card); + } else { + memcpy(card->validto, container.data(), container.size()); + } + } + } + } else { + Serial.println("Can't parse AFL data"); + } +} + +EMVCard NFCAttacks::read_emv_card() { + EMVCard res; + std::vector aid = nfc_framework.emv_ask_for_aid(); // Perform Application Selection + if(aid.empty()) { // If we can't get AID, we can't read the card + res.parsed = false; + Serial.println("Can't read card"); + } else { + // Copy AID to result card + res.aid = (uint8_t *)malloc(aid.size()); + memcpy(res.aid, aid.data(), aid.size()); + + // Initialize Application Process + std::vector pdol = nfc_framework.emv_ask_for_pdol(&aid); // Check if card require PDOL(for example, VISA) + + if(pdol.empty()) { // No PDOL(for example Mastercard) + std::vector afl = nfc_framework.emv_ask_for_afl(); // Try to get AFL without PDOL + + if(!afl.empty()) { + // Read Application data + get_afl(&res, afl.data()); // Read AFL + } else { + Serial.println("Can't get AFL ID"); + } + } else { + // TODO: Implement PDOL reading + } + } + return res; +} \ No newline at end of file diff --git a/lib/nfc_attacks/nfc_attacks.hpp b/lib/nfc_attacks/nfc_attacks.hpp index d911bac..6e39e08 100644 --- a/lib/nfc_attacks/nfc_attacks.hpp +++ b/lib/nfc_attacks/nfc_attacks.hpp @@ -19,6 +19,8 @@ #define NFC_ATTACKS_H #include #include "../../include/pins.h" +#include + typedef struct SectorResult { uint8_t uid[7]; uint8_t uid_len = 0; @@ -29,6 +31,16 @@ typedef struct SectorResult { bool dumped = false; } SectorResult; +typedef struct EMVCard { + bool parsed = true; + uint8_t *aid = nullptr; + size_t pan_len = 0; + uint8_t *pan = nullptr; + uint8_t *afl_raw = nullptr; + uint8_t *validfrom = nullptr; + uint8_t *validto = nullptr; +} EMVCard; + #include "NFCTag.hpp" #include "nfc_framework.hpp" @@ -45,7 +57,12 @@ class NFCAttacks { uint8_t *out_key, bool *key_found); bool read_sector(uint8_t initial_pos, uint8_t *key, KeyType key_type, uint8_t *out); - + + // EMV methods created with the help of https://werner.rothschopf.net/201703_arduino_esp8266_nfc.htm + void parse_pan(std::vector *afl_content, EMVCard *card); + void parse_validfrom(std::vector *afl_content, EMVCard *card); + void parse_validto(std::vector *afl_content, EMVCard *card); + void get_afl(EMVCard *card, uint8_t *afl); public: NFCAttacks(/* args */); ~NFCAttacks() {}; @@ -100,6 +117,9 @@ class NFCAttacks { bool emulate_tag(uint8_t *uid); bool emulate_tag(uint8_t *idm, uint8_t *pmm, uint8_t *sys_code); + + // EMV methods created with the help of https://werner.rothschopf.net/201703_arduino_esp8266_nfc.htm + EMVCard read_emv_card(); }; #endif diff --git a/lib/nfc_attacks/nfc_attacks_btn.cpp b/lib/nfc_attacks/nfc_attacks_btn.cpp index 1b8756a..eb5a867 100644 --- a/lib/nfc_attacks/nfc_attacks_btn.cpp +++ b/lib/nfc_attacks/nfc_attacks_btn.cpp @@ -27,6 +27,7 @@ static TaskHandle_t format_task_handle = NULL; static TaskHandle_t bruteforce_task_handle = NULL; static TaskHandle_t ui_updater_task_handle = NULL; static TaskHandle_t nfc_emulate_handle = NULL; +static TaskHandle_t emv_reader_handle = NULL; void mifare_polling(Gui *gui, NFCAttacks *attacks) { /* We delete this after usage, so we need to recreate struct every time */ @@ -132,6 +133,17 @@ void stop_emulate() { nfc_emulate_handle = NULL; } +bool reading_emv = false; + +void read_emv_card_attack(Gui *gui, NFCAttacks *attacks) { + /* We delete this after usage, so we need to recreate struct every time */ + params = (NFCTasksParams *)malloc(sizeof(NFCTasksParams)); + params->attacks = attacks; + params->gui = gui; + xTaskCreate(read_emv_card_task, "read_emv_card", 4000, (void *) params, 5, &emv_reader_handle); + reading_emv = true; +} + void destroy_tasks(NFCAttacks *attacks) { attacks->power_down(); if (polling_in_progress) { @@ -153,5 +165,10 @@ void destroy_tasks(NFCAttacks *attacks) { } if(nfc_emulate_handle != NULL) { vTaskDelete(nfc_emulate_handle); + nfc_emulate_handle = NULL; + } + if(emv_reader_handle != NULL && reading_emv) { + vTaskDelete(emv_reader_handle); + emv_reader_handle = NULL; } } \ No newline at end of file diff --git a/lib/nfc_attacks/nfc_attacks_btn.hpp b/lib/nfc_attacks/nfc_attacks_btn.hpp index 9aafa98..621a2d6 100644 --- a/lib/nfc_attacks/nfc_attacks_btn.hpp +++ b/lib/nfc_attacks/nfc_attacks_btn.hpp @@ -32,4 +32,5 @@ void reset_felica(void); void destroy_tasks(NFCAttacks *attacks); void emulate_iso14443a_tag(uint8_t *uid, NFCAttacks *attacks); void emulate_iso18092_tag(uint8_t *idm, uint8_t *pmm, uint8_t *sys_code, NFCAttacks *attacks); -void stop_emulate(); \ No newline at end of file +void stop_emulate(); +void read_emv_card_attack(Gui *gui, NFCAttacks *nfc_attacks); \ No newline at end of file diff --git a/lib/nfc_attacks/nfc_tasks.cpp b/lib/nfc_attacks/nfc_tasks.cpp index b2477df..ef979eb 100644 --- a/lib/nfc_attacks/nfc_tasks.cpp +++ b/lib/nfc_attacks/nfc_tasks.cpp @@ -282,4 +282,133 @@ void emulate_iso18092nfc(void *pv) { while (true) { params->attacks->emulate_tag(params->idm, params->pmm, params->sys_code); } +} + +// From https://github.com/huckor/BER-TLV +std::string BinToAscii(uint8_t *BinData, size_t size) +{ + char AsciiHexNo[5]; + std::string Return; + + for(int i = 0; i < size; i++) + { + sprintf(AsciiHexNo, "%02X", BinData[i]); + Return += AsciiHexNo; + } + + return Return; +} + +typedef struct EMVAID { + uint8_t aid[7]; + const char *name; +} EMVAID; + +#define AID_DICT_SIZE 11 +// http://hartleyenterprises.com/listAID.html +const EMVAID known_aid[AID_DICT_SIZE] = { + // MasterCard + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x04, 0x10, 0x10}, + .name = "MasterCard" + }, + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x04, 0x22, 0x03}, + .name = "U.S Maestro" + }, + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x04, 0x30, 0x60}, + .name = "Maestro" + }, + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x04, 0x60, 0x00}, + .name = "Cirrus" + }, + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x04, 0x99, 0x99}, + .name = "MasterCard" + }, + // Visa + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10}, + .name = "Visa" + }, + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x03, 0x20, 0x10}, + .name = "Electron" + }, + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x03, 0x20, 0x20}, + .name = "V-Pay" + }, + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x03, 0x30, 0x10}, + .name = "Visa" + }, + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x10}, + .name = "Visa" + }, + { + .aid = {0xA0, 0x00, 0x00, 0x00, 0x98, 0x08, 0x40}, + .name = "Visa" + } +}; + +extern bool reading_emv; + +void read_emv_card_task(void *pv) { + NFCTasksParams *params = static_cast(pv); + EMVCard card = params->attacks->read_emv_card(); + + if(card.parsed) { + bool found = false; + for (size_t i = 0; i < AID_DICT_SIZE && !found; i++) { + if(memcmp(card.aid, known_aid[i].aid, 7) == 0) { + set_emv_type(known_aid[i].name); + found = true; + } + } + + if(!found) { + set_emv_type("Unknown"); + } + + if(card.pan != nullptr) { + std::string pan = BinToAscii(card.pan, card.pan_len); + + /* Add some spacing */ + size_t pad = 0; + for (size_t i = 0; i < pan.size(); i++) { + if(i % 4 == 0 && i != 0) { + pan.insert(pan.begin() + i + (pad++), ' '); + } + } + + set_emv_pan(pan.c_str()); + } else { + set_emv_pan("Unknown"); + } + + if(card.validfrom != nullptr) { + std::string issuedate = BinToAscii(card.validfrom, 2); + issuedate.insert(issuedate.begin() + 2, '/'); + set_emv_issue_date(issuedate.c_str()); + } else { + set_emv_issue_date("Unknown"); + } + + if(card.validto != nullptr) { + std::string validto = BinToAscii(card.validto, 2); + validto.insert(validto.begin() + 2, '/'); + set_emv_expire_date(validto.c_str()); + } else { + set_emv_expire_date("Unknown"); + } + } else { + set_emv_type("Can't parse EMV"); + } + + reading_emv = false; + vTaskDelete(NULL); } \ No newline at end of file diff --git a/lib/nfc_attacks/nfc_tasks.hpp b/lib/nfc_attacks/nfc_tasks.hpp index 07cbed6..c93be23 100755 --- a/lib/nfc_attacks/nfc_tasks.hpp +++ b/lib/nfc_attacks/nfc_tasks.hpp @@ -39,4 +39,5 @@ void bruteforce_iso14443a_task(void *pv); void bruteforce_update_ui_task(void *pv); void emulate_iso14443anfc(void *pv); void emulate_iso18092nfc(void *pv); +void read_emv_card_task(void *pv); #endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index ccd4aa6..9284602 100644 --- a/platformio.ini +++ b/platformio.ini @@ -38,6 +38,7 @@ lib_deps_external = esphome/AsyncTCP-esphome@^2.0.0 https://github.com/vdccc/EasyButton.git https://github.com/andreock/RadioLib.git + https://github.com/huckor/BER-TLV.git build_flags = -DCONFIG_USE_LOGIN_CALLBACK=1 -DUSE_NIMBLE=true -DNO_SERIAL_PRINT_BLESNIFFER=true