|
@@ -81,8 +81,8 @@ void nfc_worker_task(void* context) {
|
|
|
nfc_worker_read_emv_app(nfc_worker);
|
|
nfc_worker_read_emv_app(nfc_worker);
|
|
|
} else if(nfc_worker->state == NfcWorkerStateReadEMV) {
|
|
} else if(nfc_worker->state == NfcWorkerStateReadEMV) {
|
|
|
nfc_worker_read_emv(nfc_worker);
|
|
nfc_worker_read_emv(nfc_worker);
|
|
|
- } else if(nfc_worker->state == NfcWorkerStateEmulateEMV) {
|
|
|
|
|
- nfc_worker_emulate_emv(nfc_worker);
|
|
|
|
|
|
|
+ } else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
|
|
|
|
+ nfc_worker_emulate_apdu(nfc_worker);
|
|
|
} else if(nfc_worker->state == NfcWorkerStateReadMifareUl) {
|
|
} else if(nfc_worker->state == NfcWorkerStateReadMifareUl) {
|
|
|
nfc_worker_read_mifare_ul(nfc_worker);
|
|
nfc_worker_read_mifare_ul(nfc_worker);
|
|
|
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
|
|
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
|
|
@@ -324,6 +324,10 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
|
|
result->emv_data.number,
|
|
result->emv_data.number,
|
|
|
emv_app.card_number,
|
|
emv_app.card_number,
|
|
|
sizeof(emv_app.card_number));
|
|
sizeof(emv_app.card_number));
|
|
|
|
|
+ if(emv_app.exp_month) {
|
|
|
|
|
+ result->emv_data.exp_mon = emv_app.exp_month;
|
|
|
|
|
+ result->emv_data.exp_year = emv_app.exp_year;
|
|
|
|
|
+ }
|
|
|
// Notify caller and exit
|
|
// Notify caller and exit
|
|
|
if(nfc_worker->callback) {
|
|
if(nfc_worker->callback) {
|
|
|
nfc_worker->callback(nfc_worker->context);
|
|
nfc_worker->callback(nfc_worker->context);
|
|
@@ -348,7 +352,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void nfc_worker_emulate_emv(NfcWorker* nfc_worker) {
|
|
|
|
|
|
|
+void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
|
|
|
ReturnCode err;
|
|
ReturnCode err;
|
|
|
uint8_t tx_buff[255] = {};
|
|
uint8_t tx_buff[255] = {};
|
|
|
uint16_t tx_len = 0;
|
|
uint16_t tx_len = 0;
|
|
@@ -362,8 +366,46 @@ void nfc_worker_emulate_emv(NfcWorker* nfc_worker) {
|
|
|
.device = NfcDeviceNfca,
|
|
.device = NfcDeviceNfca,
|
|
|
.protocol = NfcDeviceProtocolEMV,
|
|
.protocol = NfcDeviceProtocolEMV,
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
- while(nfc_worker->state == NfcWorkerStateEmulateEMV) {
|
|
|
|
|
|
|
+ // Test RX data
|
|
|
|
|
+ const uint8_t debug_rx[] = {
|
|
|
|
|
+ 0xba, 0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca,
|
|
|
|
|
+ 0xca, 0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
|
|
|
|
|
+ 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba,
|
|
|
|
|
+ 0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca,
|
|
|
|
|
+ 0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
|
|
|
|
|
+ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b,
|
|
|
|
|
+ 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe,
|
|
|
|
|
+ 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
|
|
|
|
|
+ 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba,
|
|
|
|
|
+ 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa,
|
|
|
|
|
+ 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
|
|
|
|
|
+ 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba,
|
|
|
|
|
+ 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce,
|
|
|
|
|
+ 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
|
|
|
|
|
+ 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba, 0x20,
|
|
|
|
|
+ 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce, 0x14,
|
|
|
|
|
+ 0x88, 0x00};
|
|
|
|
|
+ // Test TX data
|
|
|
|
|
+ const uint8_t debug_tx[] = {
|
|
|
|
|
+ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
|
|
|
|
|
+ 0x10, 0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad,
|
|
|
|
|
+ 0xbe, 0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12,
|
|
|
|
|
+ 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
|
|
|
|
|
+ 0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe,
|
|
|
|
|
+ 0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34,
|
|
|
|
|
+ 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14,
|
|
|
|
|
+ 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef,
|
|
|
|
|
+ 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56,
|
|
|
|
|
+ 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88,
|
|
|
|
|
+ 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce,
|
|
|
|
|
+ 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78,
|
|
|
|
|
+ 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02,
|
|
|
|
|
+ 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce, 0xee,
|
|
|
|
|
+ 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78, 0x9a,
|
|
|
|
|
+ 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02, 0x28,
|
|
|
|
|
+ 0x00, 0x00};
|
|
|
|
|
+
|
|
|
|
|
+ while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
|
|
if(api_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 300)) {
|
|
if(api_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 300)) {
|
|
|
FURI_LOG_I(NFC_WORKER_TAG, "POS terminal detected");
|
|
FURI_LOG_I(NFC_WORKER_TAG, "POS terminal detected");
|
|
|
// Read data from POS terminal
|
|
// Read data from POS terminal
|
|
@@ -401,7 +443,23 @@ void nfc_worker_emulate_emv(NfcWorker* nfc_worker) {
|
|
|
tx_len = emv_get_proc_opt_ans(tx_buff);
|
|
tx_len = emv_get_proc_opt_ans(tx_buff);
|
|
|
err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
|
if(err == ERR_NONE) {
|
|
if(err == ERR_NONE) {
|
|
|
- FURI_LOG_I(NFC_WORKER_TAG, "Received PDOL");
|
|
|
|
|
|
|
+ FURI_LOG_I(NFC_WORKER_TAG, "Transive PDOL ANS");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ FURI_LOG_E(NFC_WORKER_TAG, "Error in 4rd data exchange: Transive PDOL ANS");
|
|
|
|
|
+ api_hal_nfc_deactivate();
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(*rx_len != sizeof(debug_rx) || memcmp(rx_buff, debug_rx, sizeof(debug_rx))) {
|
|
|
|
|
+ FURI_LOG_E(NFC_WORKER_TAG, "Failed long message test");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ FURI_LOG_I(NFC_WORKER_TAG, "Correct debug message received");
|
|
|
|
|
+ tx_len = sizeof(debug_tx);
|
|
|
|
|
+ err = api_hal_nfc_data_exchange(
|
|
|
|
|
+ (uint8_t*)debug_tx, tx_len, &rx_buff, &rx_len, false);
|
|
|
|
|
+ if(err == ERR_NONE) {
|
|
|
|
|
+ FURI_LOG_I(NFC_WORKER_TAG, "Transive Debug message");
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
api_hal_nfc_deactivate();
|
|
api_hal_nfc_deactivate();
|
|
|
} else {
|
|
} else {
|