NFC: Support reading Mifare Classic key B from sector trailer, reading sector with B key where A key can't read block, Nfc Magic app not using NFC folder by default (in file select) (#2437)
* NFC: Support reading Mifare Classic key B from sector trailer and reusing it for other sectors * NFC: Fix my pointer typo * NFC: Fix reading sector with B key where A key can't read block (fixes #2413) and fix Nfc Magic app not using NFC folder by default (in file select) * NFC: Fix strange bug Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
parent
9819306731
commit
eb5dae1cda
@ -11,6 +11,10 @@ void nfc_magic_scene_file_select_on_enter(void* context) {
|
|||||||
// Process file_select return
|
// Process file_select return
|
||||||
nfc_device_set_loading_callback(nfc_magic->nfc_dev, nfc_magic_show_loading_popup, nfc_magic);
|
nfc_device_set_loading_callback(nfc_magic->nfc_dev, nfc_magic_show_loading_popup, nfc_magic);
|
||||||
|
|
||||||
|
if(!furi_string_size(nfc_magic->nfc_dev->load_path)) {
|
||||||
|
furi_string_set_str(nfc_magic->nfc_dev->load_path, NFC_APP_FOLDER);
|
||||||
|
}
|
||||||
|
|
||||||
if(nfc_file_select(nfc_magic->nfc_dev)) {
|
if(nfc_file_select(nfc_magic->nfc_dev)) {
|
||||||
if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic->nfc_dev)) {
|
if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic->nfc_dev)) {
|
||||||
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm);
|
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm);
|
||||||
|
@ -1892,7 +1892,7 @@ Function,+,menu_free,void,Menu*
|
|||||||
Function,+,menu_get_view,View*,Menu*
|
Function,+,menu_get_view,View*,Menu*
|
||||||
Function,+,menu_reset,void,Menu*
|
Function,+,menu_reset,void,Menu*
|
||||||
Function,+,menu_set_selected_item,void,"Menu*, uint32_t"
|
Function,+,menu_set_selected_item,void,"Menu*, uint32_t"
|
||||||
Function,-,mf_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, MfClassicAuthContext*, uint64_t"
|
Function,-,mf_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, MfClassicAuthContext*, uint64_t"
|
||||||
Function,-,mf_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t"
|
Function,-,mf_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t"
|
||||||
Function,-,mf_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t"
|
Function,-,mf_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t"
|
||||||
Function,-,mf_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey"
|
Function,-,mf_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey"
|
||||||
|
|
@ -569,6 +569,32 @@ void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool nfc_worker_mf_get_b_key_from_sector_trailer(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
uint16_t sector,
|
||||||
|
uint64_t key,
|
||||||
|
uint64_t* found_key) {
|
||||||
|
// Some access conditions allow reading B key via A key
|
||||||
|
|
||||||
|
uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector);
|
||||||
|
|
||||||
|
Crypto1 crypto = {};
|
||||||
|
MfClassicBlock block_tmp = {};
|
||||||
|
MfClassicAuthContext auth_context = {.sector = sector, .key_a = MF_CLASSIC_NO_KEY, .key_b = 0};
|
||||||
|
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
|
||||||
|
if(mf_classic_auth_attempt(tx_rx, &crypto, &auth_context, key)) {
|
||||||
|
if(mf_classic_read_block(tx_rx, &crypto, block, &block_tmp)) {
|
||||||
|
*found_key = nfc_util_bytes2num(&block_tmp.value[10], sizeof(uint8_t) * 6);
|
||||||
|
|
||||||
|
return *found_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void nfc_worker_mf_classic_key_attack(
|
static void nfc_worker_mf_classic_key_attack(
|
||||||
NfcWorker* nfc_worker,
|
NfcWorker* nfc_worker,
|
||||||
uint64_t key,
|
uint64_t key,
|
||||||
@ -614,6 +640,16 @@ static void nfc_worker_mf_classic_key_attack(
|
|||||||
mf_classic_set_key_found(data, i, MfClassicKeyA, key);
|
mf_classic_set_key_found(data, i, MfClassicKeyA, key);
|
||||||
FURI_LOG_D(TAG, "Key found");
|
FURI_LOG_D(TAG, "Key found");
|
||||||
nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
|
nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
|
||||||
|
|
||||||
|
uint64_t found_key;
|
||||||
|
if(nfc_worker_mf_get_b_key_from_sector_trailer(tx_rx, i, key, &found_key)) {
|
||||||
|
FURI_LOG_D(TAG, "Found B key via reading sector %d", i);
|
||||||
|
mf_classic_set_key_found(data, i, MfClassicKeyB, found_key);
|
||||||
|
|
||||||
|
if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) {
|
if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) {
|
||||||
@ -705,6 +741,19 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
|
|||||||
mf_classic_set_key_found(data, i, MfClassicKeyA, key);
|
mf_classic_set_key_found(data, i, MfClassicKeyA, key);
|
||||||
FURI_LOG_D(TAG, "Key found");
|
FURI_LOG_D(TAG, "Key found");
|
||||||
nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
|
nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
|
||||||
|
|
||||||
|
uint64_t found_key;
|
||||||
|
if(nfc_worker_mf_get_b_key_from_sector_trailer(
|
||||||
|
&tx_rx, i, key, &found_key)) {
|
||||||
|
FURI_LOG_D(TAG, "Found B key via reading sector %d", i);
|
||||||
|
mf_classic_set_key_found(data, i, MfClassicKeyB, found_key);
|
||||||
|
|
||||||
|
if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfc_worker_mf_classic_key_attack(nfc_worker, found_key, &tx_rx, i + 1);
|
||||||
|
}
|
||||||
nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1);
|
nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1);
|
||||||
}
|
}
|
||||||
furi_hal_nfc_sleep();
|
furi_hal_nfc_sleep();
|
||||||
|
@ -541,6 +541,7 @@ bool mf_classic_authenticate_skip_activate(
|
|||||||
|
|
||||||
bool mf_classic_auth_attempt(
|
bool mf_classic_auth_attempt(
|
||||||
FuriHalNfcTxRxContext* tx_rx,
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
Crypto1* crypto,
|
||||||
MfClassicAuthContext* auth_ctx,
|
MfClassicAuthContext* auth_ctx,
|
||||||
uint64_t key) {
|
uint64_t key) {
|
||||||
furi_assert(tx_rx);
|
furi_assert(tx_rx);
|
||||||
@ -549,15 +550,14 @@ bool mf_classic_auth_attempt(
|
|||||||
bool need_halt = (auth_ctx->key_a == MF_CLASSIC_NO_KEY) &&
|
bool need_halt = (auth_ctx->key_a == MF_CLASSIC_NO_KEY) &&
|
||||||
(auth_ctx->key_b == MF_CLASSIC_NO_KEY);
|
(auth_ctx->key_b == MF_CLASSIC_NO_KEY);
|
||||||
|
|
||||||
Crypto1 crypto;
|
|
||||||
if(auth_ctx->key_a == MF_CLASSIC_NO_KEY) {
|
if(auth_ctx->key_a == MF_CLASSIC_NO_KEY) {
|
||||||
// Try AUTH with key A
|
// Try AUTH with key A
|
||||||
if(mf_classic_auth(
|
if(mf_classic_auth(
|
||||||
tx_rx,
|
tx_rx,
|
||||||
mf_classic_get_first_block_num_of_sector(auth_ctx->sector),
|
mf_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector),
|
||||||
key,
|
key,
|
||||||
MfClassicKeyA,
|
MfClassicKeyA,
|
||||||
&crypto,
|
crypto,
|
||||||
false,
|
false,
|
||||||
0)) {
|
0)) {
|
||||||
auth_ctx->key_a = key;
|
auth_ctx->key_a = key;
|
||||||
@ -573,10 +573,10 @@ bool mf_classic_auth_attempt(
|
|||||||
// Try AUTH with key B
|
// Try AUTH with key B
|
||||||
if(mf_classic_auth(
|
if(mf_classic_auth(
|
||||||
tx_rx,
|
tx_rx,
|
||||||
mf_classic_get_first_block_num_of_sector(auth_ctx->sector),
|
mf_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector),
|
||||||
key,
|
key,
|
||||||
MfClassicKeyB,
|
MfClassicKeyB,
|
||||||
&crypto,
|
crypto,
|
||||||
false,
|
false,
|
||||||
0)) {
|
0)) {
|
||||||
auth_ctx->key_b = key;
|
auth_ctx->key_b = key;
|
||||||
@ -671,6 +671,9 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u
|
|||||||
do {
|
do {
|
||||||
if(blocks_read == total_blocks) break;
|
if(blocks_read == total_blocks) break;
|
||||||
if(!key_b_found) break;
|
if(!key_b_found) break;
|
||||||
|
if(key_a_found) {
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
}
|
||||||
FURI_LOG_D(TAG, "Try to read blocks with key B");
|
FURI_LOG_D(TAG, "Try to read blocks with key B");
|
||||||
key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b));
|
key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b));
|
||||||
if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) break;
|
if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) break;
|
||||||
|
@ -174,6 +174,7 @@ bool mf_classic_authenticate_skip_activate(
|
|||||||
|
|
||||||
bool mf_classic_auth_attempt(
|
bool mf_classic_auth_attempt(
|
||||||
FuriHalNfcTxRxContext* tx_rx,
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
Crypto1* crypto,
|
||||||
MfClassicAuthContext* auth_ctx,
|
MfClassicAuthContext* auth_ctx,
|
||||||
uint64_t key);
|
uint64_t key);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user