mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-10 06:54:19 +00:00
read transactions fail on some cards fixed
This commit is contained in:
parent
c061fb1681
commit
7b01a33b3f
6 changed files with 72 additions and 64 deletions
|
@ -112,6 +112,7 @@ void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) {
|
|||
if(!apl->trans[i].amount) {
|
||||
furi_string_cat_printf(str, "???");
|
||||
} else {
|
||||
FURI_LOG_D("EMV Render", "Amount: %llX\n", apl->trans[i].amount);
|
||||
uint8_t amount_bytes[6];
|
||||
bit_lib_num_to_bytes_le(apl->trans[i].amount, 6, amount_bytes);
|
||||
|
||||
|
|
|
@ -99,7 +99,8 @@ static NfcCommand emv_poller_handler_get_processing_options(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);
|
||||
|
||||
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_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;
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
|
|
@ -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_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);
|
||||
|
||||
|
|
|
@ -621,75 +621,77 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re
|
|||
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;
|
||||
|
||||
APDU* afl = &instance->data->emv_application.afl;
|
||||
|
||||
if(afl->size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
for(size_t i = 0; i < instance->data->emv_application.afl.size; i += 4) {
|
||||
uint8_t sfi = afl->data[i] >> 3;
|
||||
uint8_t record_start = afl->data[i + 1];
|
||||
uint8_t record_end = afl->data[i + 2];
|
||||
// Iterate through all records in file
|
||||
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 < 8)) FURI_BIT_SET(sfi_3_mask, record);
|
||||
|
||||
error = emv_poller_read_sfi_record(instance, sfi, record);
|
||||
if(error != EmvErrorNone) break;
|
||||
|
||||
if(!emv_decode_response_tlv(
|
||||
bit_buffer_get_data(instance->rx_buffer),
|
||||
bit_buffer_get_size_bytes(instance->rx_buffer),
|
||||
&instance->data->emv_application)) {
|
||||
error = EmvErrorProtocol;
|
||||
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
|
||||
}
|
||||
}
|
||||
bool cardholder_name_fetched = strlen(instance->data->emv_application.cardholder_name);
|
||||
// Bruteforse files 2-3
|
||||
FURI_LOG_T(TAG, "Bruteforce files 2-3");
|
||||
for(size_t sfi = 2; sfi <= 3; sfi++) {
|
||||
// Iterate through records 1-5 in file
|
||||
for(size_t record = 1; record <= 5; record++) {
|
||||
// Skip previously readed sfi
|
||||
if(sfi == 2) {
|
||||
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);
|
||||
if(error != EmvErrorNone) break;
|
||||
if(!bruteforce_sfi) {
|
||||
// SEARCH PAN, RETURN WHEN FOUND
|
||||
APDU* afl = &instance->data->emv_application.afl;
|
||||
|
||||
if(!emv_decode_response_tlv(
|
||||
bit_buffer_get_data(instance->rx_buffer),
|
||||
bit_buffer_get_size_bytes(instance->rx_buffer),
|
||||
&instance->data->emv_application)) {
|
||||
error = EmvErrorProtocol;
|
||||
FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record);
|
||||
if(afl->size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FURI_LOG_D(TAG, "Search PAN in SFI");
|
||||
|
||||
// Iterate through all files
|
||||
for(size_t i = 0; i < instance->data->emv_application.afl.size; i += 4) {
|
||||
uint8_t sfi = afl->data[i] >> 3;
|
||||
uint8_t record_start = afl->data[i + 1];
|
||||
uint8_t record_end = afl->data[i + 2];
|
||||
// Iterate through all records in file
|
||||
for(uint8_t record = record_start; record <= record_end; ++record) {
|
||||
if((sfi <= 3) && (record <= 5))
|
||||
FURI_BIT_SET(
|
||||
*readed_mask,
|
||||
record + ((sfi - 2) * 8)); //black magic: mask 0003333300022222
|
||||
|
||||
error = emv_poller_read_sfi_record(instance, sfi, record);
|
||||
if(error != EmvErrorNone) break;
|
||||
|
||||
if(!emv_decode_response_tlv(
|
||||
bit_buffer_get_data(instance->rx_buffer),
|
||||
bit_buffer_get_size_bytes(instance->rx_buffer),
|
||||
&instance->data->emv_application)) {
|
||||
error = EmvErrorProtocol;
|
||||
FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record);
|
||||
}
|
||||
|
||||
if(instance->data->emv_application.pan_len) {
|
||||
pan_fetched = true;
|
||||
break;
|
||||
} // Card number fetched
|
||||
}
|
||||
if(pan_fetched) break;
|
||||
}
|
||||
} else { // BRUTFORCE FILES 2-3. SEARCH CARDHOLDER NAME
|
||||
FURI_LOG_T(TAG, "Bruteforce files 2-3");
|
||||
for(size_t sfi = 2; sfi <= 3; sfi++) {
|
||||
// Iterate through records 1-5 in file
|
||||
for(size_t record = 1; record <= 5; record++) {
|
||||
// Skip previously readed sfi
|
||||
if((*readed_mask >> (record + ((sfi - 2) * 8))) & (0b1)) continue;
|
||||
|
||||
error = emv_poller_read_sfi_record(instance, sfi, record);
|
||||
if(error != EmvErrorNone) break;
|
||||
|
||||
if(!emv_decode_response_tlv(
|
||||
bit_buffer_get_data(instance->rx_buffer),
|
||||
bit_buffer_get_size_bytes(instance->rx_buffer),
|
||||
&instance->data->emv_application)) {
|
||||
error = EmvErrorProtocol;
|
||||
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;
|
||||
else
|
||||
return error;
|
||||
|
|
|
@ -39,6 +39,7 @@ struct EmvPoller {
|
|||
EmvPollerEvent emv_event;
|
||||
NfcGenericEvent general_event;
|
||||
NfcGenericCallback callback;
|
||||
uint16_t records_mask;
|
||||
void* context;
|
||||
};
|
||||
|
||||
|
|
|
@ -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_pin_try_counter,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_sfi_record,EmvError,"EmvPoller*, uint8_t, uint8_t"
|
||||
Function,+,emv_poller_select_application,EmvError,EmvPoller*
|
||||
|
|
|
Loading…
Reference in a new issue