1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 12:42:30 +04:00

read transactions fail on some cards fixed

This commit is contained in:
Methodius
2024-02-15 21:53:06 +09:00
parent c061fb1681
commit 7b01a33b3f
6 changed files with 72 additions and 64 deletions

View File

@@ -112,6 +112,7 @@ void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) {
if(!apl->trans[i].amount) { if(!apl->trans[i].amount) {
furi_string_cat_printf(str, "???"); furi_string_cat_printf(str, "???");
} else { } else {
FURI_LOG_D("EMV Render", "Amount: %llX\n", apl->trans[i].amount);
uint8_t amount_bytes[6]; uint8_t amount_bytes[6];
bit_lib_num_to_bytes_le(apl->trans[i].amount, 6, amount_bytes); bit_lib_num_to_bytes_le(apl->trans[i].amount, 6, amount_bytes);

View File

@@ -99,7 +99,8 @@ static NfcCommand emv_poller_handler_get_processing_options(EmvPoller* instance)
} }
static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) {
emv_poller_read_afl(instance); // Search PAN
emv_poller_read_afl(instance, false, &instance->records_mask);
emv_poller_read_log_entry(instance); emv_poller_read_log_entry(instance);
instance->state = EmvPollerStateReadExtra; instance->state = EmvPollerStateReadExtra;
@@ -110,6 +111,9 @@ static NfcCommand emv_poller_handler_read_extra_data(EmvPoller* instance) {
emv_poller_get_last_online_atc(instance); emv_poller_get_last_online_atc(instance);
emv_poller_get_pin_try_counter(instance); emv_poller_get_pin_try_counter(instance);
// Search cardholder name. This operation may break communication with the card, so it should be the last one
emv_poller_read_afl(instance, true, &instance->records_mask);
instance->state = EmvPollerStateReadSuccess; instance->state = EmvPollerStateReadSuccess;
return NfcCommandContinue; return NfcCommandContinue;
} }

View File

@@ -46,7 +46,7 @@ EmvError emv_poller_get_processing_options(EmvPoller* instance);
EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t record_num); EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t record_num);
EmvError emv_poller_read_afl(EmvPoller* instance); EmvError emv_poller_read_afl(EmvPoller* instance, bool bruteforce_sfi, uint16_t* readed_mask);
EmvError emv_poller_read_log_entry(EmvPoller* instance); EmvError emv_poller_read_log_entry(EmvPoller* instance);

View File

