Skip to content

Commit

Permalink
1.5.0 - New update, new scene
Browse files Browse the repository at this point in the history
Changes:
 - Added new scene with information about why nonces aren't collected (skipped/invalid)
 - Removed some old code, breaking compability with old firmware
 - App renamed from "Flipper (Mifare) Nested" to "Flipper Nested"

Once again, I hope I didn't break everything.
  • Loading branch information
AloneLiberty committed May 28, 2023
1 parent 93581dd commit 86fc49f
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 63 deletions.
4 changes: 2 additions & 2 deletions application.fam
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
App(
appid="mifare_nested",
name="Flipper (Mifare) Nested",
name="Flipper Nested",
apptype=FlipperAppType.EXTERNAL,
entry_point="mifare_nested_app",
requires=[
Expand All @@ -21,5 +21,5 @@ App(
fap_author="AloneLiberty",
fap_description="Recover Mifare Classic keys",
fap_weburl="https://github.com/AloneLiberty/FlipperNested",
fap_version=(1, 4)
fap_version="1.5.0"
)
22 changes: 0 additions & 22 deletions lib/nested/nested.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,6 @@
#include "../../lib/crypto1/crypto1.h"
#define TAG "Nested"

void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest) {
furi_assert(dest);
furi_assert(len <= 8);

while(len--) {
dest[len] = (uint8_t)src;
src >>= 8;
}
}

uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len) {
furi_assert(src);
furi_assert(len <= 8);

uint64_t res = 0;
while(len--) {
res = (res << 8) | (*src);
src++;
}
return res;
}

uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) {
uint16_t crc = 0x6363; // NFCA_CRC_INIT
uint8_t byte = 0;
Expand Down
1 change: 1 addition & 0 deletions mifare_nested.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ void mifare_nested_blink_stop(MifareNested* mifare_nested) {

int32_t mifare_nested_app(void* p) {
UNUSED(p);

MifareNested* mifare_nested = mifare_nested_alloc();

scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneStart);
Expand Down
3 changes: 2 additions & 1 deletion mifare_nested_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include <gui/modules/variable_item_list.h>
#include "mifare_nested_icons.h"

#define NESTED_VERSION_APP "1.4.6"
#define NESTED_VERSION_APP "1.5.0"
#define NESTED_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNested"
#define NESTED_RECOVER_KEYS_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNestedRecovery"
#define NESTED_NONCE_FORMAT_VERSION "3"
Expand Down Expand Up @@ -99,6 +99,7 @@ struct MifareNested {

NestedState* nested_state;
CheckKeysState* keys_state;
SaveNoncesResult_t* save_state;

MifareNestedWorkerState collecting_type;

Expand Down
83 changes: 63 additions & 20 deletions mifare_nested_worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ uint32_t mifare_nested_worker_predict_delay(
}

// 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
for(uint32_t rtr = 0; rtr < 25; rtr++) {
Expand Down Expand Up @@ -448,7 +448,7 @@ uint32_t mifare_nested_worker_predict_delay(
return 1;
}

void mifare_nested_worker_write_nonces(
SaveNoncesResult_t* mifare_nested_worker_write_nonces(
FuriHalNfcDevData* data,
Storage* storage,
NonceList_t* nonces,
Expand All @@ -459,6 +459,11 @@ void mifare_nested_worker_write_nonces(
uint32_t distance) {
FuriString* path = furi_string_alloc();
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);

file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS);
Expand All @@ -472,23 +477,26 @@ void mifare_nested_worker_write_nonces(
for(uint8_t tries = 0; tries < tries_count; tries++) {
for(uint8_t sector = 0; sector < sector_count; sector++) {
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) {
FuriString* path = furi_string_alloc();
FuriString* hardnested_path = furi_string_alloc();
mifare_nested_worker_get_hardnested_file_path(
data, path, sector, key_type);
data, hardnested_path, sector, key_type);

FuriString* str = furi_string_alloc_printf(
"HardNested: Key %c cuid 0x%08lx file %s sec %u\n",
!key_type ? 'A' : 'B',
nonces->cuid,
furi_string_get_cstr(path),
furi_string_get_cstr(hardnested_path),
sector);

stream_write_string(file_stream, str);

furi_string_free(path);
furi_string_free(hardnested_path);
furi_string_free(str);
} else {
FuriString* str = furi_string_alloc_printf(
Expand All @@ -515,6 +523,8 @@ void mifare_nested_worker_write_nonces(
stream_write_string(file_stream, str);
furi_string_free(str);
}

result->saved++;
}
}
}
Expand All @@ -529,10 +539,20 @@ void mifare_nested_worker_write_nonces(
}

free_nonces(nonces, sector_count, free_tries_count);
furi_string_free(path);
file_stream_close(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);

return result;
}

bool mifare_nested_worker_check_initial_keys(
Expand Down Expand Up @@ -759,7 +779,7 @@ void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_neste
mifare_nested_worker_get_block_by_sector(sector),
key_type);

info->skipped = true;
info->invalid = true;

nonces.nonces[sector][key_type][0] = info;

Expand Down Expand Up @@ -818,12 +838,20 @@ void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_neste
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);

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();
}
Expand Down Expand Up @@ -930,7 +958,7 @@ void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_
mifare_nested_worker_get_block_by_sector(sector),
key_type);

info->skipped = true;
info->invalid = true;

nonces.nonces[sector][key_type][0] = info;
mifare_nested_worker->context->nonces = &nonces;
Expand Down Expand Up @@ -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);

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();
}
Expand Down Expand Up @@ -1368,13 +1404,20 @@ void mifare_nested_worker_collect_nonces(MifareNestedWorker* mifare_nested_worke
break;
}

