1
1
#include <furi.h>
2
+ #include <furi_hal_random.h>
2
3
#include <gui/gui.h>
3
4
#include <gui/elements.h>
4
5
#include <input/input.h>
5
6
#include <notification/notification_messages.h>
6
7
#include <stdlib.h>
7
8
#include <passgen_icons.h>
8
- #include <core/string.h>
9
9
10
10
#define PASSGEN_MAX_LENGTH 16
11
+ #define PASSGEN_CHARACTERS_LENGTH (26 * 4)
11
12
12
13
#define PASSGEN_DIGITS "0123456789"
13
14
#define PASSGEN_LETTERS_LOW "abcdefghijklmnopqrstuvwxyz"
14
15
#define PASSGEN_LETTERS_UP "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
15
- #define PASSGEN_SPECIAL "!#$%% ^&*.-_"
16
+ #define PASSGEN_SPECIAL "!#$%^&*.-_"
16
17
17
18
typedef enum PassGen_Alphabet {
18
19
Digits = 1 ,
@@ -26,6 +27,25 @@ typedef enum PassGen_Alphabet {
26
27
Mixed = DigitsAllLetters | Special
27
28
} PassGen_Alphabet ;
28
29
30
+ const char * const PassGen_AlphabetChars [16 ] = {
31
+ "0" , // invalid value
32
+ /* PASSGEN_SPECIAL PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW */ PASSGEN_DIGITS ,
33
+ /* PASSGEN_SPECIAL PASSGEN_LETTERS_UP */ PASSGEN_LETTERS_LOW /* PASSGEN_DIGITS */ ,
34
+ /* PASSGEN_SPECIAL PASSGEN_LETTERS_UP */ PASSGEN_LETTERS_LOW PASSGEN_DIGITS ,
35
+ /* PASSGEN_SPECIAL */ PASSGEN_LETTERS_UP /* PASSGEN_LETTERS_LOW PASSGEN_DIGITS */ ,
36
+ /* PASSGEN_SPECIAL */ PASSGEN_LETTERS_UP /* PASSGEN_LETTERS_LOW */ PASSGEN_DIGITS ,
37
+ /* PASSGEN_SPECIAL */ PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW /* PASSGEN_DIGITS */ ,
38
+ /* PASSGEN_SPECIAL */ PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW PASSGEN_DIGITS ,
39
+ PASSGEN_SPECIAL /* PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW PASSGEN_DIGITS */ ,
40
+ PASSGEN_SPECIAL /* PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW */ PASSGEN_DIGITS ,
41
+ PASSGEN_SPECIAL /* PASSGEN_LETTERS_UP */ PASSGEN_LETTERS_LOW /* PASSGEN_DIGITS */ ,
42
+ PASSGEN_SPECIAL /* PASSGEN_LETTERS_UP */ PASSGEN_LETTERS_LOW PASSGEN_DIGITS ,
43
+ PASSGEN_SPECIAL PASSGEN_LETTERS_UP /* PASSGEN_LETTERS_LOW PASSGEN_DIGITS */ ,
44
+ PASSGEN_SPECIAL PASSGEN_LETTERS_UP /* PASSGEN_LETTERS_LOW */ PASSGEN_DIGITS ,
45
+ PASSGEN_SPECIAL PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW /* PASSGEN_DIGITS */ ,
46
+ PASSGEN_SPECIAL PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW PASSGEN_DIGITS ,
47
+ };
48
+
29
49
const int AlphabetLevels [] = {Digits , Lowercase , DigitsLower , DigitsAllLetters , Mixed };
30
50
const char * AlphabetLevelNames [] = {"1234" , "abcd" , "ab12" , "Ab12" , "Ab1#" };
31
51
const int AlphabetLevelsCount = sizeof (AlphabetLevels ) / sizeof (int );
@@ -44,21 +64,24 @@ typedef struct {
44
64
Gui * gui ;
45
65
FuriMutex * * mutex ;
46
66
NotificationApp * notify ;
67
+ const char * alphabet ;
47
68
char password [PASSGEN_MAX_LENGTH + 1 ];
48
- // char alphabet[PASSGEN_CHARACTERS_LENGTH + 1];
49
- FuriString * alphabet ;
50
- int length ;
69
+ int length ; // must be <= PASSGEN_MAX_LENGTH
51
70
int level ;
52
71
} PassGen ;
53
72
54
73
void state_free (PassGen * app ) {
74
+ // NOTE: would have preferred if a "safe" memset() was available...
75
+ // but, since cannot prevent optimization from removing
76
+ // memset(), fill with random data instead.
77
+ furi_hal_random_fill_buf ((void * )(app -> password ), PASSGEN_MAX_LENGTH );
78
+
55
79
gui_remove_view_port (app -> gui , app -> view_port );
56
80
furi_record_close (RECORD_GUI );
57
81
view_port_free (app -> view_port );
58
82
furi_message_queue_free (app -> input_queue );
59
83
furi_mutex_free (app -> mutex );
60
84
furi_record_close (RECORD_NOTIFICATION );
61
- furi_string_free (app -> alphabet );
62
85
free (app );
63
86
}
64
87
@@ -100,17 +123,19 @@ static void render_callback(Canvas* canvas, void* ctx) {
100
123
101
124
void build_alphabet (PassGen * app ) {
102
125
PassGen_Alphabet mode = AlphabetLevels [app -> level ];
103
- if ((mode & Digits ) != 0 ) furi_string_cat (app -> alphabet , PASSGEN_DIGITS );
104
- if ((mode & Lowercase ) != 0 ) furi_string_cat (app -> alphabet , PASSGEN_LETTERS_LOW );
105
- if ((mode & Uppercase ) != 0 ) furi_string_cat (app -> alphabet , PASSGEN_LETTERS_UP );
106
- if ((mode & Special ) != 0 ) furi_string_cat (app -> alphabet , PASSGEN_SPECIAL );
126
+ if (mode > 0 && mode < 16 ) {
127
+ app -> alphabet = PassGen_AlphabetChars [mode ];
128
+ } else {
129
+ app -> alphabet =
130
+ PassGen_AlphabetChars [0 ]; // Invalid mode ... password will be all zero digits
131
+ }
107
132
}
108
133
109
134
PassGen * state_init () {
110
135
PassGen * app = malloc (sizeof (PassGen ));
136
+ _Static_assert (8 <= PASSGEN_MAX_LENGTH , "app->length must be set <= PASSGEN_MAX_LENGTH" );
111
137
app -> length = 8 ;
112
138
app -> level = 2 ;
113
- app -> alphabet = furi_string_alloc ();
114
139
build_alphabet (app );
115
140
app -> input_queue = furi_message_queue_alloc (8 , sizeof (InputEvent ));
116
141
app -> view_port = view_port_alloc ();
@@ -126,12 +151,46 @@ PassGen* state_init() {
126
151
}
127
152
128
153
void generate (PassGen * app ) {
129
- int hi = furi_string_size (app -> alphabet );
130
- for (int i = 0 ; i < app -> length ; i ++ ) {
131
- int x = rand () % hi ;
132
- app -> password [i ] = furi_string_get_char (app -> alphabet , x );
154
+ memset (app -> password , 0 , PASSGEN_MAX_LENGTH + 1 );
155
+
156
+ int char_option_count = strlen (app -> alphabet );
157
+ if (char_option_count < 0 ) {
158
+ return ;
159
+ }
160
+
161
+ // determine largest character value that avoids bias
162
+ char ceil = CHAR_MAX - (CHAR_MAX % char_option_count ) - 1 ;
163
+
164
+ // iteratively fill the password buffer with random values
165
+ // then keep only values that are in-range (no bias)
166
+ void * remaining_buffer = app -> password ;
167
+ size_t remaining_length = (app -> length * sizeof (char ));
168
+
169
+ while (remaining_length != 0 ) {
170
+ // fewer calls to hardware TRNG is more efficient
171
+ furi_hal_random_fill_buf (remaining_buffer , remaining_length );
172
+
173
+ // keep only values that are in-range (no bias)
174
+ char * target = remaining_buffer ;
175
+ char * source = remaining_buffer ;
176
+ size_t valid_count = 0 ;
177
+
178
+ for (size_t i = 0 ; i < remaining_length ; i ++ ) {
179
+ int v = * source ;
180
+ // if the generated random value is in range, keep it
181
+ if (v < ceil ) {
182
+ v %= char_option_count ;
183
+ * target = app -> alphabet [v ];
184
+ // increment target pointer and count of valid items found
185
+ target ++ ;
186
+ valid_count ++ ;
187
+ }
188
+ // always increment the source pointer
189
+ source ++ ;
190
+ }
191
+ remaining_length -= valid_count ;
192
+ remaining_buffer = target ;
133
193
}
134
- app -> password [app -> length ] = '\0' ;
135
194
}
136
195
137
196
void update_password (PassGen * app , bool vibro ) {
0 commit comments