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>
@@ -66,11 +67,16 @@ typedef struct {
66
67
NotificationApp * notify ;
67
68
const char * alphabet ;
68
69
char password [PASSGEN_MAX_LENGTH + 1 ];
69
- int length ;
70
+ int length ; // must be <= PASSGEN_MAX_LENGTH
70
71
int level ;
71
72
} PassGen ;
72
73
73
74
void state_free (PassGen * app ) {
75
+ // NOTE: would have preferred if a "safe" memset() was available...
76
+ // but, since cannot prevent optimization from removing
77
+ // memset(), fill with random data instead.
78
+ furi_hal_random_fill_buf ((void * )(app -> password ), PASSGEN_MAX_LENGTH );
79
+
74
80
gui_remove_view_port (app -> gui , app -> view_port );
75
81
furi_record_close (RECORD_GUI );
76
82
view_port_free (app -> view_port );
@@ -128,6 +134,7 @@ void build_alphabet(PassGen* app)
128
134
129
135
PassGen * state_init () {
130
136
PassGen * app = malloc (sizeof (PassGen ));
137
+ _Static_assert (8 <= PASSGEN_MAX_LENGTH , "app->length must be set <= PASSGEN_MAX_LENGTH" );
131
138
app -> length = 8 ;
132
139
app -> level = 2 ;
133
140
build_alphabet (app );
@@ -146,13 +153,46 @@ PassGen* state_init() {
146
153
147
154
void generate (PassGen * app )
148
155
{
149
- int hi = strlen (app -> alphabet );
150
- for (int i = 0 ; i < app -> length ; i ++ )
151
- {
152
- int x = rand () % hi ;
153
- app -> password [i ]= app -> alphabet [x ];
156
+ memset (app -> password , 0 , PASSGEN_MAX_LENGTH + 1 );
157
+
158
+ int char_option_count = strlen (app -> alphabet );
159
+ if (char_option_count < 0 ) {
160
+ return ;
161
+ }
162
+
163
+ // determine largest character value that avoids bias
164
+ char ceil = CHAR_MAX - (CHAR_MAX % char_option_count ) - 1 ;
165
+
166
+ // iteratively fill the password buffer with random values
167
+ // then keep only values that are in-range (no bias)
168
+ void * remaining_buffer = app -> password ;
169
+ size_t remaining_length = (app -> length * sizeof (char ));
170
+
171
+ while (remaining_length != 0 ) {
172
+ // fewer calls to hardware TRNG is more efficient
173
+ furi_hal_random_fill_buf (remaining_buffer , remaining_length );
174
+
175
+ // keep only values that are in-range (no bias)
176
+ char * target = remaining_buffer ;
177
+ char * source = remaining_buffer ;
178
+ size_t valid_count = 0 ;
179
+
180
+ for (size_t i = 0 ; i < remaining_length ; i ++ ) {
181
+ int v = * source ;
182
+ // if the generated random value is in range, keep it
183
+ if (v < ceil ) {
184
+ v %= char_option_count ;
185
+ * target = app -> alphabet [v ];
186
+ // increment target pointer and count of valid items found
187
+ target ++ ;
188
+ valid_count ++ ;
189
+ }
190
+ // always increment the source pointer
191
+ source ++ ;
192
+ }
193
+ remaining_length -= valid_count ;
194
+ remaining_buffer = target ;
154
195
}
155
- app -> password [app -> length ] = '\0' ;
156
196
}
157
197
158
198
void update_password (PassGen * app , bool vibro )
0 commit comments