@@ -621,9 +621,13 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re
return error; return error;
} }
EmvError emv_poller_read_afl(EmvPoller* instance) { EmvError emv_poller_read_afl(EmvPoller* instance, bool bruteforce_sfi, uint16_t* readed_mask) {
EmvError error = EmvErrorNone; EmvError error = EmvErrorNone;
bool pan_fetched = (instance->data->emv_application.pan_len);
bool cardholder_name_fetched = strlen(instance->data->emv_application.cardholder_name);
if(!bruteforce_sfi) {
// SEARCH PAN, RETURN WHEN FOUND
APDU* afl = &instance->data->emv_application.afl; APDU* afl = &instance->data->emv_application.afl;
if(afl->size == 0) { if(afl->size == 0) {
@@ -632,11 +636,6 @@ EmvError emv_poller_read_afl(EmvPoller* instance) {
FURI_LOG_D(TAG, "Search PAN in SFI"); FURI_LOG_D(TAG, "Search PAN in SFI");
uint8_t sfi_2_mask = 0;
uint8_t sfi_3_mask = 0;
bool pan_fetched = (instance->data->emv_application.pan_len);
// Iterate through all files // Iterate through all files
for(size_t i = 0; i < instance->data->emv_application.afl.size; i += 4) { for(size_t i = 0; i < instance->data->emv_application.afl.size; i += 4) {
uint8_t sfi = afl->data[i] >> 3; uint8_t sfi = afl->data[i] >> 3;
@@ -644,8 +643,10 @@ EmvError emv_poller_read_afl(EmvPoller* instance) {
uint8_t record_end = afl->data[i + 2]; uint8_t record_end = afl->data[i + 2];
// Iterate through all records in file // Iterate through all records in file
for(uint8_t record = record_start; record <= record_end; ++record) { for(uint8_t record = record_start; record <= record_end; ++record) {
if((sfi == 2) && (record < 8)) FURI_BIT_SET(sfi_2_mask, record); if((sfi <= 3) && (record <= 5))
if((sfi == 3) && (record < 8)) FURI_BIT_SET(sfi_3_mask, record); FURI_BIT_SET(
*readed_mask,
record + ((sfi - 2) * 8)); //black magic: mask 0003333300022222
error = emv_poller_read_sfi_record(instance, sfi, record); error = emv_poller_read_sfi_record(instance, sfi, record);
if(error != EmvErrorNone) break; if(error != EmvErrorNone) break;
@@ -658,25 +659,21 @@ EmvError emv_poller_read_afl(EmvPoller* instance) {
FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record); FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record);
} }
if(instance->data->emv_application.pan_len) pan_fetched = true; // Card number fetched if(instance->data->emv_application.pan_len) {
pan_fetched = true;
break;
} // Card number fetched
} }
if(pan_fetched) break;
} }
bool cardholder_name_fetched = strlen(instance->data->emv_application.cardholder_name); } else { // BRUTFORCE FILES 2-3. SEARCH CARDHOLDER NAME
// Bruteforse files 2-3
FURI_LOG_T(TAG, "Bruteforce files 2-3"); FURI_LOG_T(TAG, "Bruteforce files 2-3");
for(size_t sfi = 2; sfi <= 3; sfi++) { for(size_t sfi = 2; sfi <= 3; sfi++) {
// Iterate through records 1-5 in file // Iterate through records 1-5 in file
for(size_t record = 1; record <= 5; record++) { for(size_t record = 1; record <= 5; record++) {
// Skip previously readed sfi // Skip previously readed sfi
if(sfi == 2) { if((*readed_mask >> (record + ((sfi - 2) * 8))) & (0b1)) continue;
if((sfi_2_mask >> record) & (0b1)) continue;
}
if(sfi == 3) {
if((sfi_3_mask >> record) & (0b1)) continue;
}
if(strlen(instance->data->emv_application.cardholder_name))
cardholder_name_fetched = true;
error = emv_poller_read_sfi_record(instance, sfi, record); error = emv_poller_read_sfi_record(instance, sfi, record);
if(error != EmvErrorNone) break; if(error != EmvErrorNone) break;
@@ -687,9 +684,14 @@ EmvError emv_poller_read_afl(EmvPoller* instance) {
error = EmvErrorProtocol; error = EmvErrorProtocol;
FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record); FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record);
} }
if(strlen(instance->data->emv_application.cardholder_name))
cardholder_name_fetched = true;
} }
} }
if(pan_fetched || cardholder_name_fetched) }
if((pan_fetched && (!bruteforce_sfi)) || (cardholder_name_fetched && bruteforce_sfi))
return EmvErrorNone; return EmvErrorNone;
else else
return error; return error;

View File

@@ -39,6 +39,7 @@ struct EmvPoller {
EmvPollerEvent emv_event; EmvPollerEvent emv_event;
NfcGenericEvent general_event; NfcGenericEvent general_event;
NfcGenericCallback callback; NfcGenericCallback callback;
uint16_t records_mask;
void* context; void* context;
}; };

View File

@@ -909,7 +909,7 @@ Function,+,emv_load,_Bool,"EmvData*, FlipperFormat*, uint32_t"
Function,+,emv_poller_get_last_online_atc,EmvError,EmvPoller* Function,+,emv_poller_get_last_online_atc,EmvError,EmvPoller*
Function,+,emv_poller_get_pin_try_counter,EmvError,EmvPoller* Function,+,emv_poller_get_pin_try_counter,EmvError,EmvPoller*
Function,+,emv_poller_get_processing_options,EmvError,EmvPoller* Function,+,emv_poller_get_processing_options,EmvError,EmvPoller*
Function,+,emv_poller_read_afl,EmvError,EmvPoller* Function,+,emv_poller_read_afl,EmvError,"EmvPoller*, _Bool, uint16_t*"
Function,+,emv_poller_read_log_entry,EmvError,EmvPoller* Function,+,emv_poller_read_log_entry,EmvError,EmvPoller*
Function,+,emv_poller_read_sfi_record,EmvError,"EmvPoller*, uint8_t, uint8_t" Function,+,emv_poller_read_sfi_record,EmvError,"EmvPoller*, uint8_t, uint8_t"
Function,+,emv_poller_select_application,EmvError,EmvPoller* Function,+,emv_poller_select_application,EmvError,EmvPoller*
1 entry status name type params
909 Function + emv_poller_get_last_online_atc EmvError EmvPoller*
910 Function + emv_poller_get_pin_try_counter EmvError EmvPoller*
911 Function + emv_poller_get_processing_options EmvError EmvPoller*
912 Function + emv_poller_read_afl EmvError EmvPoller* EmvPoller*, _Bool, uint16_t*
913 Function + emv_poller_read_log_entry EmvError EmvPoller*
914 Function + emv_poller_read_sfi_record EmvError EmvPoller*, uint8_t, uint8_t
915 Function + emv_poller_select_application EmvError EmvPoller*