Skip to content

Commit

Permalink
Merge pull request #700 from Leptopt1los/dev
Browse files Browse the repository at this point in the history
EMV protocol+parser
  • Loading branch information
xMasterX authored Jan 30, 2024
2 parents 100a46d + 872987f commit 1cb8b0e
Show file tree
Hide file tree
Showing 31 changed files with 2,113 additions and 26 deletions.
9 changes: 9 additions & 0 deletions applications/main/nfc/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,15 @@ App(
sources=["plugins/supported_cards/washcity.c"],
)

App(
appid="emv_parser",
apptype=FlipperAppType.PLUGIN,
entry_point="emv_plugin_ep",
targets=["f7"],
requires=["nfc", "storage"],
sources=["plugins/supported_cards/emv.c", "helpers/nfc_emv_parser.c"],
)

App(
appid="ndef_parser",
apptype=FlipperAppType.PLUGIN,
Expand Down
2 changes: 1 addition & 1 deletion applications/main/nfc/helpers/nfc_emv_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static bool nfc_emv_parser_search_data(

bool nfc_emv_parser_get_aid_name(
Storage* storage,
uint8_t* aid,
const uint8_t* aid,
uint8_t aid_len,
FuriString* aid_name) {
furi_assert(storage);
Expand Down
2 changes: 1 addition & 1 deletion applications/main/nfc/helpers/nfc_emv_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/
bool nfc_emv_parser_get_aid_name(
Storage* storage,
uint8_t* aid,
const uint8_t* aid,
uint8_t aid_len,
FuriString* aid_name);

Expand Down
115 changes: 115 additions & 0 deletions applications/main/nfc/helpers/protocol_support/emv/emv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "emv.h"
#include "emv_render.h"

#include <nfc/protocols/emv/emv_poller.h>

#include "nfc/nfc_app_i.h"

#include "../nfc_protocol_support_common.h"
#include "../nfc_protocol_support_gui_common.h"
#include "../iso14443_4a/iso14443_4a_i.h"

static void nfc_scene_info_on_enter_emv(NfcApp* instance) {
const NfcDevice* device = instance->nfc_device;
const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv);

FuriString* temp_str = furi_string_alloc();
// furi_string_cat_printf(
// temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
nfc_render_emv_info(data, NfcProtocolFormatTypeFull, temp_str);

widget_add_text_scroll_element(
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));

furi_string_free(temp_str);
}

static void nfc_scene_more_info_on_enter_emv(NfcApp* instance) {
// Jump to advanced scene right away
scene_manager_next_scene(instance->scene_manager, NfcSceneEmvMoreInfo);
}

static NfcCommand nfc_scene_read_poller_callback_emv(NfcGenericEvent event, void* context) {
furi_assert(event.protocol == NfcProtocolEmv);

NfcApp* instance = context;
const EmvPollerEvent* emv_event = event.event_data;

if(emv_event->type == EmvPollerEventTypeReadSuccess) {
nfc_device_set_data(
instance->nfc_device, NfcProtocolEmv, nfc_poller_get_data(instance->poller));
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
return NfcCommandStop;
}

return NfcCommandContinue;
}

static void nfc_scene_read_on_enter_emv(NfcApp* instance) {
nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_emv, instance);
}

static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) {
const NfcDevice* device = instance->nfc_device;
const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv);

FuriString* temp_str = furi_string_alloc();
// furi_string_cat_printf(
// temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
nfc_render_emv_info(data, NfcProtocolFormatTypeShort, temp_str);

widget_add_text_scroll_element(
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));

furi_string_free(temp_str);
}

// static void nfc_scene_emulate_on_enter_emv(NfcApp* instance) {
// const Iso14443_4aData* iso14443_4a_data =
// nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_4a);

// instance->listener =
// nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_4a, iso14443_4a_data);
// nfc_listener_start(
// instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance);
// }

