Procházet zdrojové kódy

Nonce loading compatible with PR 3822

noproto před 1 rokem
rodič
revize
bf162c4f2c
2 změnil soubory, kde provedl 75 přidání a 125 odebrání
  1. 66 117
      init_plugin.c
  2. 9 8
      mfkey.c

+ 66 - 117
init_plugin.c

@@ -10,10 +10,8 @@
 #include <flipper_application/flipper_application.h>
 
 // TODO: Remove defines that are not needed
-#define KEYS_DICT_SYSTEM_PATH        EXT_PATH("nfc/assets/mf_classic_dict.nfc")
-#define KEYS_DICT_USER_PATH          EXT_PATH("nfc/assets/mf_classic_dict_user.nfc")
 #define MF_CLASSIC_NONCE_PATH        EXT_PATH("nfc/.mfkey32.log")
-#define MF_CLASSIC_NESTED_NONCE_PATH EXT_PATH("nfc/.nested")
+#define MF_CLASSIC_NESTED_NONCE_PATH EXT_PATH("nfc/.nested.log")
 #define TAG                          "MFKey"
 #define MAX_NAME_LEN                 32
 #define MAX_PATH_LEN                 64
@@ -68,59 +66,30 @@ bool napi_mf_classic_mfkey32_nonces_check_presence() {
     return nonces_present;
 }
 
