[FL-2803] Mifare Classic read improvements Part 1 (#1822)

* Reuse found keys when reading a card
* Fix keys not being read if no newline at the end of the file
* Actually read all keys from the dictionary
* Support for furi_string
* Check only for re-used key after the current sector
* Declare the key attack function as static
* nfc: change logs, check worker state

Co-authored-by: gornekich <n.gorbadey@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Astra 2022-10-06 20:07:56 +03:00 committed by GitHub
parent 5de2c32c81
commit 6dde5586af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 2 deletions

View File

@ -69,9 +69,18 @@ MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) {
FuriString* next_line; FuriString* next_line;
next_line = furi_string_alloc(); next_line = furi_string_alloc();
while(true) { while(true) {
if(!stream_read_line(dict->stream, next_line)) break; if(!stream_read_line(dict->stream, next_line)) {
FURI_LOG_T(TAG, "No keys left in dict");
break;
}
furi_string_trim(next_line);
FURI_LOG_T(
TAG,
"Read line: %s, len: %d",
furi_string_get_cstr(next_line),
furi_string_size(next_line));
if(furi_string_get_char(next_line, 0) == '#') continue; if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN - 1) continue;
dict->total_keys++; dict->total_keys++;
} }
furi_string_free(next_line); furi_string_free(next_line);

View File

@ -453,6 +453,54 @@ void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) {
} }
} }
static void nfc_worker_mf_classic_key_attack(
NfcWorker* nfc_worker,
uint64_t key,
FuriHalNfcTxRxContext* tx_rx,
uint16_t start_sector) {
furi_assert(nfc_worker);
MfClassicData* data = &nfc_worker->dev_data->mf_classic_data;
uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type);
furi_assert(start_sector < total_sectors);
// Check every sector's A and B keys with the given key
for(size_t i = start_sector; i < total_sectors; i++) {
uint8_t block_num = mf_classic_get_sector_trailer_block_num_by_sector(i);
if(mf_classic_is_sector_read(data, i)) continue;
if(!mf_classic_is_key_found(data, i, MfClassicKeyA)) {
FURI_LOG_D(
TAG,
"Trying A key for sector %d, key: %04lx%08lx",
i,
(uint32_t)(key >> 32),
(uint32_t)key);
if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) {
mf_classic_set_key_found(data, i, MfClassicKeyA, key);
FURI_LOG_D(TAG, "Key found");
nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
}
}
if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) {
FURI_LOG_D(
TAG,
"Trying B key for sector %d, key: %04lx%08lx",
i,
(uint32_t)(key >> 32),
(uint32_t)key);
if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) {
mf_classic_set_key_found(data, i, MfClassicKeyB, key);
FURI_LOG_D(TAG, "Key found");
nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context);
}
}
if(mf_classic_is_sector_read(data, i)) continue;
mf_classic_read_sector(tx_rx, data, i);
if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break;
}
}
void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
furi_assert(nfc_worker); furi_assert(nfc_worker);
furi_assert(nfc_worker->callback); furi_assert(nfc_worker->callback);
@ -484,6 +532,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
bool is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); bool is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB);
uint16_t key_index = 0; uint16_t key_index = 0;
while(mf_classic_dict_get_next_key(dict, &key)) { while(mf_classic_dict_get_next_key(dict, &key)) {
FURI_LOG_T(TAG, "Key %d", key_index);
if(++key_index % NFC_DICT_KEY_BATCH_SIZE == 0) { if(++key_index % NFC_DICT_KEY_BATCH_SIZE == 0) {
nfc_worker->callback(NfcWorkerEventNewDictKeyBatch, nfc_worker->context); nfc_worker->callback(NfcWorkerEventNewDictKeyBatch, nfc_worker->context);
} }
@ -505,15 +554,19 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
is_key_a_found = mf_classic_is_key_found(data, i, MfClassicKeyA); is_key_a_found = mf_classic_is_key_found(data, i, MfClassicKeyA);
if(mf_classic_authenticate(&tx_rx, block_num, key, MfClassicKeyA)) { if(mf_classic_authenticate(&tx_rx, block_num, key, MfClassicKeyA)) {
mf_classic_set_key_found(data, i, MfClassicKeyA, key); mf_classic_set_key_found(data, i, MfClassicKeyA, key);
FURI_LOG_D(TAG, "Key found");
nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1);
} }
furi_hal_nfc_sleep(); furi_hal_nfc_sleep();
} }
if(!is_key_b_found) { if(!is_key_b_found) {
is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB);
if(mf_classic_authenticate(&tx_rx, block_num, key, MfClassicKeyB)) { if(mf_classic_authenticate(&tx_rx, block_num, key, MfClassicKeyB)) {
FURI_LOG_D(TAG, "Key found");
mf_classic_set_key_found(data, i, MfClassicKeyB, key); mf_classic_set_key_found(data, i, MfClassicKeyB, key);
nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context);
nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1);
} }
} }
if(is_key_a_found && is_key_b_found) break; if(is_key_a_found && is_key_b_found) break;