const NfcProtocolSupportBase nfc_protocol_support_emv = {
.features = NfcProtocolFeatureMoreInfo,

.scene_info =
{
.on_enter = nfc_scene_info_on_enter_emv,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_more_info =
{
.on_enter = nfc_scene_more_info_on_enter_emv,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_read =
{
.on_enter = nfc_scene_read_on_enter_emv,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_read_menu =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_read_success =
{
.on_enter = nfc_scene_read_success_on_enter_emv,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_saved_menu =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_save_name =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty,
},
};
5 changes: 5 additions & 0 deletions applications/main/nfc/helpers/protocol_support/emv/emv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include "../nfc_protocol_support_base.h"

extern const NfcProtocolSupportBase nfc_protocol_support_emv;
182 changes: 182 additions & 0 deletions applications/main/nfc/helpers/protocol_support/emv/emv_render.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
#include "emv_render.h"

#include "../iso14443_4a/iso14443_4a_render.h"
#include "nfc/nfc_app_i.h"

void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) {
nfc_render_emv_header(str);
nfc_render_emv_uid(
data->iso14443_4a_data->iso14443_3a_data->uid,
data->iso14443_4a_data->iso14443_3a_data->uid_len,
str);

if(format_type == NfcProtocolFormatTypeFull) nfc_render_emv_extra(data, str);
}

void nfc_render_emv_header(FuriString* str) {
furi_string_cat_printf(str, "\e#%s\n", "EMV");
}

void nfc_render_emv_uid(const uint8_t* uid, const uint8_t uid_len, FuriString* str) {
if(uid_len == 0) return;

furi_string_cat_printf(str, "UID: ");

for(uint8_t i = 0; i < uid_len; i++) {
furi_string_cat_printf(str, "%02X ", uid[i]);
}

furi_string_cat_printf(str, "\n");
}

void nfc_render_emv_aid(const uint8_t* uid, const uint8_t uid_len, FuriString* str) {
if(uid_len == 0) return;

furi_string_cat_printf(str, "UID: ");

for(uint8_t i = 0; i < uid_len; i++) {
furi_string_cat_printf(str, "%02X ", uid[i]);
}

furi_string_cat_printf(str, "\n");
}

void nfc_render_emv_data(const EmvData* data, FuriString* str) {
nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str);
nfc_render_emv_name(data->emv_application.name, str);
}

void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) {
if(len == 0) return;

FuriString* card_number = furi_string_alloc();
for(uint8_t i = 0; i < len; i++) {
if((i % 2 == 0) && (i != 0)) furi_string_cat_printf(card_number, " ");
furi_string_cat_printf(card_number, "%02X", data[i]);
}

// Cut padding 'F' from card number
furi_string_trim(card_number, "F");
furi_string_cat(str, card_number);
furi_string_free(card_number);

furi_string_cat_printf(str, "\n");
}

void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str) {
if(apl->exp_month == 0) return;
furi_string_cat_printf(str, "Exp: %02X/%02X\n", apl->exp_month, apl->exp_year);
}

void nfc_render_emv_currency(uint16_t cur_code, FuriString* str) {
if(!cur_code) return;

furi_string_cat_printf(str, "Currency code: %04X\n", cur_code);
}

void nfc_render_emv_country(uint16_t country_code, FuriString* str) {
if(!country_code) return;

furi_string_cat_printf(str, "Country code: %04X\n", country_code);
}

void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) {
const uint8_t len = apl->aid_len;

if(!len) {
furi_string_cat_printf(str, "No Pay Application found\n");
return;
}

furi_string_cat_printf(str, "AID: ");

for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]);

furi_string_cat_printf(str, "\n");
}

static void nfc_render_emv_pin_try_counter(uint8_t counter, FuriString* str) {
if(counter == 0xff) return;
furi_string_cat_printf(str, "PIN try left: %d\n", counter);
}

