Explorar o código

update passgen

MX %!s(int64=2) %!d(string=hai) anos
pai
achega
62734b8b8f

+ 1 - 1
ReadMe.md

@@ -108,7 +108,7 @@ The Flipper and its community wouldn't be as rich as it is without your contribu
 - [Counter (By Krulknul)](https://github.com/Krulknul/dolphin-counter)
 - [USB HID Autofire (By pbek)](https://github.com/pbek/usb_hid_autofire)
 - [IR Remote (By Hong5489)](https://github.com/Hong5489/ir_remote) - improvements [(By friebel)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/535) - Hold Option, RAW support [(By d4ve10)](https://github.com/d4ve10/ir_remote/tree/infrared_hold_option)
-- [Password Generator (By anakod)](https://github.com/anakod/flipper_passgen)
+- [Password Generator (By anakod)](https://github.com/anakod/flipper_passgen) - Proper random by [henrygab](https://github.com/anakod/flipper_passgen/pull/6)
 - [Count Down Timer (By 0w0mewo)](https://github.com/0w0mewo/fpz_cntdown_timer)
 - [QR Code (By bmatcuk)](https://github.com/bmatcuk/flipperzero-qrcode)
 - [Flipp Pomodoro Timer (By Th3Un1q3)](https://github.com/Th3Un1q3/flipp_pomodoro)

BIN=BIN
apps/Tools/passgen.fap


+ 3 - 0
apps_source_code/flipper_passgen/application.fam

@@ -9,4 +9,7 @@ App(
     fap_category="Tools",
     fap_icon="icons/passgen_icon.png",
     fap_icon_assets="icons",
+    fap_author="@anakod & @henrygab",
+    fap_version="1.1",
+    fap_description="Simple password generator",
 )

+ 75 - 16
apps_source_code/flipper_passgen/passgen.c

@@ -1,18 +1,19 @@
 #include <furi.h>
+#include <furi_hal_random.h>
 #include <gui/gui.h>
 #include <gui/elements.h>
 #include <input/input.h>
 #include <notification/notification_messages.h>
 #include <stdlib.h>
 #include <passgen_icons.h>
-#include <core/string.h>
 
 #define PASSGEN_MAX_LENGTH 16
+#define PASSGEN_CHARACTERS_LENGTH (26 * 4)
 
 #define PASSGEN_DIGITS "0123456789"
 #define PASSGEN_LETTERS_LOW "abcdefghijklmnopqrstuvwxyz"
 #define PASSGEN_LETTERS_UP "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-#define PASSGEN_SPECIAL "!#$%%^&*.-_"
+#define PASSGEN_SPECIAL "!#$%^&*.-_"
 
 typedef enum PassGen_Alphabet {
     Digits = 1,
@@ -26,6 +27,25 @@ typedef enum PassGen_Alphabet {
     Mixed = DigitsAllLetters | Special
 } PassGen_Alphabet;
 
+const char* const PassGen_AlphabetChars[16] = {
+    "0", // invalid value
+    /*    PASSGEN_SPECIAL    PASSGEN_LETTERS_UP    PASSGEN_LETTERS_LOW */ PASSGEN_DIGITS,
+    /*    PASSGEN_SPECIAL    PASSGEN_LETTERS_UP */ PASSGEN_LETTERS_LOW /* PASSGEN_DIGITS */,
+    /*    PASSGEN_SPECIAL    PASSGEN_LETTERS_UP */ PASSGEN_LETTERS_LOW PASSGEN_DIGITS,
+    /*    PASSGEN_SPECIAL */ PASSGEN_LETTERS_UP /* PASSGEN_LETTERS_LOW    PASSGEN_DIGITS */,
+    /*    PASSGEN_SPECIAL */ PASSGEN_LETTERS_UP /* PASSGEN_LETTERS_LOW */ PASSGEN_DIGITS,
+    /*    PASSGEN_SPECIAL */ PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW /* PASSGEN_DIGITS */,
+    /*    PASSGEN_SPECIAL */ PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW PASSGEN_DIGITS,
+    PASSGEN_SPECIAL /* PASSGEN_LETTERS_UP    PASSGEN_LETTERS_LOW    PASSGEN_DIGITS */,
+    PASSGEN_SPECIAL /* PASSGEN_LETTERS_UP    PASSGEN_LETTERS_LOW */ PASSGEN_DIGITS,
+    PASSGEN_SPECIAL /* PASSGEN_LETTERS_UP */ PASSGEN_LETTERS_LOW /* PASSGEN_DIGITS */,
+    PASSGEN_SPECIAL /* PASSGEN_LETTERS_UP */ PASSGEN_LETTERS_LOW PASSGEN_DIGITS,
+    PASSGEN_SPECIAL PASSGEN_LETTERS_UP /* PASSGEN_LETTERS_LOW    PASSGEN_DIGITS */,
+    PASSGEN_SPECIAL PASSGEN_LETTERS_UP /* PASSGEN_LETTERS_LOW */ PASSGEN_DIGITS,
+    PASSGEN_SPECIAL PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW /* PASSGEN_DIGITS */,
+    PASSGEN_SPECIAL PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW PASSGEN_DIGITS,
+};
+
 const int AlphabetLevels[] = {Digits, Lowercase, DigitsLower, DigitsAllLetters, Mixed};
 const char* AlphabetLevelNames[] = {"1234", "abcd", "ab12", "Ab12", "Ab1#"};
 const int AlphabetLevelsCount = sizeof(AlphabetLevels) / sizeof(int);
@@ -44,21 +64,24 @@ typedef struct {
     Gui* gui;
     FuriMutex** mutex;
     NotificationApp* notify;
+    const char* alphabet;
     char password[PASSGEN_MAX_LENGTH + 1];
-    // char alphabet[PASSGEN_CHARACTERS_LENGTH + 1];
-    FuriString* alphabet;
-    int length;
+    int length; // must be <= PASSGEN_MAX_LENGTH
     int level;
 } PassGen;
 
 void state_free(PassGen* app) {
+    // NOTE: would have preferred if a "safe" memset() was available...
+    //       but, since cannot prevent optimization from removing
+    //       memset(), fill with random data instead.
+    furi_hal_random_fill_buf((void*)(app->password), PASSGEN_MAX_LENGTH);
+
     gui_remove_view_port(app->gui, app->view_port);
     furi_record_close(RECORD_GUI);
     view_port_free(app->view_port);
     furi_message_queue_free(app->input_queue);
     furi_mutex_free(app->mutex);
     furi_record_close(RECORD_NOTIFICATION);
-    furi_string_free(app->alphabet);
     free(app);
 }
 
@@ -100,17 +123,19 @@ static void render_callback(Canvas* canvas, void* ctx) {
 
 void build_alphabet(PassGen* app) {
     PassGen_Alphabet mode = AlphabetLevels[app->level];
-    if((mode & Digits) != 0) furi_string_cat(app->alphabet, PASSGEN_DIGITS);
-    if((mode & Lowercase) != 0) furi_string_cat(app->alphabet, PASSGEN_LETTERS_LOW);
-    if((mode & Uppercase) != 0) furi_string_cat(app->alphabet, PASSGEN_LETTERS_UP);
-    if((mode & Special) != 0) furi_string_cat(app->alphabet, PASSGEN_SPECIAL);
+    if(mode > 0 && mode < 16) {
+        app->alphabet = PassGen_AlphabetChars[mode];
+    } else {
+        app->alphabet =
+            PassGen_AlphabetChars[0]; // Invalid mode ... password will be all zero digits
+    }
 }
 
 PassGen* state_init() {
     PassGen* app = malloc(sizeof(PassGen));
+    _Static_assert(8 <= PASSGEN_MAX_LENGTH, "app->length must be set <= PASSGEN_MAX_LENGTH");
     app->length = 8;
     app->level = 2;
-    app->alphabet = furi_string_alloc();
     build_alphabet(app);
     app->input_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
     app->view_port = view_port_alloc();
@@ -126,12 +151,46 @@ PassGen* state_init() {
 }
 
 void generate(PassGen* app) {
-    int hi = furi_string_size(app->alphabet);
-    for(int i = 0; i < app->length; i++) {
-        int x = rand() % hi;
-        app->password[i] = furi_string_get_char(app->alphabet, x);
+    memset(app->password, 0, PASSGEN_MAX_LENGTH + 1);
+
+    int char_option_count = strlen(app->alphabet);
+    if(char_option_count < 0) {
+        return;
+    }
+
+    // determine largest character value that avoids bias
+    char ceil = CHAR_MAX - (CHAR_MAX % char_option_count) - 1;
+
+    // iteratively fill the password buffer with random values
+    // then keep only values that are in-range (no bias)
+    void* remaining_buffer = app->password;
+    size_t remaining_length = (app->length * sizeof(char));
+
+    while(remaining_length != 0) {
+        // fewer calls to hardware TRNG is more efficient
+        furi_hal_random_fill_buf(remaining_buffer, remaining_length);
+
+        // keep only values that are in-range (no bias)
+        char* target = remaining_buffer;
+        char* source = remaining_buffer;
+        size_t valid_count = 0;
+
+        for(size_t i = 0; i < remaining_length; i++) {
+            int v = *source;
+            // if the generated random value is in range, keep it
+            if(v < ceil) {
+                v %= char_option_count;
+                *target = app->alphabet[v];
+                // increment target pointer and count of valid items found
+                target++;
+                valid_count++;
+            }
+            // always increment the source pointer
+            source++;
+        }
+        remaining_length -= valid_count;
+        remaining_buffer = target;
     }
-    app->password[app->length] = '\0';
 }
 
 void update_password(PassGen* app, bool vibro) {