|
@@ -1,8 +1,13 @@
|
|
|
#include "nfc_worker_i.h"
|
|
#include "nfc_worker_i.h"
|
|
|
#include <furi_hal.h>
|
|
#include <furi_hal.h>
|
|
|
-#include "nfc_protocols/emv_decoder.h"
|
|
|
|
|
-#include "nfc_protocols/mifare_desfire.h"
|
|
|
|
|
-#include "nfc_protocols/mifare_ultralight.h"
|
|
|
|
|
|
|
+
|
|
|
|
|
+#include <lib/nfc_protocols/nfc_util.h>
|
|
|
|
|
+#include <lib/nfc_protocols/emv_decoder.h>
|
|
|
|
|
+#include <lib/nfc_protocols/mifare_ultralight.h>
|
|
|
|
|
+#include <lib/nfc_protocols/mifare_classic.h>
|
|
|
|
|
+#include <lib/nfc_protocols/mifare_desfire.h>
|
|
|
|
|
+
|
|
|
|
|
+#include "helpers/nfc_mf_classic_dict.h"
|
|
|
|
|
|
|
|
#define TAG "NfcWorker"
|
|
#define TAG "NfcWorker"
|
|
|
|
|
|
|
@@ -20,6 +25,7 @@ NfcWorker* nfc_worker_alloc() {
|
|
|
|
|
|
|
|
nfc_worker->callback = NULL;
|
|
nfc_worker->callback = NULL;
|
|
|
nfc_worker->context = NULL;
|
|
nfc_worker->context = NULL;
|
|
|
|
|
+ nfc_worker->storage = furi_record_open("storage");
|
|
|
|
|
|
|
|
// Initialize rfal
|
|
// Initialize rfal
|
|
|
while(furi_hal_nfc_is_busy()) {
|
|
while(furi_hal_nfc_is_busy()) {
|
|
@@ -33,6 +39,7 @@ NfcWorker* nfc_worker_alloc() {
|
|
|
void nfc_worker_free(NfcWorker* nfc_worker) {
|
|
void nfc_worker_free(NfcWorker* nfc_worker) {
|
|
|
furi_assert(nfc_worker);
|
|
furi_assert(nfc_worker);
|
|
|
furi_thread_free(nfc_worker->thread);
|
|
furi_thread_free(nfc_worker->thread);
|
|
|
|
|
+ furi_record_close("storage");
|
|
|
free(nfc_worker);
|
|
free(nfc_worker);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -95,6 +102,8 @@ int32_t nfc_worker_task(void* context) {
|
|
|
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) {
|
|
|
nfc_worker_emulate_mifare_ul(nfc_worker);
|
|
nfc_worker_emulate_mifare_ul(nfc_worker);
|
|
|
|
|
+ } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
|
|
|
|
+ nfc_worker_mifare_classic_dict_attack(nfc_worker);
|
|
|
} else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
|
|
} else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
|
|
|
nfc_worker_read_mifare_desfire(nfc_worker);
|
|
nfc_worker_read_mifare_desfire(nfc_worker);
|
|
|
} else if(nfc_worker->state == NfcWorkerStateField) {
|
|
} else if(nfc_worker->state == NfcWorkerStateField) {
|
|
@@ -130,6 +139,11 @@ void nfc_worker_detect(NfcWorker* nfc_worker) {
|
|
|
dev->dev.nfca.sensRes.platformInfo,
|
|
dev->dev.nfca.sensRes.platformInfo,
|
|
|
dev->dev.nfca.selRes.sak)) {
|
|
dev->dev.nfca.selRes.sak)) {
|
|
|
result->protocol = NfcDeviceProtocolMifareUl;
|
|
result->protocol = NfcDeviceProtocolMifareUl;
|
|
|
|
|
+ } else if(mf_classic_check_card_type(
|
|
|
|
|
+ dev->dev.nfca.sensRes.anticollisionInfo,
|
|
|
|
|
+ dev->dev.nfca.sensRes.platformInfo,
|
|
|
|
|
+ dev->dev.nfca.selRes.sak)) {
|
|
|
|
|
+ result->protocol = NfcDeviceProtocolMifareClassic;
|
|
|
} else if(mf_df_check_card_type(
|
|
} else if(mf_df_check_card_type(
|
|
|
dev->dev.nfca.sensRes.anticollisionInfo,
|
|
dev->dev.nfca.sensRes.anticollisionInfo,
|
|
|
dev->dev.nfca.sensRes.platformInfo,
|
|
dev->dev.nfca.sensRes.platformInfo,
|
|
@@ -149,7 +163,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) {
|
|
|
}
|
|
}
|
|
|
// 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(NfcWorkerEventSuccess, nfc_worker->context);
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
@@ -171,7 +185,7 @@ bool nfc_worker_emulate_uid_callback(
|
|
|
if(reader_data->size > 0) {
|
|
if(reader_data->size > 0) {
|
|
|
memcpy(reader_data->data, buff_rx, reader_data->size);
|
|
memcpy(reader_data->data, buff_rx, reader_data->size);
|
|
|
if(nfc_worker->callback) {
|
|
if(nfc_worker->callback) {
|
|
|
- nfc_worker->callback(nfc_worker->context);
|
|
|
|
|
|
|
+ nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
return true;
|
|
return true;
|
|
@@ -231,7 +245,7 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
|
|
|
result->emv_data.aid_len = emv_app.aid_len;
|
|
result->emv_data.aid_len = emv_app.aid_len;
|
|
|
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
|
|
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
|
|
|
if(nfc_worker->callback) {
|
|
if(nfc_worker->callback) {
|
|
|
- nfc_worker->callback(nfc_worker->context);
|
|
|
|
|
|
|
+ nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
} else {
|
|
} else {
|
|
@@ -329,7 +343,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
|
|
memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len);
|
|
memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len);
|
|
|
// 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(NfcWorkerEventSuccess, nfc_worker->context);
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
} else {
|
|
} else {
|
|
@@ -378,7 +392,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
|
|
}
|
|
}
|
|
|
// 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(NfcWorkerEventSuccess, nfc_worker->context);
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
} else {
|
|
} else {
|
|
@@ -633,7 +647,7 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) {
|
|
|
|
|
|
|
|
// 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(NfcWorkerEventSuccess, nfc_worker->context);
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
} else {
|
|
} else {
|
|
@@ -663,13 +677,166 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
|
|
|
if(mf_ul_emulate.data_changed) {
|
|
if(mf_ul_emulate.data_changed) {
|
|
|
nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data;
|
|
nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data;
|
|
|
if(nfc_worker->callback) {
|
|
if(nfc_worker->callback) {
|
|
|
- nfc_worker->callback(nfc_worker->context);
|
|
|
|
|
|
|
+ nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
|
}
|
|
}
|
|
|
mf_ul_emulate.data_changed = false;
|
|
mf_ul_emulate.data_changed = false;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
|
|
|
|
|
+ furi_assert(nfc_worker->callback);
|
|
|
|
|
+ rfalNfcDevice* dev_list;
|
|
|
|
|
+ rfalNfcDevice* dev;
|
|
|
|
|
+ NfcDeviceCommonData* nfc_common;
|
|
|
|
|
+ uint8_t dev_cnt = 0;
|
|
|
|
|
+ FuriHalNfcTxRxContext tx_rx_ctx = {};
|
|
|
|
|
+ MfClassicAuthContext auth_ctx = {};
|
|
|
|
|
+ MfClassicReader reader = {};
|
|
|
|
|
+ uint64_t curr_key = 0;
|
|
|
|
|
+ uint16_t curr_sector = 0;
|
|
|
|
|
+ uint8_t total_sectors = 0;
|
|
|
|
|
+ NfcWorkerEvent event;
|
|
|
|
|
+
|
|
|
|
|
+ // Open dictionary
|
|
|
|
|
+ nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage);
|
|
|
|
|
+ if(!nfc_mf_classic_dict_open_file(nfc_worker->dict_stream)) {
|
|
|
|
|
+ event = NfcWorkerEventNoDictFound;
|
|
|
|
|
+ nfc_worker->callback(event, nfc_worker->context);
|
|
|
|
|
+ nfc_mf_classic_dict_close_file(nfc_worker->dict_stream);
|
|
|
|
|
+ stream_free(nfc_worker->dict_stream);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Detect Mifare Classic card
|
|
|
|
|
+ while(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
|
|
|
|
+ if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
|
|
|
|
|
+ dev = &dev_list[0];
|
|
|
|
|
+ if(mf_classic_get_type(
|
|
|
|
|
+ dev->nfcid,
|
|
|
|
|
+ dev->nfcidLen,
|
|
|
|
|
+ dev->dev.nfca.sensRes.anticollisionInfo,
|
|
|
|
|
+ dev->dev.nfca.sensRes.platformInfo,
|
|
|
|
|
+ dev->dev.nfca.selRes.sak,
|
|
|
|
|
+ &reader)) {
|
|
|
|
|
+ total_sectors = mf_classic_get_total_sectors_num(&reader);
|
|
|
|
|
+ if(reader.type == MfClassicType1k) {
|
|
|
|
|
+ event = NfcWorkerEventDetectedClassic1k;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ event = NfcWorkerEventDetectedClassic4k;
|
|
|
|
|
+ }
|
|
|
|
|
+ nfc_worker->callback(event, nfc_worker->context);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ event = NfcWorkerEventNoCardDetected;
|
|
|
|
|
+ nfc_worker->callback(event, nfc_worker->context);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
|
|
|
|
+ bool card_removed_notified = false;
|
|
|
|
|
+ bool card_found_notified = false;
|
|
|
|
|
+ // Seek for mifare classic keys
|
|
|
|
|
+ for(curr_sector = 0; curr_sector < total_sectors; curr_sector++) {
|
|
|
|
|
+ FURI_LOG_I(TAG, "Sector: %d ...", curr_sector);
|
|
|
|
|
+ event = NfcWorkerEventNewSector;
|
|
|
|
|
+ nfc_worker->callback(event, nfc_worker->context);
|
|
|
|
|
+ mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector);
|
|
|
|
|
+ bool sector_key_found = false;
|
|
|
|
|
+ while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) {
|
|
|
|
|
+ furi_hal_nfc_deactivate();
|
|
|
|
|
+ if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) {
|
|
|
|
|
+ if(!card_found_notified) {
|
|
|
|
|
+ if(reader.type == MfClassicType1k) {
|
|
|
|
|
+ event = NfcWorkerEventDetectedClassic1k;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ event = NfcWorkerEventDetectedClassic4k;
|
|
|
|
|
+ }
|
|
|
|
|
+ nfc_worker->callback(event, nfc_worker->context);
|
|
|
|
|
+ card_found_notified = true;
|
|
|
|
|
+ card_removed_notified = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ FURI_LOG_D(
|
|
|
|
|
+ TAG,
|
|
|
|
|
+ "Try to auth to sector %d with key %04lx%08lx",
|
|
|
|
|
+ curr_sector,
|
|
|
|
|
+ (uint32_t)(curr_key >> 32),
|
|
|
|
|
+ (uint32_t)curr_key);
|
|
|
|
|
+ if(mf_classic_auth_attempt(&tx_rx_ctx, &auth_ctx, curr_key)) {
|
|
|
|
|
+ sector_key_found = true;
|
|
|
|
|
+ if((auth_ctx.key_a != MF_CLASSIC_NO_KEY) &&
|
|
|
|
|
+ (auth_ctx.key_b != MF_CLASSIC_NO_KEY))
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Notify that no tag is availalble
|
|
|
|
|
+ FURI_LOG_D(TAG, "Can't find tags");
|
|
|
|
|
+ if(!card_removed_notified) {
|
|
|
|
|
+ event = NfcWorkerEventNoCardDetected;
|
|
|
|
|
+ nfc_worker->callback(event, nfc_worker->context);
|
|
|
|
|
+ card_removed_notified = true;
|
|
|
|
|
+ card_found_notified = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if(nfc_worker->state != NfcWorkerStateReadMifareClassic) break;
|
|
|
|
|
+ }
|
|
|
|
|
+ if(nfc_worker->state != NfcWorkerStateReadMifareClassic) break;
|
|
|
|
|
+ if(sector_key_found) {
|
|
|
|
|
+ // Notify that keys were found
|
|
|
|
|
+ if(auth_ctx.key_a != MF_CLASSIC_NO_KEY) {
|
|
|
|
|
+ FURI_LOG_I(
|
|
|
|
|
+ TAG,
|
|
|
|
|
+ "Sector %d key A: %04lx%08lx",
|
|
|
|
|
+ curr_sector,
|
|
|
|
|
+ (uint32_t)(auth_ctx.key_a >> 32),
|
|
|
|
|
+ (uint32_t)auth_ctx.key_a);
|
|
|
|
|
+ event = NfcWorkerEventFoundKeyA;
|
|
|
|
|
+ nfc_worker->callback(event, nfc_worker->context);
|
|
|
|
|
+ }
|
|
|
|
|
+ if(auth_ctx.key_b != MF_CLASSIC_NO_KEY) {
|
|
|
|
|
+ FURI_LOG_I(
|
|
|
|
|
+ TAG,
|
|
|
|
|
+ "Sector %d key B: %04lx%08lx",
|
|
|
|
|
+ curr_sector,
|
|
|
|
|
+ (uint32_t)(auth_ctx.key_b >> 32),
|
|
|
|
|
+ (uint32_t)auth_ctx.key_b);
|
|
|
|
|
+ event = NfcWorkerEventFoundKeyB;
|
|
|
|
|
+ nfc_worker->callback(event, nfc_worker->context);
|
|
|
|
|
+ }
|
|
|
|
|
+ // Add sectors to read sequence
|
|
|
|
|
+ mf_classic_reader_add_sector(&reader, curr_sector, auth_ctx.key_a, auth_ctx.key_b);
|
|
|
|
|
+ }
|
|
|
|
|
+ nfc_mf_classic_dict_reset(nfc_worker->dict_stream);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
|
|
|
|
+ FURI_LOG_I(TAG, "Found keys to %d sectors. Start reading sectors", reader.sectors_to_read);
|
|
|
|
|
+ uint8_t sectors_read =
|
|
|
|
|
+ mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data);
|
|
|
|
|
+ if(sectors_read) {
|
|
|
|
|
+ dev = &dev_list[0];
|
|
|
|
|
+ nfc_common = &nfc_worker->dev_data->nfc_data;
|
|
|
|
|
+ nfc_common->uid_len = dev->dev.nfca.nfcId1Len;
|
|
|
|
|
+ nfc_common->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo;
|
|
|
|
|
+ nfc_common->atqa[1] = dev->dev.nfca.sensRes.platformInfo;
|
|
|
|
|
+ nfc_common->sak = dev->dev.nfca.selRes.sak;
|
|
|
|
|
+ nfc_common->protocol = NfcDeviceProtocolMifareClassic;
|
|
|
|
|
+ memcpy(nfc_common->uid, dev->dev.nfca.nfcId1, nfc_common->uid_len);
|
|
|
|
|
+ event = NfcWorkerEventSuccess;
|
|
|
|
|
+ FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ event = NfcWorkerEventFail;
|
|
|
|
|
+ FURI_LOG_W(TAG, "Failed to read any sector");
|
|
|
|
|
+ }
|
|
|
|
|
+ nfc_worker->callback(event, nfc_worker->context);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ nfc_mf_classic_dict_close_file(nfc_worker->dict_stream);
|
|
|
|
|
+ stream_free(nfc_worker->dict_stream);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
ReturnCode nfc_exchange_full(
|
|
ReturnCode nfc_exchange_full(
|
|
|
uint8_t* tx_buff,
|
|
uint8_t* tx_buff,
|
|
|
uint16_t tx_len,
|
|
uint16_t tx_len,
|
|
@@ -900,7 +1067,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|
|
|
|
|
|
|
// 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(NfcWorkerEventSuccess, nfc_worker->context);
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|