Преглед изворни кода

Update MFKey to v2.7 (#231)

Co-authored-by: あく <alleteam@gmail.com>
Nathan N пре 1 година
родитељ
комит
ddec205940
8 измењених фајлова са 145 додато и 128 уклоњено
  1. 2 0
      .catalog/changelog.md
  2. 1 1
      application.fam
  3. 1 1
      crypto1.c
  4. 56 5
      crypto1.h
  5. 14 14
      init_plugin.c
  6. 64 93
      mfkey.c
  7. 5 12
      mfkey.h
  8. 2 2
      plugin_interface.h

+ 2 - 0
.catalog/changelog.md

@@ -1,3 +1,5 @@
+## 2.7
+ - Mfkey32 recovery is 30% faster, fix UI and slowdown bugs
 ## 2.6
  - Version bump for catalog build system
 ## 2.5

+ 1 - 1
application.fam

@@ -15,7 +15,7 @@ App(
     fap_icon_assets="images",
     fap_weburl="https://github.com/noproto/FlipperMfkey",
     fap_description="MIFARE Classic key recovery tool",
-    fap_version="2.6",
+    fap_version="2.7",
 )
 
 App(

+ 1 - 1
crypto1.c

@@ -19,4 +19,4 @@ void crypto1_get_lfsr(struct Crypto1State* state, MfClassicKey* lfsr) {
     for(i = 0; i < 6; ++i) {
         lfsr->data[i] = (lfsr_value >> ((5 - i) * 8)) & 0xFF;
     }
-}
+}

+ 56 - 5
crypto1.h

@@ -5,10 +5,10 @@
 #include "mfkey.h"
 #include <nfc/protocols/mf_classic/mf_classic.h>
 
-#define LF_POLY_ODD (0x29CE5C)
+#define LF_POLY_ODD  (0x29CE5C)
 #define LF_POLY_EVEN (0x870804)
-#define BIT(x, n) ((x) >> (n) & 1)
-#define BEBIT(x, n) BIT(x, (n) ^ 24)
+#define BIT(x, n)    ((x) >> (n) & 1)
+#define BEBIT(x, n)  BIT(x, (n) ^ 24)
 #define SWAPENDIAN(x) \
     ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16)
 
@@ -21,6 +21,8 @@ static inline uint32_t crypt_word(struct Crypto1State* s);
 static inline void crypt_word_noret(struct Crypto1State* s, uint32_t in, int x);
 static inline uint32_t crypt_word_ret(struct Crypto1State* s, uint32_t in, int x);
 static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x);
+static inline uint8_t napi_lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb);
+static inline uint32_t napi_lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb);
 
 static const uint8_t lookup1[256] = {
     0, 0,  16, 16, 0,  16, 0,  0,  0, 16, 0,  0,  16, 16, 16, 16, 0, 0,  16, 16, 0,  16, 0,  0,
@@ -147,10 +149,59 @@ static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int
     return;
 }
 
+// TODO:
+/*
+uint32_t rollback_word(struct Crypto1State *s, uint32_t in, int x) {
+    uint32_t res_ret = 0;
+    uint8_t ret;
+    uint32_t feedin, t, next_in;
+    for (int i = 31; i >= 0; i--) {
+        next_in = BEBIT(in, i);
+        s->odd &= 0xffffff;
+        t = s->odd, s->odd = s->even, s->even = t;
+        ret = filter(s->odd);
+        feedin = ret & (!!x);
+        feedin ^= s->even & 1;
+        feedin ^= LF_POLY_EVEN & (s->even >>= 1);
+        feedin ^= LF_POLY_ODD & s->odd;
+        feedin ^= !!next_in;
+        s->even |= (evenparity32(feedin)) << 23;
+        res_ret |= (ret << (24 ^ i));
+    }
+    return res_ret;
+}
+*/
+
+uint8_t napi_lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb) {
+    int out;
+    uint8_t ret;
+    uint32_t t;
+    s->odd &= 0xffffff;
+    t = s->odd, s->odd = s->even, s->even = t;
+
+    out = s->even & 1;
+    out ^= LF_POLY_EVEN & (s->even >>= 1);
+    out ^= LF_POLY_ODD & s->odd;
+    out ^= !!in;
+    out ^= (ret = filter(s->odd)) & !!fb;
+
+    s->even |= evenparity32(out) << 23;
+    return ret;
+}
+
+uint32_t napi_lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb) {
+    int i;
+    uint32_t ret = 0;
+    for(i = 31; i >= 0; --i)
+        ret |= napi_lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24);
+    return ret;
+}
+
 static inline uint32_t prng_successor(uint32_t x, uint32_t n) {
     SWAPENDIAN(x);
-    while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
+    while(n--)
+        x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
     return SWAPENDIAN(x);
 }
 
