39
39
#include "TOTP.h"
40
40
#include "base32.h"
41
41
42
+ #ifndef TOTP_FACE_MAX_KEY_LENGTH
43
+ #define TOTP_FACE_MAX_KEY_LENGTH 128
44
+ #endif
45
+
42
46
typedef struct {
43
47
unsigned char labels [2 ];
44
48
hmac_alg algorithm ;
45
49
uint32_t period ;
46
- size_t key_length ;
47
- unsigned char * key ;
50
+ size_t encoded_key_length ;
51
+ unsigned char * encoded_key ;
48
52
} totp_t ;
49
53
50
54
#define CREDENTIAL (label , key_array , algo , timestep ) \
51
55
(const totp_t) { \
52
- .key = ((unsigned char *) key_array), \
53
- .key_length = sizeof(key_array) - 1, \
56
+ .encoded_key = ((unsigned char *) key_array), \
57
+ .encoded_key_length = sizeof(key_array) - 1, \
54
58
.period = (timestep), \
55
59
.labels = (#label), \
56
60
.algorithm = (algo), \
@@ -67,15 +71,63 @@ static totp_t credentials[] = {
67
71
// END OF KEY DATA.
68
72
////////////////////////////////////////////////////////////////////////////////
69
73
74
+ static inline totp_t * totp_at (size_t i ) {
75
+ return & credentials [i ];
76
+ }
77
+
70
78
static inline totp_t * totp_current (totp_state_t * totp_state ) {
71
- return & credentials [ totp_state -> current_index ] ;
79
+ return totp_at ( totp_state -> current_index ) ;
72
80
}
73
81
74
82
static inline size_t totp_total (void ) {
75
83
return sizeof (credentials ) / sizeof (* credentials );
76
84
}
77
85
78
- static void totp_display (totp_state_t * totp_state ) {
86
+ static void totp_validate_key_lengths (void ) {
87
+ for (size_t n = totp_total (), i = 0 ; i < n ; ++ i ) {
88
+ totp_t * totp = totp_at (i );
89
+
90
+ if (UNBASE32_LEN (totp -> encoded_key_length ) > TOTP_FACE_MAX_KEY_LENGTH ) {
91
+ // Key exceeds static limits, turn it off by zeroing the length
92
+ totp -> encoded_key_length = 0 ;
93
+ }
94
+ }
95
+ }
96
+
97
+ static void totp_generate (totp_state_t * totp_state ) {
98
+ totp_t * totp = totp_current (totp_state );
99
+
100
+ if (totp -> encoded_key_length <= 0 ) {
101
+ // Key exceeded static limits and was turned off
102
+ totp_state -> current_decoded_key_length = 0 ;
103
+ return ;
104
+ }
105
+
106
+ totp_state -> current_decoded_key_length = base32_decode (totp -> encoded_key , totp_state -> current_decoded_key );
107
+
108
+ if (totp_state -> current_decoded_key_length == 0 ) {
109
+ // Decoding failed for some reason
110
+ // Not a base 32 string?
111
+ return ;
112
+ }
113
+
114
+ TOTP (
115
+ totp_state -> current_decoded_key ,
116
+ totp_state -> current_decoded_key_length ,
117
+ totp -> period ,
118
+ totp -> algorithm
119
+ );
120
+ }
121
+
122
+ static void totp_display_error (totp_state_t * totp_state ) {
123
+ char buf [10 + 1 ];
124
+ totp_t * totp = totp_current (totp_state );
125
+
126
+ snprintf (buf , sizeof (buf ), "%c%c ERROR " , totp -> labels [0 ], totp -> labels [1 ]);
127
+ watch_display_string (buf , 0 );
128
+ }
129
+
130
+ static void totp_display_code (totp_state_t * totp_state ) {
79
131
char buf [14 ];
80
132
div_t result ;
81
133
uint8_t valid_for ;
@@ -92,46 +144,55 @@ static void totp_display(totp_state_t *totp_state) {
92
144
watch_display_string (buf , 0 );
93
145
}
94
146
95
- static void totp_face_decode_secrets (void ) {
96
- for (size_t n = totp_total (), i = 0 ; i < n ; ++ i ) {
97
- totp_t * totp = & credentials [i ];
98
- unsigned char * key = totp -> key ;
147
+ static void totp_display (totp_state_t * totp_state ) {
148
+ if (totp_state -> current_decoded_key_length > 0 ) {
149
+ totp_display_code (totp_state );
150
+ } else {
151
+ totp_display_error (totp_state );
152
+ }
153
+ }
99
154
100
- totp -> key = malloc (UNBASE32_LEN (totp -> key_length ));
101
- totp -> key_length = base32_decode (key , totp -> key );
155
+ static void totp_generate_and_display (totp_state_t * totp_state ) {
156
+ totp_generate (totp_state );
157
+ totp_display (totp_state );
158
+ }
102
159
103
- if (totp -> key_length == 0 ) {
104
- free (totp -> key );
105
- continue ;
106
- }
107
- }
160
+ static inline uint32_t totp_compute_base_timestamp (movement_settings_t * settings ) {
161
+ return watch_utility_date_time_to_unix_time (watch_rtc_get_date_time (), movement_timezone_offsets [settings -> bit .time_zone ] * 60 );
108
162
}
109
163
110
164
void totp_face_setup (movement_settings_t * settings , uint8_t watch_face_index , void * * context_ptr ) {
111
165
(void ) settings ;
112
166
(void ) watch_face_index ;
113
167
168
+ totp_validate_key_lengths ();
169
+
114
170
if (* context_ptr == NULL ) {
115
171
totp_state_t * totp = malloc (sizeof (totp_state_t ));
116
- totp_face_decode_secrets ( );
172
+ totp -> current_decoded_key = malloc ( TOTP_FACE_MAX_KEY_LENGTH );
117
173
* context_ptr = totp ;
118
174
}
119
175
}
120
176
121
177
void totp_face_activate (movement_settings_t * settings , void * context ) {
122
178
(void ) settings ;
123
- memset (context , 0 , sizeof (totp_state_t ));
124
- totp_state_t * totp_state = (totp_state_t * )context ;
125
- totp_t * totp = totp_current (totp_state );
126
- TOTP (totp -> key , totp -> key_length , totp -> period , totp -> algorithm );
127
- totp_state -> timestamp = watch_utility_date_time_to_unix_time (watch_rtc_get_date_time (), movement_timezone_offsets [settings -> bit .time_zone ] * 60 );
128
- totp_state -> current_code = getCodeFromTimestamp (totp_state -> timestamp );
179
+
180
+ totp_state_t * totp = (totp_state_t * ) context ;
181
+
182
+ totp -> timestamp = totp_compute_base_timestamp (settings );
183
+ totp -> steps = 0 ;
184
+ totp -> current_code = 0 ;
185
+ totp -> current_index = 0 ;
186
+ totp -> current_decoded_key_length = 0 ;
187
+ // totp->current_decoded_key is already initialized in setup
188
+
189
+ totp_generate_and_display (totp );
129
190
}
130
191
131
192
bool totp_face_loop (movement_event_t event , movement_settings_t * settings , void * context ) {
132
193
(void ) settings ;
133
- totp_state_t * totp_state = ( totp_state_t * ) context ;
134
- totp_t * totp ;
194
+
195
+ totp_state_t * totp_state = ( totp_state_t * ) context ;
135
196
136
197
switch (event .event_type ) {
137
198
case EVENT_TICK :
@@ -150,9 +211,9 @@ bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void
150
211
// wrap around to first key
151
212
totp_state -> current_index = 0 ;
152
213
}
153
- totp = totp_current ( totp_state );
154
- TOTP ( totp -> key , totp -> key_length , totp -> period , totp -> algorithm );
155
- totp_display ( totp_state );
214
+
215
+ totp_generate_and_display ( totp_state );
216
+
156
217
break ;
157
218
case EVENT_LIGHT_BUTTON_UP :
158
219
if (totp_state -> current_index == 0 ) {
@@ -161,9 +222,9 @@ bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void
161
222
} else {
162
223
totp_state -> current_index -- ;
163
224
}
164
- totp = totp_current ( totp_state );
165
- TOTP ( totp -> key , totp -> key_length , totp -> period , totp -> algorithm );
166
- totp_display ( totp_state );
225
+
226
+ totp_generate_and_display ( totp_state );
227
+
167
228
break ;
168
229
case EVENT_ALARM_BUTTON_DOWN :
169
230
case EVENT_ALARM_LONG_PRESS :
0 commit comments