-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #700 from Leptopt1los/dev
EMV protocol+parser
- Loading branch information
Showing
31 changed files
with
2,113 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
applications/main/nfc/helpers/protocol_support/emv/emv.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
182
applications/main/nfc/helpers/protocol_support/emv/emv_render.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
30
applications/main/nfc/helpers/protocol_support/emv/emv_render.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.