-#endif // CRYPTO1_H
+#endif // CRYPTO1_H

+ 14 - 14
init_plugin.c

@@ -10,22 +10,22 @@
 #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 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 TAG                          "MFKey"
+#define MAX_NAME_LEN                 32
+#define MAX_PATH_LEN                 64
 
-#define LF_POLY_ODD (0x29CE5C)
+#define LF_POLY_ODD  (0x29CE5C)
 #define LF_POLY_EVEN (0x870804)
-#define CONST_M1_1 (LF_POLY_EVEN << 1 | 1)
-#define CONST_M2_1 (LF_POLY_ODD << 1)
-#define CONST_M1_2 (LF_POLY_ODD)
-#define CONST_M2_2 (LF_POLY_EVEN << 1 | 1)
-#define BIT(x, n) ((x) >> (n) & 1)
-#define BEBIT(x, n) BIT(x, (n) ^ 24)
+#define CONST_M1_1   (LF_POLY_EVEN << 1 | 1)
+#define CONST_M2_1   (LF_POLY_ODD << 1)
+#define CONST_M1_2   (LF_POLY_ODD)
+#define CONST_M2_2   (LF_POLY_EVEN << 1 | 1)
+#define BIT(x, n)    ((x) >> (n) & 1)
+#define BEBIT(x, n)  BIT(x, (n) ^ 24)
 #define SWAPENDIAN(x) \
     ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16)
 
@@ -409,4 +409,4 @@ static const FlipperAppPluginDescriptor init_plugin_descriptor = {
 /* Plugin entry point - must return a pointer to const descriptor  */
 const FlipperAppPluginDescriptor* init_plugin_ep() {
     return &init_plugin_descriptor;
-}
+}

+ 64 - 93
mfkey.c

@@ -32,35 +32,38 @@
 #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 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 TAG                          "MFKey"
+#define MAX_NAME_LEN                 32
+#define MAX_PATH_LEN                 64
 
-#define LF_POLY_ODD (0x29CE5C)
+#define LF_POLY_ODD  (0x29CE5C)
 #define LF_POLY_EVEN (0x870804)
-#define CONST_M1_1 (LF_POLY_EVEN << 1 | 1)
-#define CONST_M2_1 (LF_POLY_ODD << 1)
-#define CONST_M1_2 (LF_POLY_ODD)
-#define CONST_M2_2 (LF_POLY_EVEN << 1 | 1)
-#define BIT(x, n) ((x) >> (n) & 1)
-#define BEBIT(x, n) BIT(x, (n) ^ 24)
+#define CONST_M1_1   (LF_POLY_EVEN << 1 | 1)
+#define CONST_M2_1   (LF_POLY_ODD << 1)
+#define CONST_M1_2   (LF_POLY_ODD)
+#define CONST_M2_2   (LF_POLY_EVEN << 1 | 1)
+#define BIT(x, n)    ((x) >> (n) & 1)
+#define BEBIT(x, n)  BIT(x, (n) ^ 24)
 #define SWAPENDIAN(x) \
     ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16)
 //#define SIZEOF(arr) sizeof(arr) / sizeof(*arr)
 
