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>
@@ -27,6 +28,25 @@ typedef enum PassGen_Alphabet
27
28
Mixed = DigitsAllLetters | Special
28
29
} PassGen_Alphabet ;
29
30
31
+ const char * const PassGen_AlphabetChars [16 ] = {
32
+ "0" , // invalid value
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
+ PASSGEN_SPECIAL PASSGEN_LETTERS_UP PASSGEN_LETTERS_LOW PASSGEN_DIGITS ,
48
+ };
49
+
30
50
const int AlphabetLevels [] = { Digits , Lowercase , DigitsLower , DigitsAllLetters , Mixed };
31
51
const char * AlphabetLevelNames [] = { "1234" , "abcd" , "ab12" , "Ab12" , "Ab1#" };
32
52
const int AlphabetLevelsCount = sizeof (AlphabetLevels ) / sizeof (int );
@@ -45,13 +65,18 @@ typedef struct {
45
65
Gui * gui ;
46
66
FuriMutex * * mutex ;
47
67
NotificationApp * notify ;
68
+ const char * alphabet ;
48
69
char password [PASSGEN_MAX_LENGTH + 1 ];
49
- char alphabet [PASSGEN_CHARACTERS_LENGTH + 1 ];
50
- int length ;
70
+ int length ; // must be <= PASSGEN_MAX_LENGTH
51
71
int level ;
52
72
} PassGen ;
53
73
54
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
+
55
80
gui_remove_view_port (app -> gui , app -> view_port );
56
81
furi_record_close (RECORD_GUI );
57
82
view_port_free (app -> view_port );
@@ -100,19 +125,16 @@ static void render_callback(Canvas* canvas, void* ctx) {
100
125
void build_alphabet (PassGen * app )
101
126
{
102
127
PassGen_Alphabet mode = AlphabetLevels [app -> level ];
103
- app -> alphabet [0 ] = '\0' ;
104
- if ((mode & Digits ) != 0 )
105
- strcat (app -> alphabet , PASSGEN_DIGITS );
106
- if ((mode & Lowercase ) != 0 )
107
- strcat (app -> alphabet , PASSGEN_LETTERS_LOW );
108
- if ((mode & Uppercase ) != 0 )
109
- strcat (app -> alphabet , PASSGEN_LETTERS_UP );
110
- if ((mode & Special ) != 0 )
111
- strcat (app -> alphabet , PASSGEN_SPECIAL );
128
+ if (mode > 0 && mode < 16 ) {
129
+ app -> alphabet = PassGen_AlphabetChars [mode ];
130
+ } else {
131
+ app -> alphabet = PassGen_AlphabetChars [0 ]; // Invalid mode ... password will be all zero digits
132
+ }
112
133
}
113
134
114
135
PassGen * state_init () {
115
136
PassGen * app = malloc (sizeof (PassGen ));
137
+ _Static_assert (8 <= PASSGEN_MAX_LENGTH , "app->length must be set <= PASSGEN_MAX_LENGTH" );
116
138
app -> length = 8 ;
117
139
app -> level = 2 ;
118
140
build_alphabet (app );
@@ -131,13 +153,46 @@ PassGen* state_init() {
131
153
132
154
void generate (PassGen * app )
133
155
{
134
- int hi = strlen (app -> alphabet );
135
- for (int i = 0 ; i < app -> length ; i ++ )
136
- {
137
- int x = rand () % hi ;
138
- 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 ;
139
195
}
140
- app -> password [app -> length ] = '\0' ;
141
196
}
142
197
143
198
void update_password (PassGen * app , bool vibro )
0 commit comments