[FL-1643] NFC emv assets (#661)
* assets: add EMV AID table for NFC app * file-worker: add searching for value by the key * nfc: add emv parser helpers * assets: add country and currency codes * nfc: add country and currency code parsing * emv_decoder: add country and currency code support * nfc: add AID. currency and country display * nfc: rework bank_card view * nfc: add currency and country save * assets: change emv chip asset * nfc: change asset in bank card * gui: add frame element to widget * nfc: add bank card frame, add documentation * rfal: fix long APDU command emulation * nfc: fix typos * Scripts ReadMe: assets delivery command Co-authored-by: あく <alleteam@gmail.com> Co-authored-by: DrZlo13 <who.just.the.doctor@gmail.com>
This commit is contained in:
@@ -575,7 +575,9 @@ ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_
|
||||
*rvdLen = (uint16_t*)&gNfcDev.rxLen;
|
||||
*rxData = (uint8_t*)( (gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) ? gNfcDev.rxBuf.isoDepBuf.apdu :
|
||||
((gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_NFCDEP) ? gNfcDev.rxBuf.nfcDepBuf.pdu : gNfcDev.rxBuf.rfBuf));
|
||||
gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE_DONE;
|
||||
if(gNfcDev.disc.activate_after_sak) {
|
||||
gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE_DONE;
|
||||
}
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
|
@@ -71,6 +71,10 @@ bool FileWorkerCpp::read_until_buffered(string_t str_result, char* file_buf, siz
|
||||
return file_worker_read_until_buffered(file_worker, str_result, file_buf, file_buf_cnt, max_length, separator);
|
||||
}
|
||||
|
||||
bool FileWorkerCpp::get_value_from_key(string_t key, char delimiter, string_t value) {
|
||||
return file_worker_get_value_from_key(file_worker, key, delimiter, value);
|
||||
}
|
||||
|
||||
bool FileWorkerCpp::is_file_exist(const char* filename, bool* exist) {
|
||||
return file_worker_is_file_exist(file_worker, filename, exist);
|
||||
}
|
||||
|
@@ -143,6 +143,17 @@ public:
|
||||
*/
|
||||
bool read_until_buffered(string_t str_result, char* file_buf, size_t* file_buf_cnt, size_t max_length, char separator = '\n');
|
||||
|
||||
/**
|
||||
* @brief Gets value from key
|
||||
*
|
||||
* @param file_worker FileWorker instance
|
||||
* @param key key
|
||||
* @param delimeter key-value delimeter
|
||||
* @param value value for given key
|
||||
* @return true on success
|
||||
*/
|
||||
bool get_value_from_key(string_t key, char delimiter, string_t value);
|
||||
|
||||
/**
|
||||
* @brief Check whether file exist or not
|
||||
*
|
||||
|
@@ -355,6 +355,34 @@ bool file_worker_read_until_buffered(
|
||||
return string_size(str_result) || *file_buf_cnt;
|
||||
}
|
||||
|
||||
bool file_worker_get_value_from_key(FileWorker* file_worker, string_t key, char delimiter, string_t value) {
|
||||
bool found = false;
|
||||
string_t next_line;
|
||||
string_t next_key;
|
||||
string_init(next_line);
|
||||
string_init(next_key);
|
||||
size_t delim_pos = 0;
|
||||
|
||||
while(file_worker_read_until(file_worker, next_line, '\n')) {
|
||||
delim_pos = string_search_char(next_line, delimiter);
|
||||
if(delim_pos == STRING_FAILURE) {
|
||||
break;
|
||||
}
|
||||
string_set_n(next_key, next_line, 0, delim_pos);
|
||||
if(string_equal_p(next_key, key)) {
|
||||
string_right(next_line, delim_pos);
|
||||
string_strim(next_line);
|
||||
string_set(value, next_line);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string_clear(next_line);
|
||||
string_clear(next_key);
|
||||
return found;
|
||||
}
|
||||
|
||||
bool file_worker_rename(FileWorker* file_worker, const char* old_path, const char* new_path) {
|
||||
FS_Error fs_result = storage_common_rename(file_worker->api, old_path, new_path);
|
||||
|
||||
|
@@ -185,6 +185,17 @@ bool file_worker_read_until_buffered(
|
||||
size_t max_length,
|
||||
char separator);
|
||||
|
||||
/**
|
||||
* @brief Gets value from key
|
||||
*
|
||||
* @param file_worker FileWorker instance
|
||||
* @param key key
|
||||
* @param delimeter key-value delimeter
|
||||
* @param value value for given key
|
||||
* @return true on success
|
||||
*/
|
||||
bool file_worker_get_value_from_key(FileWorker* file_worker, string_t key, char delimiter, string_t value);
|
||||
|
||||
/**
|
||||
* @brief Check whether file exist or not
|
||||
*
|
||||
|
@@ -63,6 +63,14 @@ static uint16_t emv_parse_TLV(uint8_t* dest, uint8_t* src, uint16_t* idx) {
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool emv_decode_search_tag_u16_r(uint16_t tag, uint8_t* buff, uint16_t* idx) {
|
||||
if((buff[*idx] << 8 | buff[*idx + 1]) == tag) {
|
||||
*idx = *idx + 3;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t emv_prepare_select_ppse(uint8_t* dest) {
|
||||
const uint8_t emv_select_ppse[] = {
|
||||
0x00, 0xA4, // SELECT ppse
|
||||
@@ -219,10 +227,15 @@ bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app
|
||||
if(buff[i] == EMV_TAG_PAN) {
|
||||
memcpy(app->card_number, &buff[i + 2], 8);
|
||||
pan_parsed = true;
|
||||
} else if((buff[i] << 8 | buff[i + 1]) == EMV_TAG_EXP_DATE) {
|
||||
i += 3;
|
||||
} else if(emv_decode_search_tag_u16_r(EMV_TAG_EXP_DATE, buff, &i)) {
|
||||
app->exp_year = buff[i++];
|
||||
app->exp_month = buff[i++];
|
||||
} else if(emv_decode_search_tag_u16_r(EMV_TAG_CURRENCY_CODE, buff, &i)) {
|
||||
app->currency_code = (buff[i] << 8) | buff[i + 1];
|
||||
i += 2;
|
||||
} else if(emv_decode_search_tag_u16_r(EMV_TAG_COUNTRY_CODE, buff, &i)) {
|
||||
app->country_code = (buff[i] << 8) | buff[i + 1];
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
return pan_parsed;
|
||||
|
@@ -17,6 +17,8 @@
|
||||
#define EMV_TAG_PAN 0x5A
|
||||
#define EMV_TAG_AFL 0x94
|
||||
#define EMV_TAG_EXP_DATE 0x5F24
|
||||
#define EMV_TAG_COUNTRY_CODE 0x5F28
|
||||
#define EMV_TAG_CURRENCY_CODE 0x9F42
|
||||
#define EMV_TAG_CARDHOLDER_NAME 0x5F20
|
||||
|
||||
typedef struct {
|
||||
@@ -39,7 +41,8 @@ typedef struct {
|
||||
uint8_t card_number[8];
|
||||
uint8_t exp_month;
|
||||
uint8_t exp_year;
|
||||
char crdholder_name[32];
|
||||
uint16_t country_code;
|
||||
uint16_t currency_code;
|
||||
APDU pdol;
|
||||
APDU afl;
|
||||
} EmvApplication;
|
||||
|
Reference in New Issue
Block a user