-static int eta_round_time = 56;
-static int eta_total_time = 900;
+static int eta_round_time = 44;
+static int eta_total_time = 705;
 // MSB_LIMIT: Chunk size (out of 256)
 static int MSB_LIMIT = 16;
 
 int check_state(struct Crypto1State* t, MfClassicNonce* n) {
     if(!(t->odd | t->even)) return 0;
     if(n->attack == mfkey32) {
-        rollback_word_noret(t, 0, 0);
+        uint32_t rb = (napi_lfsr_rollback_word(t, 0, 0) ^ n->p64);
+        if(rb != n->ar0_enc) {
+            return 0;
+        }
         rollback_word_noret(t, n->nr0_enc, 1);
         rollback_word_noret(t, n->uid_xor_nt0, 0);
         struct Crypto1State temp = {t->odd, t->even};
@@ -391,9 +394,6 @@ int calculate_msb_tables(
 
 void** allocate_blocks(const size_t* block_sizes, int num_blocks) {
     void** block_pointers = malloc(num_blocks * sizeof(void*));
-    if(block_pointers == NULL) {
-        return NULL;
-    }
 
     for(int i = 0; i < num_blocks; i++) {
         if(memmgr_heap_get_max_free_block() < block_sizes[i]) {
@@ -406,19 +406,15 @@ void** allocate_blocks(const size_t* block_sizes, int num_blocks) {
         }
 
         block_pointers[i] = malloc(block_sizes[i]);
-        if(block_pointers[i] == NULL) {
-            // Allocation failed, free previously allocated blocks
-            for(int j = 0; j < i; j++) {
-                free(block_pointers[j]);
-            }
-            free(block_pointers);
-            return NULL;
-        }
     }
 
     return block_pointers;
 }
 
+bool is_full_speed() {
+    return MSB_LIMIT == 16;
+}
+
 bool recover(MfClassicNonce* n, int ks2, unsigned int in, ProgramState* program_state) {
     bool found = false;
     const size_t block_sizes[] = {49216, 49216, 5120, 5120, 4096};
@@ -427,9 +423,11 @@ bool recover(MfClassicNonce* n, int ks2, unsigned int in, ProgramState* program_
     void** block_pointers = allocate_blocks(block_sizes, num_blocks);
     if(block_pointers == NULL) {
         // System has less than the guaranteed amount of RAM (140 KB) - adjust some parameters to run anyway at half speed
-        eta_round_time *= 2;
-        eta_total_time *= 2;
-        MSB_LIMIT /= 2;
+        if(is_full_speed()) {
+            //eta_round_time *= 2;
+            eta_total_time *= 2;
+            MSB_LIMIT /= 2;
+        }
         block_pointers = allocate_blocks(reduced_block_sizes, num_blocks);
         if(block_pointers == NULL) {
             // System has less than 70 KB of RAM - should never happen so we don't reduce speed further
@@ -675,9 +673,10 @@ static void render_callback(Canvas* const canvas, void* ctx) {
     ProgramState* program_state = ctx;
     furi_mutex_acquire(program_state->mutex, FuriWaitForever);
     char draw_str[44] = {};
-    canvas_clear(canvas);
+
     canvas_draw_frame(canvas, 0, 0, 128, 64);
     canvas_draw_frame(canvas, 0, 15, 128, 64);
+
     canvas_set_font(canvas, FontPrimary);
     canvas_draw_str_aligned(canvas, 5, 4, AlignLeft, AlignTop, "MFKey");
     snprintf(draw_str, sizeof(draw_str), "RAM: %zub", memmgr_get_free_heap());
@@ -725,7 +724,7 @@ static void render_callback(Canvas* const canvas, void* ctx) {
         canvas_draw_str_aligned(canvas, 26, 28, AlignLeft, AlignTop, draw_str);
     } else if(program_state->mfkey_state == Complete) {
         // TODO: Scrollable list view to see cracked keys if user presses down
-        elements_progress_bar_with_text(canvas, 5, 18, 118, 1, draw_str);
+        elements_progress_bar(canvas, 5, 18, 118, 1);
         canvas_set_font(canvas, FontSecondary);
         snprintf(draw_str, sizeof(draw_str), "Complete");
         canvas_draw_str_aligned(canvas, 40, 31, AlignLeft, AlignTop, draw_str);
@@ -766,9 +765,7 @@ static void render_callback(Canvas* const canvas, void* ctx) {
 
 static void input_callback(InputEvent* input_event, void* event_queue) {
     furi_assert(event_queue);
-
-    PluginEvent event = {.type = EventTypeKey, .input = *input_event};
-    furi_message_queue_put((FuriMessageQueue*)event_queue, &event, FuriWaitForever);
+    furi_message_queue_put((FuriMessageQueue*)event_queue, input_event, FuriWaitForever);
 }
 
 static void mfkey_state_init(ProgramState* program_state) {
@@ -792,25 +789,14 @@ static int32_t mfkey_worker_thread(void* ctx) {
     return 0;
 }
 
-void start_mfkey_thread(ProgramState* program_state) {
-    if(!program_state->is_thread_running) {
-        furi_thread_start(program_state->mfkeythread);
-    }
-}
-
 int32_t mfkey_main() {
-    FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
+    FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
 
     ProgramState* program_state = malloc(sizeof(ProgramState));
 
     mfkey_state_init(program_state);
 
     program_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
-    if(!program_state->mutex) {
-        //FURI_LOG_E(TAG, "cannot create mutex\r\n");
-        free(program_state);
-        return 255;
-    }
 
     // Set system callbacks
     ViewPort* view_port = view_port_alloc();
@@ -822,72 +808,57 @@ int32_t mfkey_main() {
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
 
     program_state->mfkeythread = furi_thread_alloc();
-    furi_thread_set_name(program_state->mfkeythread, "MFKey Worker");
+    furi_thread_set_name(program_state->mfkeythread, "MFKeyWorker");
     furi_thread_set_stack_size(program_state->mfkeythread, 2048);
     furi_thread_set_context(program_state->mfkeythread, program_state);
     furi_thread_set_callback(program_state->mfkeythread, mfkey_worker_thread);
 
-    PluginEvent event;
+    InputEvent input_event;
     for(bool main_loop = true; main_loop;) {
-        FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
+        FuriStatus event_status = furi_message_queue_get(event_queue, &input_event, 100);
 
         furi_mutex_acquire(program_state->mutex, FuriWaitForever);
 
         if(event_status == FuriStatusOk) {
-            // press events
-            if(event.type == EventTypeKey) {
-                if(event.input.type == InputTypePress) {
-                    switch(event.input.key) {
-                    case InputKeyUp:
-                        break;
-                    case InputKeyDown:
-                        break;
-                    case InputKeyRight:
-                        if(!program_state->is_thread_running &&
-                           program_state->mfkey_state == Ready) {
-                            program_state->mfkey_state = Help;
-                            view_port_update(view_port);
-                        }
-                        break;
-                    case InputKeyLeft:
-                        break;
-                    case InputKeyOk:
-                        if(!program_state->is_thread_running &&
-                           program_state->mfkey_state == Ready) {
-                            start_mfkey_thread(program_state);
-                            view_port_update(view_port);
-                        }
-                        break;
-                    case InputKeyBack:
-                        if(!program_state->is_thread_running &&
-                           program_state->mfkey_state == Help) {
-                            program_state->mfkey_state = Ready;
-                            view_port_update(view_port);
-                        } else {
-                            program_state->close_thread_please = true;
-                            if(program_state->is_thread_running && program_state->mfkeythread) {
-                                // Wait until thread is finished
-                                furi_thread_join(program_state->mfkeythread);
-                            }
-                            program_state->close_thread_please = false;
-                            main_loop = false;
+            if(input_event.type == InputTypePress) {
+                switch(input_event.key) {
+                case InputKeyRight:
+                    if(!program_state->is_thread_running && program_state->mfkey_state == Ready) {
+                        program_state->mfkey_state = Help;
+                    }
+                    break;
+                case InputKeyOk:
+                    if(!program_state->is_thread_running && program_state->mfkey_state == Ready) {
+                        furi_thread_start(program_state->mfkeythread);
+                    }
+                    break;
+                case InputKeyBack:
+                    if(!program_state->is_thread_running && program_state->mfkey_state == Help) {
+                        program_state->mfkey_state = Ready;
+                    } else {
+                        program_state->close_thread_please = true;
+                        if(program_state->is_thread_running) {
+                            // Wait until thread is finished
+                            furi_thread_join(program_state->mfkeythread);
                         }
-                        break;
-                    default:
-                        break;
+                        program_state->close_thread_please = false;
+                        main_loop = false;
                     }
+                    break;
+                default:
+                    break;
                 }
             }
         }
 
-        view_port_update(view_port);
         furi_mutex_release(program_state->mutex);
+        view_port_update(view_port);
     }
 
     furi_thread_free(program_state->mfkeythread);
     view_port_enabled_set(view_port, false);
     gui_remove_view_port(gui, view_port);
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
     view_port_free(view_port);
     furi_message_queue_free(event_queue);
     furi_mutex_free(program_state->mutex);
@@ -895,4 +866,4 @@ int32_t mfkey_main() {
 
     return 0;
 }
-#pragma GCC pop_options
+#pragma GCC pop_options

+ 5 - 12
mfkey.h

@@ -17,16 +17,6 @@ struct Msb {
     uint32_t states[768];
 };
 
-typedef enum {
-    EventTypeTick,
-    EventTypeKey,
-} EventType;
-
-typedef struct {
-    EventType type;
-    InputEvent input;
-} PluginEvent;
-
 typedef enum {
     MissingNonces,
     ZeroNonces,
@@ -64,7 +54,10 @@ typedef struct {
     FuriThread* mfkeythread;
 } ProgramState;
 
-typedef enum { mfkey32, static_nested } AttackType;
+typedef enum {
+    mfkey32,
+    static_nested
+} AttackType;
 
 typedef struct {
     AttackType attack;
@@ -104,4 +97,4 @@ struct KeysDict {
     size_t total_keys;
 };
 
-#endif // MFKEY_H
+#endif // MFKEY_H

+ 2 - 2
plugin_interface.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#define PLUGIN_APP_ID "mfkey"
+#define PLUGIN_APP_ID      "mfkey"
 #define PLUGIN_API_VERSION 1
 
 typedef struct {
@@ -10,4 +10,4 @@ typedef struct {
     MfClassicNonceArray* (
         *napi_mf_classic_nonce_array_alloc)(KeysDict*, bool, KeysDict*, ProgramState*);
     void (*napi_mf_classic_nonce_array_free)(MfClassicNonceArray*);
-} MfkeyPlugin;
+} MfkeyPlugin;