void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) {
if(apl->transaction_counter)
furi_string_cat_printf(str, "Transactions: %d\n", apl->transaction_counter);
if(apl->last_online_atc)
furi_string_cat_printf(str, "Last Online ATC: %d\n", apl->last_online_atc);

const uint8_t len = apl->active_tr;
if(!len) {
furi_string_cat_printf(str, "No transactions info\n");
return;
}

Storage* storage = furi_record_open(RECORD_STORAGE);
FuriString* tmp = furi_string_alloc();

//furi_string_cat_printf(str, "Transactions:\n");
for(int i = 0; i < len; i++) {
if(!apl->trans[i].amount) continue;
// transaction counter
furi_string_cat_printf(str, "\e#%d: ", apl->trans[i].atc);

// Print transaction amount
uint8_t* a = (uint8_t*)&apl->trans[i].amount;
bool top = true;
for(int x = 0; x < 6; x++) {
// cents
if(x == 5) {
furi_string_cat_printf(str, ".%02X", a[x]);
break;
}
if(a[x]) {
if(top) {
furi_string_cat_printf(str, "%X", a[x]);
top = false;
} else {
furi_string_cat_printf(str, "%02X", a[x]);
}
}
}

if(apl->trans[i].currency) {
furi_string_set_str(tmp, "UNK");
nfc_emv_parser_get_currency_name(storage, apl->trans[i].currency, tmp);
furi_string_cat_printf(str, " %s\n", furi_string_get_cstr(tmp));
}

if(apl->trans[i].country) {
furi_string_set_str(tmp, "UNK");
nfc_emv_parser_get_country_name(storage, apl->trans[i].country, tmp);
furi_string_cat_printf(str, "Country: %s\n", furi_string_get_cstr(tmp));
}

if(apl->trans[i].date)
furi_string_cat_printf(
str,
"%02lx/%02lx/%02lx ",
apl->trans[i].date >> 16,
(apl->trans[i].date >> 8) & 0xff,
apl->trans[i].date & 0xff);

if(apl->trans[i].time)
furi_string_cat_printf(
str,
"%02lx:%02lx:%02lx\n",
apl->trans[i].time & 0xff,
(apl->trans[i].time >> 8) & 0xff,
apl->trans[i].time >> 16);
}

furi_string_free(tmp);
furi_record_close(RECORD_STORAGE);
}

void nfc_render_emv_extra(const EmvData* data, FuriString* str) {
nfc_render_emv_application(&data->emv_application, str);

nfc_render_emv_currency(data->emv_application.currency_code, str);
nfc_render_emv_country(data->emv_application.country_code, str);
nfc_render_emv_pin_try_counter(data->emv_application.pin_try_counter, str);
}
30 changes: 30 additions & 0 deletions applications/main/nfc/helpers/protocol_support/emv/emv_render.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <nfc/protocols/emv/emv.h>

#include "../nfc_protocol_support_render_common.h"
#include <stdint.h>

void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str);

void nfc_render_emv_data(const EmvData* data, FuriString* str);

void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str);

void nfc_render_emv_name(const char* data, FuriString* str);

void nfc_render_emv_application(const EmvApplication* data, FuriString* str);

void nfc_render_emv_extra(const EmvData* data, FuriString* str);

void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str);

void nfc_render_emv_country(uint16_t country_code, FuriString* str);

void nfc_render_emv_currency(uint16_t cur_code, FuriString* str);

void nfc_render_emv_transactions(const EmvApplication* data, FuriString* str);

void nfc_render_emv_uid(const uint8_t* uid, const uint8_t uid_len, FuriString* str);

void nfc_render_emv_header(FuriString* str);
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "mf_ultralight/mf_ultralight.h"
#include "mf_classic/mf_classic.h"
#include "mf_desfire/mf_desfire.h"
#include "emv/emv.h"
#include "slix/slix.h"
#include "st25tb/st25tb.h"

Expand All @@ -41,5 +42,6 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = {
[NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire,
[NfcProtocolSlix] = &nfc_protocol_support_slix,
[NfcProtocolSt25tb] = &nfc_protocol_support_st25tb,
[NfcProtocolEmv] = &nfc_protocol_support_emv,
/* Add new protocol support implementations here */
};
1 change: 1 addition & 0 deletions applications/main/nfc/nfc_app_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "helpers/mf_ultralight_auth.h"
#include "helpers/mf_user_dict.h"
#include "helpers/mfkey32_logger.h"
#include "helpers/nfc_emv_parser.h"
#include "helpers/mf_classic_key_cache.h"
#include "helpers/nfc_supported_cards.h"

Expand Down
Loading

0 comments on commit 1cb8b0e

Please sign in to comment.