[FL-2933] Mf Classic initial write, update, detect reader (#1941)

* nfc: introduce nfc write
* nfc: add write logic
* nfc worker: add write state
* nfc: add mfc update logic
* nfc: add update success logic
* nfc: add custom card for detect reader
* nfc: update write logic
* nfc: add halt command, add notifications
* nfc: add write fail scene
* nfc: fixes and clean up
* nfc: fix navigation ad notifications
* nfc: fix detect reader nfc data setter

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
gornekich
2022-10-28 20:10:16 +04:00
committed by GitHub
parent 09b622d4ae
commit 93a6e17ce5
23 changed files with 949 additions and 93 deletions

View File

@@ -99,6 +99,10 @@ int32_t nfc_worker_task(void* context) {
nfc_worker_emulate_mf_ultralight(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateMfClassicEmulate) {
nfc_worker_emulate_mf_classic(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateMfClassicWrite) {
nfc_worker_write_mf_classic(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateMfClassicUpdate) {
nfc_worker_update_mf_classic(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadMfUltralightReadAuth) {
nfc_worker_mf_ultralight_read_auth(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) {
@@ -666,6 +670,144 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) {
rfal_platform_spi_release();
}
void nfc_worker_write_mf_classic(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {};
bool card_found_notified = false;
FuriHalNfcDevData nfc_data = {};
MfClassicData* src_data = &nfc_worker->dev_data->mf_classic_data;
MfClassicData dest_data = *src_data;
while(nfc_worker->state == NfcWorkerStateMfClassicWrite) {
if(furi_hal_nfc_detect(&nfc_data, 200)) {
if(!card_found_notified) {
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
card_found_notified = true;
}
furi_hal_nfc_sleep();
FURI_LOG_I(TAG, "Check low level nfc data");
if(memcmp(&nfc_data, &nfc_worker->dev_data->nfc_data, sizeof(FuriHalNfcDevData))) {
FURI_LOG_E(TAG, "Wrong card");
nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context);
break;
}
FURI_LOG_I(TAG, "Check mf classic type");
MfClassicType type =
mf_classic_get_classic_type(nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak);
if(type != nfc_worker->dev_data->mf_classic_data.type) {
FURI_LOG_E(TAG, "Wrong mf classic type");
nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context);
break;
}
// Set blocks not read
mf_classic_set_sector_data_not_read(&dest_data);
FURI_LOG_I(TAG, "Updating card sectors");
uint8_t total_sectors = mf_classic_get_total_sectors_num(type);
bool write_success = true;
for(uint8_t i = 0; i < total_sectors; i++) {
FURI_LOG_I(TAG, "Reading sector %d", i);
mf_classic_read_sector(&tx_rx, &dest_data, i);
bool old_data_read = mf_classic_is_sector_data_read(src_data, i);
bool new_data_read = mf_classic_is_sector_data_read(&dest_data, i);
if(old_data_read != new_data_read) {
FURI_LOG_E(TAG, "Failed to update sector %d", i);
write_success = false;
break;
}
if(nfc_worker->state != NfcWorkerStateMfClassicWrite) break;
if(!mf_classic_write_sector(&tx_rx, &dest_data, src_data, i)) {
FURI_LOG_E(TAG, "Failed to write %d sector", i);
write_success = false;
break;
}
}
if(nfc_worker->state != NfcWorkerStateMfClassicWrite) break;
if(write_success) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
break;
} else {
nfc_worker->callback(NfcWorkerEventFail, nfc_worker->context);
break;
}
} else {
if(card_found_notified) {
nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
card_found_notified = false;
}
}
furi_delay_ms(300);
}
}
void nfc_worker_update_mf_classic(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {};
bool card_found_notified = false;
FuriHalNfcDevData nfc_data = {};
MfClassicData* old_data = &nfc_worker->dev_data->mf_classic_data;
MfClassicData new_data = *old_data;
while(nfc_worker->state == NfcWorkerStateMfClassicUpdate) {
if(furi_hal_nfc_detect(&nfc_data, 200)) {
if(!card_found_notified) {
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
card_found_notified = true;
}
furi_hal_nfc_sleep();
FURI_LOG_I(TAG, "Check low level nfc data");
if(memcmp(&nfc_data, &nfc_worker->dev_data->nfc_data, sizeof(FuriHalNfcDevData))) {
FURI_LOG_E(TAG, "Low level nfc data mismatch");
nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context);
break;
}
FURI_LOG_I(TAG, "Check MF classic type");
MfClassicType type =
mf_classic_get_classic_type(nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak);
if(type != nfc_worker->dev_data->mf_classic_data.type) {
FURI_LOG_E(TAG, "MF classic type mismatch");
nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context);
break;
}
// Set blocks not read
mf_classic_set_sector_data_not_read(&new_data);
FURI_LOG_I(TAG, "Updating card sectors");
uint8_t total_sectors = mf_classic_get_total_sectors_num(type);
bool update_success = true;
for(uint8_t i = 0; i < total_sectors; i++) {
FURI_LOG_I(TAG, "Reading sector %d", i);
mf_classic_read_sector(&tx_rx, &new_data, i);
bool old_data_read = mf_classic_is_sector_data_read(old_data, i);
bool new_data_read = mf_classic_is_sector_data_read(&new_data, i);
if(old_data_read != new_data_read) {
FURI_LOG_E(TAG, "Failed to update sector %d", i);
update_success = false;
break;
}
if(nfc_worker->state != NfcWorkerStateMfClassicUpdate) break;
}
if(nfc_worker->state != NfcWorkerStateMfClassicUpdate) break;
// Check updated data
if(update_success) {
*old_data = new_data;
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
break;
}
} else {
if(card_found_notified) {
nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
card_found_notified = false;
}
}
furi_delay_ms(300);
}
}
void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) {
furi_assert(nfc_worker);
furi_assert(nfc_worker->callback);
@@ -758,7 +900,13 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {};
ReaderAnalyzer* reader_analyzer = nfc_worker->reader_analyzer;
FuriHalNfcDevData* nfc_data = reader_analyzer_get_nfc_data(reader_analyzer);
FuriHalNfcDevData* nfc_data = NULL;
if(nfc_worker->dev_data->protocol == NfcDeviceProtocolMifareClassic) {
nfc_data = &nfc_worker->dev_data->nfc_data;
reader_analyzer_set_nfc_data(reader_analyzer, nfc_data);
} else {
nfc_data = reader_analyzer_get_nfc_data(reader_analyzer);
}
MfClassicEmulator emulator = {
.cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4),
.data = nfc_worker->dev_data->mf_classic_data,