|
@@ -296,7 +296,7 @@ uint32_t mifare_nested_worker_predict_delay(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// This part of attack is my attempt to implement it on Flipper.
|
|
// This part of attack is my attempt to implement it on Flipper.
|
|
|
- // Proxmark can do this in 2 fucking steps, but idk how.
|
|
|
|
|
|
|
+ // Check README.md for more info
|
|
|
|
|
|
|
|
// First, we find RPNG rounds per 1000 us
|
|
// First, we find RPNG rounds per 1000 us
|
|
|
for(uint32_t rtr = 0; rtr < 25; rtr++) {
|
|
for(uint32_t rtr = 0; rtr < 25; rtr++) {
|
|
@@ -448,7 +448,7 @@ uint32_t mifare_nested_worker_predict_delay(
|
|
|
return 1;
|
|
return 1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void mifare_nested_worker_write_nonces(
|
|
|
|
|
|
|
+SaveNoncesResult_t* mifare_nested_worker_write_nonces(
|
|
|
FuriHalNfcDevData* data,
|
|
FuriHalNfcDevData* data,
|
|
|
Storage* storage,
|
|
Storage* storage,
|
|
|
NonceList_t* nonces,
|
|
NonceList_t* nonces,
|
|
@@ -459,6 +459,11 @@ void mifare_nested_worker_write_nonces(
|
|
|
uint32_t distance) {
|
|
uint32_t distance) {
|
|
|
FuriString* path = furi_string_alloc();
|
|
FuriString* path = furi_string_alloc();
|
|
|
Stream* file_stream = file_stream_alloc(storage);
|
|
Stream* file_stream = file_stream_alloc(storage);
|
|
|
|
|
+ SaveNoncesResult_t* result = malloc(sizeof(SaveNoncesResult_t));
|
|
|
|
|
+ result->saved = 0;
|
|
|
|
|
+ result->invalid = 0;
|
|
|
|
|
+ result->skipped = 0;
|
|
|
|
|
+
|
|
|
mifare_nested_worker_get_nonces_file_path(data, path);
|
|
mifare_nested_worker_get_nonces_file_path(data, path);
|
|
|
|
|
|
|
|
file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS);
|
|
file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS);
|
|
@@ -472,23 +477,26 @@ void mifare_nested_worker_write_nonces(
|
|
|
for(uint8_t tries = 0; tries < tries_count; tries++) {
|
|
for(uint8_t tries = 0; tries < tries_count; tries++) {
|
|
|
for(uint8_t sector = 0; sector < sector_count; sector++) {
|
|
for(uint8_t sector = 0; sector < sector_count; sector++) {
|
|
|
for(uint8_t key_type = 0; key_type < 2; key_type++) {
|
|
for(uint8_t key_type = 0; key_type < 2; key_type++) {
|
|
|
- if(nonces->nonces[sector][key_type][tries]->collected &&
|
|
|
|
|
- !nonces->nonces[sector][key_type][tries]->skipped) {
|
|
|
|
|
|
|
+ if(nonces->nonces[sector][key_type][tries]->invalid) {
|
|
|
|
|
+ result->invalid++;
|
|
|
|
|
+ } else if(nonces->nonces[sector][key_type][tries]->skipped) {
|
|
|
|
|
+ result->skipped++;
|
|
|
|
|
+ } else if(nonces->nonces[sector][key_type][tries]->collected) {
|
|
|
if(nonces->nonces[sector][key_type][tries]->hardnested) {
|
|
if(nonces->nonces[sector][key_type][tries]->hardnested) {
|
|
|
- FuriString* path = furi_string_alloc();
|
|
|
|
|
|
|
+ FuriString* hardnested_path = furi_string_alloc();
|
|
|
mifare_nested_worker_get_hardnested_file_path(
|
|
mifare_nested_worker_get_hardnested_file_path(
|
|
|
- data, path, sector, key_type);
|
|
|
|
|
|
|
+ data, hardnested_path, sector, key_type);
|
|
|
|
|
|
|
|
FuriString* str = furi_string_alloc_printf(
|
|
FuriString* str = furi_string_alloc_printf(
|
|
|
"HardNested: Key %c cuid 0x%08lx file %s sec %u\n",
|
|
"HardNested: Key %c cuid 0x%08lx file %s sec %u\n",
|
|
|
!key_type ? 'A' : 'B',
|
|
!key_type ? 'A' : 'B',
|
|
|
nonces->cuid,
|
|
nonces->cuid,
|
|
|
- furi_string_get_cstr(path),
|
|
|
|
|
|
|
+ furi_string_get_cstr(hardnested_path),
|
|
|
sector);
|
|
sector);
|
|
|
|
|
|
|
|
stream_write_string(file_stream, str);
|
|
stream_write_string(file_stream, str);
|
|
|
|
|
|
|
|
- furi_string_free(path);
|
|
|
|
|
|
|
+ furi_string_free(hardnested_path);
|
|
|
furi_string_free(str);
|
|
furi_string_free(str);
|
|
|
} else {
|
|
} else {
|
|
|
FuriString* str = furi_string_alloc_printf(
|
|
FuriString* str = furi_string_alloc_printf(
|
|
@@ -515,6 +523,8 @@ void mifare_nested_worker_write_nonces(
|
|
|
stream_write_string(file_stream, str);
|
|
stream_write_string(file_stream, str);
|
|
|
furi_string_free(str);
|
|
furi_string_free(str);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ result->saved++;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -529,10 +539,20 @@ void mifare_nested_worker_write_nonces(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
free_nonces(nonces, sector_count, free_tries_count);
|
|
free_nonces(nonces, sector_count, free_tries_count);
|
|
|
- furi_string_free(path);
|
|
|
|
|
file_stream_close(file_stream);
|
|
file_stream_close(file_stream);
|
|
|
free(file_stream);
|
|
free(file_stream);
|
|
|
|
|
+
|
|
|
|
|
+ if(!result->saved) {
|
|
|
|
|
+ FURI_LOG_E(TAG, "No nonces collected, removing file...");
|
|
|
|
|
+ if(!storage_simply_remove(storage, furi_string_get_cstr(path))) {
|
|
|
|
|
+ FURI_LOG_E(TAG, "Failed to remove .nonces file");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ furi_string_free(path);
|
|
|
furi_record_close(RECORD_STORAGE);
|
|
furi_record_close(RECORD_STORAGE);
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool mifare_nested_worker_check_initial_keys(
|
|
bool mifare_nested_worker_check_initial_keys(
|
|
@@ -759,7 +779,7 @@ void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_neste
|
|
|
mifare_nested_worker_get_block_by_sector(sector),
|
|
mifare_nested_worker_get_block_by_sector(sector),
|
|
|
key_type);
|
|
key_type);
|
|
|
|
|
|
|
|
- info->skipped = true;
|
|
|
|
|
|
|
+ info->invalid = true;
|
|
|
|
|
|
|
|
nonces.nonces[sector][key_type][0] = info;
|
|
nonces.nonces[sector][key_type][0] = info;
|
|
|
|
|
|
|
@@ -818,12 +838,20 @@ void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_neste
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0);
|
|
|
|
|
|
|
+ SaveNoncesResult_t* result =
|
|
|
|
|
+ mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0);
|
|
|
|
|
|
|
|
free(mf_data);
|
|
free(mf_data);
|
|
|
|
|
|
|
|
- mifare_nested_worker->callback(
|
|
|
|
|
- MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context);
|
|
|
|
|
|
|
+ if(result->saved) {
|
|
|
|
|
+ mifare_nested_worker->callback(
|
|
|
|
|
+ MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ mifare_nested_worker->context->save_state = result;
|
|
|
|
|
+
|
|
|
|
|
+ mifare_nested_worker->callback(
|
|
|
|
|
+ MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
nfc_deactivate();
|
|
nfc_deactivate();
|
|
|
}
|
|
}
|
|
@@ -930,7 +958,7 @@ void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_
|
|
|
mifare_nested_worker_get_block_by_sector(sector),
|
|
mifare_nested_worker_get_block_by_sector(sector),
|
|
|
key_type);
|
|
key_type);
|
|
|
|
|
|
|
|
- info->skipped = true;
|
|
|
|
|
|
|
+ info->invalid = true;
|
|
|
|
|
|
|
|
nonces.nonces[sector][key_type][0] = info;
|
|
nonces.nonces[sector][key_type][0] = info;
|
|
|
mifare_nested_worker->context->nonces = &nonces;
|
|
mifare_nested_worker->context->nonces = &nonces;
|
|
@@ -1059,12 +1087,20 @@ void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0);
|
|
|
|
|
|
|
+ SaveNoncesResult_t* result =
|
|
|
|
|
+ mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0);
|
|
|
|
|
|
|
|
free(mf_data);
|
|
free(mf_data);
|
|
|
|
|
|
|
|
- mifare_nested_worker->callback(
|
|
|
|
|
- MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context);
|
|
|
|
|
|
|
+ if(result->saved) {
|
|
|
|
|
+ mifare_nested_worker->callback(
|
|
|
|
|
+ MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ mifare_nested_worker->context->save_state = result;
|
|
|
|
|
+
|
|
|
|
|
+ mifare_nested_worker->callback(
|
|
|
|
|
+ MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
nfc_deactivate();
|
|
nfc_deactivate();
|
|
|
}
|
|
}
|
|
@@ -1368,13 +1404,20 @@ void mifare_nested_worker_collect_nonces(MifareNestedWorker* mifare_nested_worke
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- mifare_nested_worker_write_nonces(
|
|
|
|
|
|
|
+ SaveNoncesResult_t* result = mifare_nested_worker_write_nonces(
|
|
|
&data, storage, &nonces, tries_count, 3, sector_count, delay, distance);
|
|
&data, storage, &nonces, tries_count, 3, sector_count, delay, distance);
|
|
|
|
|
|
|
|
free(mf_data);
|
|
free(mf_data);
|
|
|
|
|
|
|
|
- mifare_nested_worker->callback(
|
|
|
|
|
- MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context);
|
|
|
|
|
|
|
+ if(result->saved) {
|
|
|
|
|
+ mifare_nested_worker->callback(
|
|
|
|
|
+ MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ mifare_nested_worker->context->save_state = result;
|
|
|
|
|
+
|
|
|
|
|
+ mifare_nested_worker->callback(
|
|
|
|
|
+ MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
nfc_deactivate();
|
|
nfc_deactivate();
|
|
|
}
|
|
}
|