mifare_nested_worker_write_nonces(
SaveNoncesResult_t* result = mifare_nested_worker_write_nonces(
&data, storage, &nonces, tries_count, 3, sector_count, delay, distance);

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();
}
Expand Down
10 changes: 9 additions & 1 deletion mifare_nested_worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ typedef enum {
MifareNestedWorkerEventReserved = 1000,

MifareNestedWorkerEventNoTagDetected,
MifareNestedWorkerEventNoNoncesCollected,
MifareNestedWorkerEventNoncesCollected,
MifareNestedWorkerEventCollecting,

Expand Down Expand Up @@ -64,8 +65,9 @@ typedef struct {
uint32_t target_nt[2];
uint32_t target_ks[2];
uint8_t parity[2][4];
bool collected;
bool skipped;
bool invalid;
bool collected;
bool hardnested;
} Nonces;

Expand All @@ -87,3 +89,9 @@ typedef struct {
uint32_t sector_keys;
bool tag_lost;
} KeyInfo_t;

typedef struct {
uint32_t saved;
uint32_t invalid;
uint32_t skipped;
} SaveNoncesResult_t;
2 changes: 1 addition & 1 deletion scenes/mifare_nested_scene_about.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void mifare_nested_scene_about_on_enter(void* context) {
14,
AlignCenter,
AlignBottom,
"\e#\e! Flipper (Mifare) Nested \e!\n",
"\e#\e! Flipper Nested \e!\n",
false);
widget_add_text_scroll_element(
mifare_nested->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
Expand Down
9 changes: 1 addition & 8 deletions scenes/mifare_nested_scene_check.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,7 @@ bool mifare_nested_scene_check_on_event(void* context, SceneManagerEvent event)
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
if(event.event == MifareNestedWorkerEventNoncesCollected) {
scene_manager_next_scene(
mifare_nested->scene_manager, MifareNestedSceneNoncesCollected);
consumed = true;
} else if(event.event == MifareNestedWorkerEventAttackFailed) {
scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed);
consumed = true;
} else if(event.event == MifareNestedWorkerEventCollecting) {
if(event.event == MifareNestedWorkerEventCollecting) {
if(mifare_nested->run == NestedRunAttack) {
if(mifare_nested->settings->only_hardnested) {
FURI_LOG_I("MifareNested", "Using Hard Nested because user settings");
Expand Down
7 changes: 0 additions & 7 deletions scenes/mifare_nested_scene_check_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,6 @@ bool mifare_nested_scene_check_keys_on_event(void* context, SceneManagerEvent ev
if(event.event == GuiButtonTypeCenter) {
scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0);
consumed = true;
} else if(event.event == MifareNestedWorkerEventNoncesCollected) {
scene_manager_next_scene(
mifare_nested->scene_manager, MifareNestedSceneNoncesCollected);
consumed = true;
} else if(event.event == MifareNestedWorkerEventNeedKey) {
scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneNoKeys);
consumed = true;
} else if(event.event == MifareNestedWorkerEventKeysFound) {
scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneAddedKeys);
consumed = true;
Expand Down
4 changes: 4 additions & 0 deletions scenes/mifare_nested_scene_collecting.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ bool mifare_nested_scene_collecting_on_event(void* context, SceneManagerEvent ev
scene_manager_next_scene(
mifare_nested->scene_manager, MifareNestedSceneNoncesCollected);
consumed = true;
} else if(event.event == MifareNestedWorkerEventNoNoncesCollected) {
scene_manager_next_scene(
mifare_nested->scene_manager, MifareNestedSceneNoNoncesCollected);
consumed = true;
} else if(event.event == MifareNestedWorkerEventAttackFailed) {
scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed);
consumed = true;
Expand Down
3 changes: 2 additions & 1 deletion scenes/mifare_nested_scene_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ ADD_SCENE(mifare_nested, about, About)
ADD_SCENE(mifare_nested, static_encrypted_nonce, StaticEncryptedNonce)
ADD_SCENE(mifare_nested, need_key_recovery, NeedKeyRecovery)
ADD_SCENE(mifare_nested, need_collection, NeedCollection)
ADD_SCENE(mifare_nested, settings, Settings)
ADD_SCENE(mifare_nested, settings, Settings)
ADD_SCENE(mifare_nested, no_nonces_collected, NoNoncesCollected)
Loading

0 comments on commit 86fc49f

Please sign in to comment.