-bool distance_in_nonces_file(const char* file_path, const char* file_name) {
-    char full_path[MAX_PATH_LEN];
-    snprintf(full_path, sizeof(full_path), "%s/%s", file_path, file_name);
-    bool distance_present = false;
-    Storage* storage = furi_record_open(RECORD_STORAGE);
-    Stream* file_stream = buffered_file_stream_alloc(storage);
-    FuriString* line_str;
-    line_str = furi_string_alloc();
-
-    if(buffered_file_stream_open(file_stream, full_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
-        while(true) {
-            if(!stream_read_line(file_stream, line_str)) break;
-            if(furi_string_search_str(line_str, "distance") != FURI_STRING_FAILURE) {
-                distance_present = true;
-                break;
-            }
-        }
-    }
-
-    buffered_file_stream_close(file_stream);
-    stream_free(file_stream);
-    furi_string_free(line_str);
-    furi_record_close(RECORD_STORAGE);
-
-    return distance_present;
-}
-
 bool napi_mf_classic_nested_nonces_check_presence() {
     Storage* storage = furi_record_open(RECORD_STORAGE);
+    Stream* stream = buffered_file_stream_alloc(storage);
+    bool nonces_present = false;
+    FuriString* line = furi_string_alloc();
 
-    if(!(storage_dir_exists(storage, MF_CLASSIC_NESTED_NONCE_PATH))) {
-        furi_record_close(RECORD_STORAGE);
-        return false;
-    }
+    do {
+        if(!buffered_file_stream_open(
+               stream, MF_CLASSIC_NESTED_NONCE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
+            break;
+        }
 
-    bool nonces_present = false;
-    File* dir = storage_file_alloc(storage);
-    char filename_buffer[MAX_NAME_LEN];
-    FileInfo file_info;
-
-    if(storage_dir_open(dir, MF_CLASSIC_NESTED_NONCE_PATH)) {
-        while(storage_dir_read(dir, &file_info, filename_buffer, MAX_NAME_LEN)) {
-            // We only care about Static Nested files
-            if(!(file_info.flags & FSF_DIRECTORY) && strstr(filename_buffer, ".nonces") &&
-               !(distance_in_nonces_file(MF_CLASSIC_NESTED_NONCE_PATH, filename_buffer))) {
+        while(stream_read_line(stream, line)) {
+            if(furi_string_search_str(line, "dist 0") != FURI_STRING_FAILURE) {
                 nonces_present = true;
                 break;
             }
         }
-    }
 
-    storage_dir_close(dir);
-    storage_file_free(dir);
+    } while(false);
+
+    furi_string_free(line);
+    buffered_file_stream_close(stream);
+    stream_free(stream);
     furi_record_close(RECORD_STORAGE);
 
     return nonces_present;
@@ -262,89 +231,69 @@ bool load_nested_nonces(
     KeysDict* system_dict,
     bool system_dict_exists,
     KeysDict* user_dict) {
-    Storage* storage = furi_record_open(RECORD_STORAGE);
-    File* dir = storage_file_alloc(storage);
-    char filename_buffer[MAX_NAME_LEN];
-    FileInfo file_info;
-    FuriString* next_line = furi_string_alloc();
-
-    if(!storage_dir_open(dir, MF_CLASSIC_NESTED_NONCE_PATH)) {
-        storage_dir_close(dir);
-        storage_file_free(dir);
-        furi_record_close(RECORD_STORAGE);
-        furi_string_free(next_line);
+    if(!buffered_file_stream_open(
+           nonce_array->stream, MF_CLASSIC_NESTED_NONCE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
         return false;
     }
 
-    while(storage_dir_read(dir, &file_info, filename_buffer, MAX_NAME_LEN)) {
-        if(!(file_info.flags & FSF_DIRECTORY) && strstr(filename_buffer, ".nonces") &&
-           !(distance_in_nonces_file(MF_CLASSIC_NESTED_NONCE_PATH, filename_buffer))) {
-            char full_path[MAX_PATH_LEN];
-            snprintf(
-                full_path,
-                sizeof(full_path),
-                "%s/%s",
-                MF_CLASSIC_NESTED_NONCE_PATH,
-                filename_buffer);
-
-            // TODO: We should only need READ_WRITE here if we plan on adding a newline to the end of the file if has none
-            if(!buffered_file_stream_open(
-                   nonce_array->stream, full_path, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) {
-                buffered_file_stream_close(nonce_array->stream);
-                continue;
-            }
+    FuriString* next_line = furi_string_alloc();
+    bool array_loaded = false;
 
-            while(stream_read_line(nonce_array->stream, next_line)) {
-                if(furi_string_search_str(next_line, "Nested:") != FURI_STRING_FAILURE) {
-                    MfClassicNonce res = {0};
-                    res.attack = static_nested;
-                    int parsed = sscanf(
-                        furi_string_get_cstr(next_line),
-                        "Nested: %*s %*s cuid 0x%" PRIx32 " nt0 0x%" PRIx32 " ks0 0x%" PRIx32
-                        " par0 %4[01] nt1 0x%" PRIx32 " ks1 0x%" PRIx32 " par1 %4[01]",
-                        &res.uid,
-                        &res.nt0,
-                        &res.ks1_1_enc,
-                        res.par_1_str,
-                        &res.nt1,
-                        &res.ks1_2_enc,
-                        res.par_2_str);
-
-                    if(parsed != 7) continue;
-                    res.par_1 = binaryStringToInt(res.par_1_str);
-                    res.par_2 = binaryStringToInt(res.par_2_str);
-                    res.uid_xor_nt0 = res.uid ^ res.nt0;
-                    res.uid_xor_nt1 = res.uid ^ res.nt1;
-
-                    (program_state->total)++;
-                    if((system_dict_exists &&
-                        key_already_found_for_nonce_in_dict(system_dict, &res)) ||
-                       (key_already_found_for_nonce_in_dict(user_dict, &res))) {
-                        (program_state->cracked)++;
-                        (program_state->num_completed)++;
-                        continue;
-                    }
+    while(stream_read_line(nonce_array->stream, next_line)) {
+        const char* line = furi_string_get_cstr(next_line);
 
-                    nonce_array->remaining_nonce_array = realloc(
-                        nonce_array->remaining_nonce_array,
-                        sizeof(MfClassicNonce) * (nonce_array->remaining_nonces + 1));
-                    nonce_array->remaining_nonce_array[nonce_array->remaining_nonces] = res;
-                    nonce_array->remaining_nonces++;
-                    nonce_array->total_nonces++;
-                }
+        // Only process lines ending with "dist 0"
+        if(!strstr(line, "dist 0")) {
+            continue;
+        }
+
+        MfClassicNonce res = {0};
+        res.attack = static_nested;
+
+        int parsed = sscanf(
+            line,
+            "Sec %*d key %*c cuid %" PRIx32 " nt0 %" PRIx32 " ks0 %" PRIx32
+            " par0 %4[01] nt1 %" PRIx32 " ks1 %" PRIx32 " par1 %4[01]",
+            &res.uid,
+            &res.nt0,
+            &res.ks1_1_enc,
+            res.par_1_str,
+            &res.nt1,
+            &res.ks1_2_enc,
+            res.par_2_str);
+
+        if(parsed >= 4) { // At least one nonce is present
+            res.par_1 = binaryStringToInt(res.par_1_str);
+            res.uid_xor_nt0 = res.uid ^ res.nt0;
+
+            if(parsed == 7) { // Both nonces are present
+                res.par_2 = binaryStringToInt(res.par_2_str);
+                res.uid_xor_nt1 = res.uid ^ res.nt1;
             }
 
-            buffered_file_stream_close(nonce_array->stream);
+            (program_state->total)++;
+            if((system_dict_exists && key_already_found_for_nonce_in_dict(system_dict, &res)) ||
+               (key_already_found_for_nonce_in_dict(user_dict, &res))) {
+                (program_state->cracked)++;
+                (program_state->num_completed)++;
+                continue;
+            }
+
+            nonce_array->remaining_nonce_array = realloc(
+                nonce_array->remaining_nonce_array,
+                sizeof(MfClassicNonce) * (nonce_array->remaining_nonces + 1));
+            nonce_array->remaining_nonce_array[nonce_array->remaining_nonces] = res;
+            nonce_array->remaining_nonces++;
+            nonce_array->total_nonces++;
+            array_loaded = true;
         }
     }
 
-    storage_dir_close(dir);
-    storage_file_free(dir);
-    furi_record_close(RECORD_STORAGE);
     furi_string_free(next_line);
+    buffered_file_stream_close(nonce_array->stream);
 
     //FURI_LOG_I(TAG, "Loaded %lu Static Nested nonces", nonce_array->total_nonces);
-    return true;
+    return array_loaded;
 }
 
 MfClassicNonceArray* napi_mf_classic_nonce_array_alloc(

+ 9 - 8
mfkey.c

@@ -1,7 +1,6 @@
 #pragma GCC optimize("O3")
 #pragma GCC optimize("-funroll-all-loops")
 
-// TODO: Add keys to top of the user dictionary, not the bottom
 // TODO: More efficient dictionary bruteforce by scanning through hardcoded very common keys and previously found dictionary keys first?
 //       (a cache for key_already_found_for_nonce_in_dict)
 // TODO: Selectively unroll loops to reduce binary size
@@ -31,13 +30,11 @@
 #include <storage/storage.h>
 
 // TODO: Remove defines that are not needed
-#define KEYS_DICT_SYSTEM_PATH        EXT_PATH("nfc/assets/mf_classic_dict.nfc")
-#define KEYS_DICT_USER_PATH          EXT_PATH("nfc/assets/mf_classic_dict_user.nfc")
-#define MF_CLASSIC_NONCE_PATH        EXT_PATH("nfc/.mfkey32.log")
-#define MF_CLASSIC_NESTED_NONCE_PATH EXT_PATH("nfc/.nested")
-#define TAG                          "MFKey"
-#define MAX_NAME_LEN                 32
-#define MAX_PATH_LEN                 64
+#define KEYS_DICT_SYSTEM_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc")
+#define KEYS_DICT_USER_PATH   EXT_PATH("nfc/assets/mf_classic_dict_user.nfc")
+#define TAG                   "MFKey"
+#define MAX_NAME_LEN          32
+#define MAX_PATH_LEN          64
 
 #define LF_POLY_ODD  (0x29CE5C)
 #define LF_POLY_EVEN (0x870804)
@@ -74,6 +71,8 @@ int check_state(struct Crypto1State* t, MfClassicNonce* n) {
         }
         return 0;
     } else if(n->attack == static_nested) {
+        // TODO: Needs to be revised to save all candidate keys for static encrypted when all properties produce a match
+        // A static encrypted MfClassicNonce has no nonce pair
         struct Crypto1State temp = {t->odd, t->even};
         rollback_word_noret(t, n->uid_xor_nt1, 0);
         if(n->ks1_1_enc == crypt_word_ret(t, n->uid_xor_nt0, 0)) {
@@ -727,12 +726,14 @@ static void render_callback(Canvas* const canvas, void* ctx) {
         canvas_set_font(canvas, FontSecondary);
         snprintf(draw_str, sizeof(draw_str), "Complete");
         canvas_draw_str_aligned(canvas, 40, 31, AlignLeft, AlignTop, draw_str);
+        // Mfkey32
         snprintf(
             draw_str,
             sizeof(draw_str),
             "Keys added to user dict: %d",
             program_state->unique_cracked);
         canvas_draw_str_aligned(canvas, 10, 41, AlignLeft, AlignTop, draw_str);
+        // TODO: Keys added to UID dict (Static Encrypted)
     } else if(program_state->mfkey_state == Ready) {
         canvas_set_font(canvas, FontSecondary);
         canvas_draw_str_aligned(canvas, 50, 30, AlignLeft, AlignTop, "Ready");