Merge pull request #385 from matheusmoreira/totp-hot-patch
TOTP hotfix: reduce memory usage
This commit is contained in:
commit
1e29fe85e5
@ -39,18 +39,22 @@
|
|||||||
#include "TOTP.h"
|
#include "TOTP.h"
|
||||||
#include "base32.h"
|
#include "base32.h"
|
||||||
|
|
||||||
|
#ifndef TOTP_FACE_MAX_KEY_LENGTH
|
||||||
|
#define TOTP_FACE_MAX_KEY_LENGTH 128
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char labels[2];
|
unsigned char labels[2];
|
||||||
hmac_alg algorithm;
|
hmac_alg algorithm;
|
||||||
uint32_t period;
|
uint32_t period;
|
||||||
size_t key_length;
|
size_t encoded_key_length;
|
||||||
unsigned char *key;
|
unsigned char *encoded_key;
|
||||||
} totp_t;
|
} totp_t;
|
||||||
|
|
||||||
#define CREDENTIAL(label, key_array, algo, timestep) \
|
#define CREDENTIAL(label, key_array, algo, timestep) \
|
||||||
(const totp_t) { \
|
(const totp_t) { \
|
||||||
.key = ((unsigned char *) key_array), \
|
.encoded_key = ((unsigned char *) key_array), \
|
||||||
.key_length = sizeof(key_array) - 1, \
|
.encoded_key_length = sizeof(key_array) - 1, \
|
||||||
.period = (timestep), \
|
.period = (timestep), \
|
||||||
.labels = (#label), \
|
.labels = (#label), \
|
||||||
.algorithm = (algo), \
|
.algorithm = (algo), \
|
||||||
@ -67,15 +71,63 @@ static totp_t credentials[] = {
|
|||||||
// END OF KEY DATA.
|
// END OF KEY DATA.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static inline totp_t *totp_at(size_t i) {
|
||||||
|
return &credentials[i];
|
||||||
|
}
|
||||||
|
|
||||||
static inline totp_t *totp_current(totp_state_t *totp_state) {
|
static inline totp_t *totp_current(totp_state_t *totp_state) {
|
||||||
return &credentials[totp_state->current_index];
|
return totp_at(totp_state->current_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t totp_total(void) {
|
static inline size_t totp_total(void) {
|
||||||
return sizeof(credentials) / sizeof(*credentials);
|
return sizeof(credentials) / sizeof(*credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void totp_display(totp_state_t *totp_state) {
|
static void totp_validate_key_lengths(void) {
|
||||||
|
for (size_t n = totp_total(), i = 0; i < n; ++i) {
|
||||||
|
totp_t *totp = totp_at(i);
|
||||||
|
|
||||||
|
if (UNBASE32_LEN(totp->encoded_key_length) > TOTP_FACE_MAX_KEY_LENGTH) {
|
||||||
|
// Key exceeds static limits, turn it off by zeroing the length
|
||||||
|
totp->encoded_key_length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void totp_generate(totp_state_t *totp_state) {
|
||||||
|
totp_t *totp = totp_current(totp_state);
|
||||||
|
|
||||||
|
if (totp->encoded_key_length <= 0) {
|
||||||
|
// Key exceeded static limits and was turned off
|
||||||
|
totp_state->current_decoded_key_length = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
totp_state->current_decoded_key_length = base32_decode(totp->encoded_key, totp_state->current_decoded_key);
|
||||||
|
|
||||||
|
if (totp_state->current_decoded_key_length == 0) {
|
||||||
|
// Decoding failed for some reason
|
||||||
|
// Not a base 32 string?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TOTP(
|
||||||
|
totp_state->current_decoded_key,
|
||||||
|
totp_state->current_decoded_key_length,
|
||||||
|
totp->period,
|
||||||
|
totp->algorithm
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void totp_display_error(totp_state_t *totp_state) {
|
||||||
|
char buf[10 + 1];
|
||||||
|
totp_t *totp = totp_current(totp_state);
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%c%c ERROR ", totp->labels[0], totp->labels[1]);
|
||||||
|
watch_display_string(buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void totp_display_code(totp_state_t *totp_state) {
|
||||||
char buf[14];
|
char buf[14];
|
||||||
div_t result;
|
div_t result;
|
||||||
uint8_t valid_for;
|
uint8_t valid_for;
|
||||||
@ -92,46 +144,55 @@ static void totp_display(totp_state_t *totp_state) {
|
|||||||
watch_display_string(buf, 0);
|
watch_display_string(buf, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void totp_face_decode_secrets(void) {
|
static void totp_display(totp_state_t *totp_state) {
|
||||||
for (size_t n = totp_total(), i = 0; i < n; ++i) {
|
if (totp_state->current_decoded_key_length > 0) {
|
||||||
totp_t *totp = &credentials[i];
|
totp_display_code(totp_state);
|
||||||
unsigned char *key = totp->key;
|
} else {
|
||||||
|
totp_display_error(totp_state);
|
||||||
totp->key = malloc(UNBASE32_LEN(totp->key_length));
|
|
||||||
totp->key_length = base32_decode(key, totp->key);
|
|
||||||
|
|
||||||
if (totp->key_length == 0) {
|
|
||||||
free(totp->key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void totp_generate_and_display(totp_state_t *totp_state) {
|
||||||
|
totp_generate(totp_state);
|
||||||
|
totp_display(totp_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t totp_compute_base_timestamp(movement_settings_t *settings) {
|
||||||
|
return watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), movement_timezone_offsets[settings->bit.time_zone] * 60);
|
||||||
|
}
|
||||||
|
|
||||||
void totp_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
void totp_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
||||||
(void) settings;
|
(void) settings;
|
||||||
(void) watch_face_index;
|
(void) watch_face_index;
|
||||||
|
|
||||||
|
totp_validate_key_lengths();
|
||||||
|
|
||||||
if (*context_ptr == NULL) {
|
if (*context_ptr == NULL) {
|
||||||
totp_state_t *totp = malloc(sizeof(totp_state_t));
|
totp_state_t *totp = malloc(sizeof(totp_state_t));
|
||||||
totp_face_decode_secrets();
|
totp->current_decoded_key = malloc(TOTP_FACE_MAX_KEY_LENGTH);
|
||||||
*context_ptr = totp;
|
*context_ptr = totp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void totp_face_activate(movement_settings_t *settings, void *context) {
|
void totp_face_activate(movement_settings_t *settings, void *context) {
|
||||||
(void) settings;
|
(void) settings;
|
||||||
memset(context, 0, sizeof(totp_state_t));
|
|
||||||
totp_state_t *totp_state = (totp_state_t *)context;
|
totp_state_t *totp = (totp_state_t *) context;
|
||||||
totp_t *totp = totp_current(totp_state);
|
|
||||||
TOTP(totp->key, totp->key_length, totp->period, totp->algorithm);
|
totp->timestamp = totp_compute_base_timestamp(settings);
|
||||||
totp_state->timestamp = watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), movement_timezone_offsets[settings->bit.time_zone] * 60);
|
totp->steps = 0;
|
||||||
totp_state->current_code = getCodeFromTimestamp(totp_state->timestamp);
|
totp->current_code = 0;
|
||||||
|
totp->current_index = 0;
|
||||||
|
totp->current_decoded_key_length = 0;
|
||||||
|
// totp->current_decoded_key is already initialized in setup
|
||||||
|
|
||||||
|
totp_generate_and_display(totp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||||
(void) settings;
|
(void) settings;
|
||||||
totp_state_t *totp_state = (totp_state_t *)context;
|
|
||||||
totp_t *totp;
|
totp_state_t *totp_state = (totp_state_t *) context;
|
||||||
|
|
||||||
switch (event.event_type) {
|
switch (event.event_type) {
|
||||||
case EVENT_TICK:
|
case EVENT_TICK:
|
||||||
@ -150,9 +211,9 @@ bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void
|
|||||||
// wrap around to first key
|
// wrap around to first key
|
||||||
totp_state->current_index = 0;
|
totp_state->current_index = 0;
|
||||||
}
|
}
|
||||||
totp = totp_current(totp_state);
|
|
||||||
TOTP(totp->key, totp->key_length, totp->period, totp->algorithm);
|
totp_generate_and_display(totp_state);
|
||||||
totp_display(totp_state);
|
|
||||||
break;
|
break;
|
||||||
case EVENT_LIGHT_BUTTON_UP:
|
case EVENT_LIGHT_BUTTON_UP:
|
||||||
if (totp_state->current_index == 0) {
|
if (totp_state->current_index == 0) {
|
||||||
@ -161,9 +222,9 @@ bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void
|
|||||||
} else {
|
} else {
|
||||||
totp_state->current_index--;
|
totp_state->current_index--;
|
||||||
}
|
}
|
||||||
totp = totp_current(totp_state);
|
|
||||||
TOTP(totp->key, totp->key_length, totp->period, totp->algorithm);
|
totp_generate_and_display(totp_state);
|
||||||
totp_display(totp_state);
|
|
||||||
break;
|
break;
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
case EVENT_ALARM_BUTTON_DOWN:
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
case EVENT_ALARM_LONG_PRESS:
|
||||||
|
@ -70,6 +70,8 @@ typedef struct {
|
|||||||
uint8_t steps;
|
uint8_t steps;
|
||||||
uint32_t current_code;
|
uint32_t current_code;
|
||||||
uint8_t current_index;
|
uint8_t current_index;
|
||||||
|
uint8_t *current_decoded_key;
|
||||||
|
size_t current_decoded_key_length;
|
||||||
} totp_state_t;
|
} totp_state_t;
|
||||||
|
|
||||||
void totp_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
void totp_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user