This commit is contained in:
RogueMaster
2022-10-17 10:24:19 -04:00
parent 441e0fad45
commit 8f416c9304
48 changed files with 2235 additions and 1769 deletions

View File

@@ -29,8 +29,8 @@ void view_unlock_model(View* view) {
} }
static void commit_text_input_callback(void* context) { static void commit_text_input_callback(void* context) {
InputTextSceneState* text_input_state = (InputTextSceneState *)context; InputTextSceneState* text_input_state = (InputTextSceneState*)context;
if (text_input_state->callback != 0) { if(text_input_state->callback != 0) {
InputTextSceneCallbackResult* result = malloc(sizeof(InputTextSceneCallbackResult)); InputTextSceneCallbackResult* result = malloc(sizeof(InputTextSceneCallbackResult));
result->user_input_length = strlen(text_input_state->text_input_buffer); result->user_input_length = strlen(text_input_state->text_input_buffer);
result->user_input = malloc(result->user_input_length + 1); result->user_input = malloc(result->user_input_length + 1);

View File

@@ -11,9 +11,9 @@
#include "../generate_token/totp_scene_generate_token.h" #include "../generate_token/totp_scene_generate_token.h"
#define TOKEN_ALGO_LIST_LENGTH 3 #define TOKEN_ALGO_LIST_LENGTH 3
char* TOKEN_ALGO_LIST[] = { "SHA1", "SHA256", "SHA512" }; char* TOKEN_ALGO_LIST[] = {"SHA1", "SHA256", "SHA512"};
#define TOKEN_DIGITS_LIST_LENGTH 2 #define TOKEN_DIGITS_LIST_LENGTH 2
char* TOKEN_DIGITS_LIST[] = { "6 digits", "8 digits" }; char* TOKEN_DIGITS_LIST[] = {"6 digits", "8 digits"};
typedef enum { typedef enum {
TokenNameTextBox, TokenNameTextBox,
@@ -62,7 +62,9 @@ static void on_token_secret_user_comitted(InputTextSceneCallbackResult* result)
free(result); free(result);
} }
void totp_scene_add_new_token_activate(PluginState* plugin_state, const TokenAddEditSceneContext* context) { void totp_scene_add_new_token_activate(
PluginState* plugin_state,
const TokenAddEditSceneContext* context) {
SceneState* scene_state = malloc(sizeof(SceneState)); SceneState* scene_state = malloc(sizeof(SceneState));
plugin_state->current_scene_state = scene_state; plugin_state->current_scene_state = scene_state;
scene_state->token_name = "Name"; scene_state->token_name = "Name";
@@ -84,7 +86,7 @@ void totp_scene_add_new_token_activate(PluginState* plugin_state, const TokenAdd
scene_state->input_state = NULL; scene_state->input_state = NULL;
if (context == NULL) { if(context == NULL) {
scene_state->current_token_index = -1; scene_state->current_token_index = -1;
} else { } else {
scene_state->current_token_index = context->current_token_index; scene_state->current_token_index = context->current_token_index;
@@ -92,17 +94,44 @@ void totp_scene_add_new_token_activate(PluginState* plugin_state, const TokenAdd
} }
void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_state) { void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_state) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
if (scene_state->input_started_at > 0) { if(scene_state->input_started_at > 0) {
totp_input_text_render(canvas, scene_state->input_state); totp_input_text_render(canvas, scene_state->input_state);
return; return;
} }
ui_control_text_box_render(canvas, 10 - scene_state->screen_y_offset, scene_state->token_name, scene_state->selected_control == TokenNameTextBox); ui_control_text_box_render(
ui_control_text_box_render(canvas, 27 - scene_state->screen_y_offset, scene_state->token_secret, scene_state->selected_control == TokenSecretTextBox); canvas,
ui_control_select_render(canvas, 0, 44 - scene_state->screen_y_offset, SCREEN_WIDTH, TOKEN_ALGO_LIST[scene_state->algo], scene_state->selected_control == TokenAlgoSelect); 10 - scene_state->screen_y_offset,
ui_control_select_render(canvas, 0, 63 - scene_state->screen_y_offset, SCREEN_WIDTH, TOKEN_DIGITS_LIST[scene_state->digits_count], scene_state->selected_control == TokenLengthSelect); scene_state->token_name,
ui_control_button_render(canvas, SCREEN_WIDTH_CENTER - 24, 85 - scene_state->screen_y_offset, 48, 13, "Confirm", scene_state->selected_control == ConfirmButton); scene_state->selected_control == TokenNameTextBox);
ui_control_text_box_render(
canvas,
27 - scene_state->screen_y_offset,
scene_state->token_secret,
scene_state->selected_control == TokenSecretTextBox);
ui_control_select_render(
canvas,
0,
44 - scene_state->screen_y_offset,
SCREEN_WIDTH,
TOKEN_ALGO_LIST[scene_state->algo],
scene_state->selected_control == TokenAlgoSelect);
ui_control_select_render(
canvas,
0,
63 - scene_state->screen_y_offset,
SCREEN_WIDTH,
TOKEN_DIGITS_LIST[scene_state->digits_count],
scene_state->selected_control == TokenLengthSelect);
ui_control_button_render(
canvas,
SCREEN_WIDTH_CENTER - 24,
85 - scene_state->screen_y_offset,
48,
13,
"Confirm",
scene_state->selected_control == ConfirmButton);
canvas_set_color(canvas, ColorWhite); canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 0, 0, SCREEN_WIDTH, 10); canvas_draw_box(canvas, 0, 0, SCREEN_WIDTH, 10);
@@ -113,7 +142,7 @@ void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_s
} }
void update_screen_y_offset(SceneState* scene_state) { void update_screen_y_offset(SceneState* scene_state) {
if (scene_state->selected_control > TokenAlgoSelect) { if(scene_state->selected_control > TokenAlgoSelect) {
scene_state->screen_y_offset = 35; scene_state->screen_y_offset = 35;
} else { } else {
scene_state->screen_y_offset = 0; scene_state->screen_y_offset = 0;
@@ -122,112 +151,121 @@ void update_screen_y_offset(SceneState* scene_state) {
bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState* plugin_state) { bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState* plugin_state) {
if(event->type == EventTypeKey) { if(event->type == EventTypeKey) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
if (scene_state->input_started_at > 0 && furi_get_tick() - scene_state->input_started_at > 300) { if(scene_state->input_started_at > 0 &&
furi_get_tick() - scene_state->input_started_at > 300) {
return totp_input_text_handle_event(event, scene_state->input_state); return totp_input_text_handle_event(event, scene_state->input_state);
} }
if (event->input.type == InputTypeLong && event->input.key == InputKeyBack) { if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) {
return false; return false;
} else if(event->input.type == InputTypePress) { } else if(event->input.type == InputTypePress) {
switch(event->input.key) { switch(event->input.key) {
case InputKeyUp: case InputKeyUp:
if (scene_state->selected_control > TokenNameTextBox) { if(scene_state->selected_control > TokenNameTextBox) {
scene_state->selected_control--; scene_state->selected_control--;
update_screen_y_offset(scene_state); update_screen_y_offset(scene_state);
} }
break; break;
case InputKeyDown: case InputKeyDown:
if (scene_state->selected_control < ConfirmButton) { if(scene_state->selected_control < ConfirmButton) {
scene_state->selected_control++; scene_state->selected_control++;
update_screen_y_offset(scene_state); update_screen_y_offset(scene_state);
} }
break; break;
case InputKeyRight: case InputKeyRight:
if (scene_state->selected_control == TokenAlgoSelect) { if(scene_state->selected_control == TokenAlgoSelect) {
if (scene_state->algo < SHA512) { if(scene_state->algo < SHA512) {
scene_state->algo++; scene_state->algo++;
} else {
scene_state->algo = SHA1;
}
}
else if (scene_state->selected_control == TokenLengthSelect) {
if (scene_state->digits_count < TOTP_8_DIGITS) {
scene_state->digits_count++;
} else {
scene_state->digits_count = TOTP_6_DIGITS;
}
}
break;
case InputKeyLeft:
if (scene_state->selected_control == TokenAlgoSelect) {
if (scene_state->algo > SHA1) {
scene_state->algo--;
} else {
scene_state->algo = SHA512;
}
}
else if (scene_state->selected_control == TokenLengthSelect) {
if (scene_state->digits_count > TOTP_6_DIGITS) {
scene_state->digits_count--;
} else {
scene_state->digits_count = TOTP_8_DIGITS;
}
}
break;
case InputKeyOk:
switch (scene_state->selected_control) {
case TokenNameTextBox:
if (scene_state->input_state != NULL) {
totp_input_text_free(scene_state->input_state);
}
scene_state->input_state = totp_input_text_activate(scene_state->token_name_input_context);
scene_state->input_started_at = furi_get_tick();
break;
case TokenSecretTextBox:
if (scene_state->input_state != NULL) {
totp_input_text_free(scene_state->input_state);
}
scene_state->input_state = totp_input_text_activate(scene_state->token_secret_input_context);
scene_state->input_started_at = furi_get_tick();
break;
case TokenAlgoSelect:
break;
case TokenLengthSelect:
break;
case ConfirmButton: {
TokenInfo* tokenInfo = token_info_alloc();
tokenInfo->name = malloc(scene_state->token_name_length + 1);
strcpy(tokenInfo->name, scene_state->token_name);
token_info_set_secret(tokenInfo, scene_state->token_secret, scene_state->token_secret_length, &plugin_state->iv[0]);
tokenInfo->algo = scene_state->algo;
tokenInfo->digits = scene_state->digits_count;
if (plugin_state->tokens_list == NULL) {
plugin_state->tokens_list = list_init_head(tokenInfo);
} else {
list_add(plugin_state->tokens_list, tokenInfo);
}
plugin_state->tokens_count++;
totp_config_file_save_new_token(tokenInfo);
GenerateTokenSceneContext generate_scene_context = { .current_token_index = plugin_state->tokens_count - 1 };
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, &generate_scene_context);
break;
}
}
break;
case InputKeyBack:
if (scene_state->current_token_index >= 0) {
GenerateTokenSceneContext generate_scene_context = { .current_token_index = scene_state->current_token_index };
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, &generate_scene_context);
} else { } else {
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); scene_state->algo = SHA1;
} }
} else if(scene_state->selected_control == TokenLengthSelect) {
if(scene_state->digits_count < TOTP_8_DIGITS) {
scene_state->digits_count++;
} else {
scene_state->digits_count = TOTP_6_DIGITS;
}
}
break;
case InputKeyLeft:
if(scene_state->selected_control == TokenAlgoSelect) {
if(scene_state->algo > SHA1) {
scene_state->algo--;
} else {
scene_state->algo = SHA512;
}
} else if(scene_state->selected_control == TokenLengthSelect) {
if(scene_state->digits_count > TOTP_6_DIGITS) {
scene_state->digits_count--;
} else {
scene_state->digits_count = TOTP_8_DIGITS;
}
}
break;
case InputKeyOk:
switch(scene_state->selected_control) {
case TokenNameTextBox:
if(scene_state->input_state != NULL) {
totp_input_text_free(scene_state->input_state);
}
scene_state->input_state =
totp_input_text_activate(scene_state->token_name_input_context);
scene_state->input_started_at = furi_get_tick();
break; break;
case TokenSecretTextBox:
if(scene_state->input_state != NULL) {
totp_input_text_free(scene_state->input_state);
}
scene_state->input_state =
totp_input_text_activate(scene_state->token_secret_input_context);
scene_state->input_started_at = furi_get_tick();
break;
case TokenAlgoSelect:
break;
case TokenLengthSelect:
break;
case ConfirmButton: {
TokenInfo* tokenInfo = token_info_alloc();
tokenInfo->name = malloc(scene_state->token_name_length + 1);
strcpy(tokenInfo->name, scene_state->token_name);
token_info_set_secret(
tokenInfo,
scene_state->token_secret,
scene_state->token_secret_length,
&plugin_state->iv[0]);
tokenInfo->algo = scene_state->algo;
tokenInfo->digits = scene_state->digits_count;
if(plugin_state->tokens_list == NULL) {
plugin_state->tokens_list = list_init_head(tokenInfo);
} else {
list_add(plugin_state->tokens_list, tokenInfo);
}
plugin_state->tokens_count++;
totp_config_file_save_new_token(tokenInfo);
GenerateTokenSceneContext generate_scene_context = {
.current_token_index = plugin_state->tokens_count - 1};
totp_scene_director_activate_scene(
plugin_state, TotpSceneGenerateToken, &generate_scene_context);
break;
}
}
break;
case InputKeyBack:
if(scene_state->current_token_index >= 0) {
GenerateTokenSceneContext generate_scene_context = {
.current_token_index = scene_state->current_token_index};
totp_scene_director_activate_scene(
plugin_state, TotpSceneGenerateToken, &generate_scene_context);
} else {
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
}
break;
} }
} }
} }
@@ -235,8 +273,8 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
} }
void totp_scene_add_new_token_deactivate(PluginState* plugin_state) { void totp_scene_add_new_token_deactivate(PluginState* plugin_state) {
if (plugin_state->current_scene_state == NULL) return; if(plugin_state->current_scene_state == NULL) return;
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
free(scene_state->token_name); free(scene_state->token_name);
free(scene_state->token_secret); free(scene_state->token_secret);
@@ -246,7 +284,7 @@ void totp_scene_add_new_token_deactivate(PluginState* plugin_state) {
free(scene_state->token_secret_input_context->header_text); free(scene_state->token_secret_input_context->header_text);
free(scene_state->token_secret_input_context); free(scene_state->token_secret_input_context);
if (scene_state->input_state != NULL) { if(scene_state->input_state != NULL) {
totp_input_text_free(scene_state->input_state); totp_input_text_free(scene_state->input_state);
} }

View File

@@ -11,7 +11,9 @@ typedef struct {
} TokenAddEditSceneContext; } TokenAddEditSceneContext;
void totp_scene_add_new_token_init(PluginState* plugin_state); void totp_scene_add_new_token_init(PluginState* plugin_state);
void totp_scene_add_new_token_activate(PluginState* plugin_state, const TokenAddEditSceneContext* context); void totp_scene_add_new_token_activate(
PluginState* plugin_state,
const TokenAddEditSceneContext* context);
void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_state); void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_state);
bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState* plugin_state); bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState* plugin_state);
void totp_scene_add_new_token_deactivate(PluginState* plugin_state); void totp_scene_add_new_token_deactivate(PluginState* plugin_state);

View File

@@ -7,11 +7,7 @@
#define DIGIT_TO_CHAR(digit) ((digit) + '0') #define DIGIT_TO_CHAR(digit) ((digit) + '0')
typedef enum { typedef enum { HoursInput, MinutesInput, ConfirmButton } Control;
HoursInput,
MinutesInput,
ConfirmButton
} Control;
typedef struct { typedef struct {
int8_t tz_offset_hours; int8_t tz_offset_hours;
@@ -24,10 +20,12 @@ void totp_scene_app_settings_init(PluginState* plugin_state) {
UNUSED(plugin_state); UNUSED(plugin_state);
} }
void totp_scene_app_settings_activate(PluginState* plugin_state, const AppSettingsSceneContext* context) { void totp_scene_app_settings_activate(
PluginState* plugin_state,
const AppSettingsSceneContext* context) {
SceneState* scene_state = malloc(sizeof(SceneState)); SceneState* scene_state = malloc(sizeof(SceneState));
plugin_state->current_scene_state = scene_state; plugin_state->current_scene_state = scene_state;
if (context != NULL) { if(context != NULL) {
scene_state->current_token_index = context->current_token_index; scene_state->current_token_index = context->current_token_index;
} else { } else {
scene_state->current_token_index = -1; scene_state->current_token_index = -1;
@@ -41,7 +39,7 @@ void totp_scene_app_settings_activate(PluginState* plugin_state, const AppSettin
static void two_digit_to_str(int8_t num, char* str) { static void two_digit_to_str(int8_t num, char* str) {
uint8_t index = 0; uint8_t index = 0;
if (num < 0) { if(num < 0) {
str[0] = '-'; str[0] = '-';
index++; index++;
num = -num; num = -num;
@@ -55,7 +53,7 @@ static void two_digit_to_str(int8_t num, char* str) {
} }
void totp_scene_app_settings_render(Canvas* const canvas, PluginState* plugin_state) { void totp_scene_app_settings_render(Canvas* const canvas, PluginState* plugin_state) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Timezone offset"); canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Timezone offset");
@@ -64,78 +62,102 @@ void totp_scene_app_settings_render(Canvas* const canvas, PluginState* plugin_st
char tmp_str[4]; char tmp_str[4];
two_digit_to_str(scene_state->tz_offset_hours, &tmp_str[0]); two_digit_to_str(scene_state->tz_offset_hours, &tmp_str[0]);
canvas_draw_str_aligned(canvas, 0, 16, AlignLeft, AlignTop, "Hours:"); canvas_draw_str_aligned(canvas, 0, 16, AlignLeft, AlignTop, "Hours:");
ui_control_select_render(canvas, 36, 10, SCREEN_WIDTH - 36, &tmp_str[0], scene_state->selected_control == HoursInput); ui_control_select_render(
canvas,
36,
10,
SCREEN_WIDTH - 36,
&tmp_str[0],
scene_state->selected_control == HoursInput);
two_digit_to_str(scene_state->tz_offset_minutes, &tmp_str[0]); two_digit_to_str(scene_state->tz_offset_minutes, &tmp_str[0]);
canvas_draw_str_aligned(canvas, 0, 34, AlignLeft, AlignTop, "Minutes:"); canvas_draw_str_aligned(canvas, 0, 34, AlignLeft, AlignTop, "Minutes:");
ui_control_select_render(canvas, 36, 28, SCREEN_WIDTH - 36, &tmp_str[0], scene_state->selected_control == MinutesInput); ui_control_select_render(
canvas,
36,
28,
SCREEN_WIDTH - 36,
&tmp_str[0],
scene_state->selected_control == MinutesInput);
ui_control_button_render(canvas, SCREEN_WIDTH_CENTER - 24, 50, 48, 13, "Confirm", scene_state->selected_control == ConfirmButton); ui_control_button_render(
canvas,
SCREEN_WIDTH_CENTER - 24,
50,
48,
13,
"Confirm",
scene_state->selected_control == ConfirmButton);
} }
bool totp_scene_app_settings_handle_event(PluginEvent* const event, PluginState* plugin_state) { bool totp_scene_app_settings_handle_event(PluginEvent* const event, PluginState* plugin_state) {
if (event->type == EventTypeKey) { if(event->type == EventTypeKey) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
if(event->input.type == InputTypePress) { if(event->input.type == InputTypePress) {
switch(event->input.key) { switch(event->input.key) {
case InputKeyUp: case InputKeyUp:
if (scene_state->selected_control > HoursInput) { if(scene_state->selected_control > HoursInput) {
scene_state->selected_control--; scene_state->selected_control--;
}
break;
case InputKeyDown:
if(scene_state->selected_control < ConfirmButton) {
scene_state->selected_control++;
}
break;
case InputKeyRight:
if(scene_state->selected_control == HoursInput) {
if(scene_state->tz_offset_hours < 12) {
scene_state->tz_offset_hours++;
} }
break; } else if(scene_state->selected_control == MinutesInput) {
case InputKeyDown: if(scene_state->tz_offset_minutes < 45) {
if (scene_state->selected_control < ConfirmButton) { scene_state->tz_offset_minutes += 15;
scene_state->selected_control++; } else {
scene_state->tz_offset_minutes = 0;
} }
break; }
case InputKeyRight: break;
if (scene_state->selected_control == HoursInput) { case InputKeyLeft:
if (scene_state->tz_offset_hours < 12) { if(scene_state->selected_control == HoursInput) {
scene_state->tz_offset_hours++; if(scene_state->tz_offset_hours > -12) {
} scene_state->tz_offset_hours--;
} else if (scene_state->selected_control == MinutesInput) {
if (scene_state->tz_offset_minutes < 45) {
scene_state->tz_offset_minutes += 15;
} else {
scene_state->tz_offset_minutes = 0;
}
} }
break; } else if(scene_state->selected_control == MinutesInput) {
case InputKeyLeft: if(scene_state->tz_offset_minutes >= 15) {
if (scene_state->selected_control == HoursInput) { scene_state->tz_offset_minutes -= 15;
if (scene_state->tz_offset_hours > -12) { } else {
scene_state->tz_offset_hours--; scene_state->tz_offset_minutes = 45;
}
} else if (scene_state->selected_control == MinutesInput) {
if (scene_state->tz_offset_minutes >= 15) {
scene_state->tz_offset_minutes -= 15;
} else {
scene_state->tz_offset_minutes = 45;
}
} }
break; }
case InputKeyOk: break;
if (scene_state->selected_control == ConfirmButton) { case InputKeyOk:
plugin_state->timezone_offset = (float)scene_state->tz_offset_hours + (float)scene_state->tz_offset_minutes / 60.0f; if(scene_state->selected_control == ConfirmButton) {
totp_config_file_update_timezone_offset(plugin_state->timezone_offset); plugin_state->timezone_offset = (float)scene_state->tz_offset_hours +
(float)scene_state->tz_offset_minutes / 60.0f;
totp_config_file_update_timezone_offset(plugin_state->timezone_offset);
if (scene_state->current_token_index >= 0) { if(scene_state->current_token_index >= 0) {
TokenMenuSceneContext generate_scene_context = { .current_token_index = scene_state->current_token_index }; TokenMenuSceneContext generate_scene_context = {
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, &generate_scene_context); .current_token_index = scene_state->current_token_index};
} else { totp_scene_director_activate_scene(
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL); plugin_state, TotpSceneTokenMenu, &generate_scene_context);
}
}
break;
case InputKeyBack: {
if (scene_state->current_token_index >= 0) {
TokenMenuSceneContext generate_scene_context = { .current_token_index = scene_state->current_token_index };
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, &generate_scene_context);
} else { } else {
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL);
} }
break;
} }
break;
case InputKeyBack: {
if(scene_state->current_token_index >= 0) {
TokenMenuSceneContext generate_scene_context = {
.current_token_index = scene_state->current_token_index};
totp_scene_director_activate_scene(
plugin_state, TotpSceneTokenMenu, &generate_scene_context);
} else {
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL);
}
break;
}
} }
} }
} }
@@ -143,8 +165,8 @@ bool totp_scene_app_settings_handle_event(PluginEvent* const event, PluginState*
} }
void totp_scene_app_settings_deactivate(PluginState* plugin_state) { void totp_scene_app_settings_deactivate(PluginState* plugin_state) {
if (plugin_state->current_scene_state == NULL) return; if(plugin_state->current_scene_state == NULL) return;
free(plugin_state->current_scene_state); free(plugin_state->current_scene_state);
plugin_state->current_scene_state = NULL; plugin_state->current_scene_state = NULL;
} }

View File

@@ -11,7 +11,9 @@ typedef struct {
} AppSettingsSceneContext; } AppSettingsSceneContext;
void totp_scene_app_settings_init(PluginState* plugin_state); void totp_scene_app_settings_init(PluginState* plugin_state);
void totp_scene_app_settings_activate(PluginState* plugin_state, const AppSettingsSceneContext* context); void totp_scene_app_settings_activate(
PluginState* plugin_state,
const AppSettingsSceneContext* context);
void totp_scene_app_settings_render(Canvas* const canvas, PluginState* plugin_state); void totp_scene_app_settings_render(Canvas* const canvas, PluginState* plugin_state);
bool totp_scene_app_settings_handle_event(PluginEvent* const event, PluginState* plugin_state); bool totp_scene_app_settings_handle_event(PluginEvent* const event, PluginState* plugin_state);
void totp_scene_app_settings_deactivate(PluginState* plugin_state); void totp_scene_app_settings_deactivate(PluginState* plugin_state);

View File

@@ -27,28 +27,46 @@ void totp_scene_authenticate_activate(PluginState* plugin_state) {
} }
void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) { void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
int v_shift = 0; int v_shift = 0;
if (scene_state->code_length > 0) { if(scene_state->code_length > 0) {
v_shift = -10; v_shift = -10;
} }
if (plugin_state->crypto_verify_data == NULL) { if(plugin_state->crypto_verify_data == NULL) {
canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER - 10 + v_shift, AlignCenter, AlignCenter, "Use arrow keys"); canvas_draw_str_aligned(
canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER + 5 + v_shift, AlignCenter, AlignCenter, "to setup new PIN"); canvas,
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER - 10 + v_shift,
AlignCenter,
AlignCenter,
"Use arrow keys");
canvas_draw_str_aligned(
canvas,
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER + 5 + v_shift,
AlignCenter,
AlignCenter,
"to setup new PIN");
} else { } else {
canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER + v_shift, AlignCenter, AlignCenter, "Use arrow keys to enter PIN"); canvas_draw_str_aligned(
canvas,
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER + v_shift,
AlignCenter,
AlignCenter,
"Use arrow keys to enter PIN");
} }
const uint8_t PIN_ASTERISK_RADIUS = 3; const uint8_t PIN_ASTERISK_RADIUS = 3;
const uint8_t PIN_ASTERISK_STEP = (PIN_ASTERISK_RADIUS << 1) + 2; const uint8_t PIN_ASTERISK_STEP = (PIN_ASTERISK_RADIUS << 1) + 2;
if (scene_state->code_length > 0) { if(scene_state->code_length > 0) {
uint8_t left_start_x = (scene_state->code_length - 1) * PIN_ASTERISK_STEP >> 1; uint8_t left_start_x = (scene_state->code_length - 1) * PIN_ASTERISK_STEP >> 1;
for (uint8_t i = 0; i < scene_state->code_length; i++) { for(uint8_t i = 0; i < scene_state->code_length; i++) {
canvas_draw_disc( canvas_draw_disc(
canvas, canvas,
SCREEN_WIDTH_CENTER - left_start_x + i * PIN_ASTERISK_STEP, SCREEN_WIDTH_CENTER - left_start_x + i * PIN_ASTERISK_STEP,
SCREEN_HEIGHT_CENTER + 10, SCREEN_HEIGHT_CENTER + 10,
PIN_ASTERISK_RADIUS); PIN_ASTERISK_RADIUS);
} }
} }
@@ -56,10 +74,10 @@ void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_st
bool totp_scene_authenticate_handle_event(PluginEvent* const event, PluginState* plugin_state) { bool totp_scene_authenticate_handle_event(PluginEvent* const event, PluginState* plugin_state) {
if(event->type == EventTypeKey) { if(event->type == EventTypeKey) {
if (event->input.type == InputTypeLong && event->input.key == InputKeyBack) { if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) {
return false; return false;
} else if(event->input.type == InputTypePress) { } else if(event->input.type == InputTypePress) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
const uint8_t ARROW_UP_CODE = 2; const uint8_t ARROW_UP_CODE = 2;
const uint8_t ARROW_RIGHT_CODE = 8; const uint8_t ARROW_RIGHT_CODE = 8;
@@ -67,56 +85,63 @@ bool totp_scene_authenticate_handle_event(PluginEvent* const event, PluginState*
const uint8_t ARROW_LEFT_CODE = 5; const uint8_t ARROW_LEFT_CODE = 5;
switch(event->input.key) { switch(event->input.key) {
case InputKeyUp: case InputKeyUp:
if (scene_state->code_length < MAX_CODE_LENGTH) { if(scene_state->code_length < MAX_CODE_LENGTH) {
scene_state->code_input[scene_state->code_length] = ARROW_UP_CODE; scene_state->code_input[scene_state->code_length] = ARROW_UP_CODE;
scene_state->code_length++; scene_state->code_length++;
} }
break; break;
case InputKeyDown: case InputKeyDown:
if (scene_state->code_length < MAX_CODE_LENGTH) { if(scene_state->code_length < MAX_CODE_LENGTH) {
scene_state->code_input[scene_state->code_length] = ARROW_DOWN_CODE; scene_state->code_input[scene_state->code_length] = ARROW_DOWN_CODE;
scene_state->code_length++; scene_state->code_length++;
} }
break; break;
case InputKeyRight: case InputKeyRight:
if (scene_state->code_length < MAX_CODE_LENGTH) { if(scene_state->code_length < MAX_CODE_LENGTH) {
scene_state->code_input[scene_state->code_length] = ARROW_RIGHT_CODE; scene_state->code_input[scene_state->code_length] = ARROW_RIGHT_CODE;
scene_state->code_length++; scene_state->code_length++;
} }
break; break;
case InputKeyLeft: case InputKeyLeft:
if (scene_state->code_length < MAX_CODE_LENGTH) { if(scene_state->code_length < MAX_CODE_LENGTH) {
scene_state->code_input[scene_state->code_length] = ARROW_LEFT_CODE; scene_state->code_input[scene_state->code_length] = ARROW_LEFT_CODE;
scene_state->code_length++; scene_state->code_length++;
} }
break; break;
case InputKeyOk: case InputKeyOk:
totp_crypto_seed_iv(plugin_state, &scene_state->code_input[0], scene_state->code_length); totp_crypto_seed_iv(
plugin_state, &scene_state->code_input[0], scene_state->code_length);
if (totp_crypto_verify_key(plugin_state)) { if(totp_crypto_verify_key(plugin_state)) {
FURI_LOG_D(LOGGING_TAG, "PIN is valid"); FURI_LOG_D(LOGGING_TAG, "PIN is valid");
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
} else { } else {
FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid"); FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid");
memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH); memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE); memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
scene_state->code_length = 0; scene_state->code_length = 0;
DialogMessage* message = dialog_message_alloc(); DialogMessage* message = dialog_message_alloc();
dialog_message_set_buttons(message, "Try again", NULL, NULL); dialog_message_set_buttons(message, "Try again", NULL, NULL);
dialog_message_set_header(message, "You entered\ninvalid PIN", SCREEN_WIDTH_CENTER - 25, SCREEN_HEIGHT_CENTER - 5, AlignCenter, AlignCenter); dialog_message_set_header(
dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17); message,
dialog_message_show(plugin_state->dialogs, message); "You entered\ninvalid PIN",
dialog_message_free(message); SCREEN_WIDTH_CENTER - 25,
} SCREEN_HEIGHT_CENTER - 5,
break; AlignCenter,
case InputKeyBack: AlignCenter);
if (scene_state->code_length > 0) { dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17);
scene_state->code_input[scene_state->code_length - 1] = 0; dialog_message_show(plugin_state->dialogs, message);
scene_state->code_length--; dialog_message_free(message);
} }
break; break;
case InputKeyBack:
if(scene_state->code_length > 0) {
scene_state->code_input[scene_state->code_length - 1] = 0;
scene_state->code_length--;
}
break;
} }
} }
} }
@@ -125,7 +150,7 @@ bool totp_scene_authenticate_handle_event(PluginEvent* const event, PluginState*
} }
void totp_scene_authenticate_deactivate(PluginState* plugin_state) { void totp_scene_authenticate_deactivate(PluginState* plugin_state) {
if (plugin_state->current_scene_state == NULL) return; if(plugin_state->current_scene_state == NULL) return;
free(plugin_state->current_scene_state); free(plugin_state->current_scene_state);
plugin_state->current_scene_state = NULL; plugin_state->current_scene_state = NULL;
} }

View File

@@ -35,14 +35,14 @@ static const NotificationSequence sequence_short_vibro_and_sound = {
}; };
static void i_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) { static void i_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) {
if (len == TOTP_8_DIGITS) { if(len == TOTP_8_DIGITS) {
str[8] = '\0'; str[8] = '\0';
} else if (len == TOTP_6_DIGITS) { } else if(len == TOTP_6_DIGITS) {
str[6] = '\0'; str[6] = '\0';
} }
if (i_token_code == 0) { if(i_token_code == 0) {
if (len > TOTP_6_DIGITS) { if(len > TOTP_6_DIGITS) {
str[7] = '-'; str[7] = '-';
str[6] = '-'; str[6] = '-';
} }
@@ -54,14 +54,14 @@ static void i_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount le
str[1] = '-'; str[1] = '-';
str[0] = '-'; str[0] = '-';
} else { } else {
if (len == TOTP_8_DIGITS) { if(len == TOTP_8_DIGITS) {
str[7] = DIGIT_TO_CHAR(i_token_code % 10); str[7] = DIGIT_TO_CHAR(i_token_code % 10);
str[6] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10); str[6] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
str[5] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10); str[5] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
} else if (len == TOTP_6_DIGITS) { } else if(len == TOTP_6_DIGITS) {
str[5] = DIGIT_TO_CHAR(i_token_code % 10); str[5] = DIGIT_TO_CHAR(i_token_code % 10);
} }
str[4] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10); str[4] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
str[3] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10); str[3] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
str[2] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10); str[2] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
@@ -71,20 +71,26 @@ static void i_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount le
} }
TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) { TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
switch (algo) { switch(algo) {
case SHA1: return TOTP_ALGO_SHA1; case SHA1:
case SHA256: return TOTP_ALGO_SHA256; return TOTP_ALGO_SHA1;
case SHA512: return TOTP_ALGO_SHA512; case SHA256:
return TOTP_ALGO_SHA256;
case SHA512:
return TOTP_ALGO_SHA512;
} }
return NULL; return NULL;
} }
void update_totp_params(PluginState* const plugin_state) { void update_totp_params(PluginState* const plugin_state) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
if (scene_state->current_token_index < plugin_state->tokens_count) { if(scene_state->current_token_index < plugin_state->tokens_count) {
TokenInfo* tokenInfo = (TokenInfo *)(list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data); TokenInfo* tokenInfo =
(TokenInfo*)(list_element_at(
plugin_state->tokens_list, scene_state->current_token_index)
->data);
scene_state->need_token_update = true; scene_state->need_token_update = true;
scene_state->last_code_name = tokenInfo->name; scene_state->last_code_name = tokenInfo->name;
@@ -95,12 +101,14 @@ void totp_scene_generate_token_init(PluginState* plugin_state) {
UNUSED(plugin_state); UNUSED(plugin_state);
} }
void totp_scene_generate_token_activate(PluginState* plugin_state, const GenerateTokenSceneContext* context) { void totp_scene_generate_token_activate(
if (!plugin_state->token_list_loaded) { PluginState* plugin_state,
const GenerateTokenSceneContext* context) {
if(!plugin_state->token_list_loaded) {
totp_config_file_load_tokens(plugin_state); totp_config_file_load_tokens(plugin_state);
} }
SceneState* scene_state = malloc(sizeof(SceneState)); SceneState* scene_state = malloc(sizeof(SceneState));
if (context == NULL) { if(context == NULL) {
scene_state->current_token_index = 0; scene_state->current_token_index = 0;
} else { } else {
scene_state->current_token_index = context->current_token_index; scene_state->current_token_index = context->current_token_index;
@@ -112,46 +120,84 @@ void totp_scene_generate_token_activate(PluginState* plugin_state, const Generat
} }
void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) { void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) {
if (plugin_state->tokens_count == 0) { if(plugin_state->tokens_count == 0) {
canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER - 10, AlignCenter, AlignCenter, "Token list is empty"); canvas_draw_str_aligned(
canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER + 10, AlignCenter, AlignCenter, "Press OK button to add"); canvas,
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER - 10,
AlignCenter,
AlignCenter,
"Token list is empty");
canvas_draw_str_aligned(
canvas,
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER + 10,
AlignCenter,
AlignCenter,
"Press OK button to add");
return; return;
} }
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
FuriHalRtcDateTime curr_dt; FuriHalRtcDateTime curr_dt;
furi_hal_rtc_get_datetime(&curr_dt); furi_hal_rtc_get_datetime(&curr_dt);
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt); uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
bool is_new_token_time = curr_ts % TOKEN_LIFETIME == 0; bool is_new_token_time = curr_ts % TOKEN_LIFETIME == 0;
if (is_new_token_time && scene_state->last_token_gen_time != curr_ts) { if(is_new_token_time && scene_state->last_token_gen_time != curr_ts) {
scene_state->need_token_update = true; scene_state->need_token_update = true;
} }
if (scene_state->need_token_update) { if(scene_state->need_token_update) {
scene_state->need_token_update = false; scene_state->need_token_update = false;
scene_state->last_token_gen_time = curr_ts; scene_state->last_token_gen_time = curr_ts;
TokenInfo* tokenInfo = (TokenInfo*)(list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data); TokenInfo* tokenInfo =
(TokenInfo*)(list_element_at(
plugin_state->tokens_list, scene_state->current_token_index)
->data);
uint8_t key_length; uint8_t key_length;
uint8_t* key = totp_crypto_decrypt(tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length); uint8_t* key = totp_crypto_decrypt(
tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length);
i_token_to_str(totp_at(get_totp_algo_impl(tokenInfo->algo), token_info_get_digits_count(tokenInfo), key, key_length, curr_ts, plugin_state->timezone_offset, TOKEN_LIFETIME), scene_state->last_code, tokenInfo->digits); i_token_to_str(
totp_at(
get_totp_algo_impl(tokenInfo->algo),
token_info_get_digits_count(tokenInfo),
key,
key_length,
curr_ts,
plugin_state->timezone_offset,
TOKEN_LIFETIME),
scene_state->last_code,
tokenInfo->digits);
memset(key, 0, key_length); memset(key, 0, key_length);
free(key); free(key);
if (is_new_token_time) { if(is_new_token_time) {
notification_message(plugin_state->notification, &sequence_short_vibro_and_sound); notification_message(plugin_state->notification, &sequence_short_vibro_and_sound);
} }
} }
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
uint16_t token_name_width = canvas_string_width(canvas, scene_state->last_code_name); uint16_t token_name_width = canvas_string_width(canvas, scene_state->last_code_name);
if (SCREEN_WIDTH - token_name_width > 18) { if(SCREEN_WIDTH - token_name_width > 18) {
canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER - 20, AlignCenter, AlignCenter, scene_state->last_code_name); canvas_draw_str_aligned(
canvas,
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER - 20,
AlignCenter,
AlignCenter,
scene_state->last_code_name);
} else { } else {
canvas_draw_str_aligned(canvas, 9, SCREEN_HEIGHT_CENTER - 20, AlignLeft, AlignCenter, scene_state->last_code_name); canvas_draw_str_aligned(
canvas,
9,
SCREEN_HEIGHT_CENTER - 20,
AlignLeft,
AlignCenter,
scene_state->last_code_name);
canvas_set_color(canvas, ColorWhite); canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 0, SCREEN_HEIGHT_CENTER - 24, 9, 9); canvas_draw_box(canvas, 0, SCREEN_HEIGHT_CENTER - 24, 9, 9);
canvas_draw_box(canvas, SCREEN_WIDTH - 10, SCREEN_HEIGHT_CENTER - 24, 9, 9); canvas_draw_box(canvas, SCREEN_WIDTH - 10, SCREEN_HEIGHT_CENTER - 24, 9, 9);
@@ -159,7 +205,13 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
} }
canvas_set_font(canvas, FontBigNumbers); canvas_set_font(canvas, FontBigNumbers);
canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter, scene_state->last_code); canvas_draw_str_aligned(
canvas,
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER,
AlignCenter,
AlignCenter,
scene_state->last_code);
const uint8_t BAR_MARGIN = 3; const uint8_t BAR_MARGIN = 3;
const uint8_t BAR_HEIGHT = 4; const uint8_t BAR_HEIGHT = 4;
@@ -167,56 +219,64 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
uint8_t barWidth = (uint8_t)((float)(SCREEN_WIDTH - (BAR_MARGIN << 1)) * percentDone); uint8_t barWidth = (uint8_t)((float)(SCREEN_WIDTH - (BAR_MARGIN << 1)) * percentDone);
uint8_t barX = ((SCREEN_WIDTH - (BAR_MARGIN << 1) - barWidth) >> 1) + BAR_MARGIN; uint8_t barX = ((SCREEN_WIDTH - (BAR_MARGIN << 1) - barWidth) >> 1) + BAR_MARGIN;
canvas_draw_box( canvas_draw_box(canvas, barX, SCREEN_HEIGHT - BAR_MARGIN - BAR_HEIGHT, barWidth, BAR_HEIGHT);
canvas,
barX,
SCREEN_HEIGHT - BAR_MARGIN - BAR_HEIGHT,
barWidth,
BAR_HEIGHT);
if (plugin_state->tokens_count > 1) { if(plugin_state->tokens_count > 1) {
canvas_draw_xbm(canvas, 0, SCREEN_HEIGHT_CENTER - 24, ICON_ARROW_LEFT_8x9_WIDTH, ICON_ARROW_LEFT_8x9_HEIGHT, &ICON_ARROW_LEFT_8x9[0]); canvas_draw_xbm(
canvas_draw_xbm(canvas, SCREEN_WIDTH - 9, SCREEN_HEIGHT_CENTER - 24, ICON_ARROW_RIGHT_8x9_WIDTH, ICON_ARROW_RIGHT_8x9_HEIGHT, &ICON_ARROW_RIGHT_8x9[0]); canvas,
0,
SCREEN_HEIGHT_CENTER - 24,
ICON_ARROW_LEFT_8x9_WIDTH,
ICON_ARROW_LEFT_8x9_HEIGHT,
&ICON_ARROW_LEFT_8x9[0]);
canvas_draw_xbm(
canvas,
SCREEN_WIDTH - 9,
SCREEN_HEIGHT_CENTER - 24,
ICON_ARROW_RIGHT_8x9_WIDTH,
ICON_ARROW_RIGHT_8x9_HEIGHT,
&ICON_ARROW_RIGHT_8x9[0]);
} }
} }
bool totp_scene_generate_token_handle_event(PluginEvent* const event, PluginState* plugin_state) { bool totp_scene_generate_token_handle_event(PluginEvent* const event, PluginState* plugin_state) {
if(event->type == EventTypeKey) { if(event->type == EventTypeKey) {
if (event->input.type == InputTypeLong && event->input.key == InputKeyBack) { if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) {
return false; return false;
} else if(event->input.type == InputTypePress) { } else if(event->input.type == InputTypePress) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
switch(event->input.key) { switch(event->input.key) {
case InputKeyUp: case InputKeyUp:
break; break;
case InputKeyDown: case InputKeyDown:
break; break;
case InputKeyRight: case InputKeyRight:
if (scene_state->current_token_index < plugin_state->tokens_count - 1) { if(scene_state->current_token_index < plugin_state->tokens_count - 1) {
scene_state->current_token_index++; scene_state->current_token_index++;
} else { } else {
scene_state->current_token_index = 0; scene_state->current_token_index = 0;
} }
update_totp_params(plugin_state); update_totp_params(plugin_state);
break; break;
case InputKeyLeft: case InputKeyLeft:
if (scene_state->current_token_index > 0) { if(scene_state->current_token_index > 0) {
scene_state->current_token_index--; scene_state->current_token_index--;
} else { } else {
scene_state->current_token_index = plugin_state->tokens_count - 1; scene_state->current_token_index = plugin_state->tokens_count - 1;
} }
update_totp_params(plugin_state); update_totp_params(plugin_state);
break; break;
case InputKeyOk: case InputKeyOk:
if (plugin_state->tokens_count == 0) { if(plugin_state->tokens_count == 0) {
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, NULL);
} else { } else {
TokenMenuSceneContext ctx = { .current_token_index = scene_state->current_token_index }; TokenMenuSceneContext ctx = {
totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, &ctx); .current_token_index = scene_state->current_token_index};
} totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu, &ctx);
break; }
case InputKeyBack: break;
break; case InputKeyBack:
break;
} }
} }
} }
@@ -225,8 +285,8 @@ bool totp_scene_generate_token_handle_event(PluginEvent* const event, PluginStat
} }
void totp_scene_generate_token_deactivate(PluginState* plugin_state) { void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
if (plugin_state->current_scene_state == NULL) return; if(plugin_state->current_scene_state == NULL) return;
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
free(scene_state->last_code); free(scene_state->last_code);
free(scene_state); free(scene_state);

View File

@@ -11,7 +11,9 @@ typedef struct {
} GenerateTokenSceneContext; } GenerateTokenSceneContext;
void totp_scene_generate_token_init(PluginState* plugin_state); void totp_scene_generate_token_init(PluginState* plugin_state);
void totp_scene_generate_token_activate(PluginState* plugin_state, const GenerateTokenSceneContext* context); void totp_scene_generate_token_activate(
PluginState* plugin_state,
const GenerateTokenSceneContext* context);
void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state); void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state);
bool totp_scene_generate_token_handle_event(PluginEvent* const event, PluginState* plugin_state); bool totp_scene_generate_token_handle_event(PluginEvent* const event, PluginState* plugin_state);
void totp_scene_generate_token_deactivate(PluginState* plugin_state); void totp_scene_generate_token_deactivate(PluginState* plugin_state);

View File

@@ -6,25 +6,28 @@
#include "token_menu/totp_scene_token_menu.h" #include "token_menu/totp_scene_token_menu.h"
#include "app_settings/totp_app_settings.h" #include "app_settings/totp_app_settings.h"
void totp_scene_director_activate_scene(PluginState* const plugin_state, Scene scene, const void* context) { void totp_scene_director_activate_scene(
PluginState* const plugin_state,
Scene scene,
const void* context) {
plugin_state->changing_scene = true; plugin_state->changing_scene = true;
totp_scene_director_deactivate_active_scene(plugin_state); totp_scene_director_deactivate_active_scene(plugin_state);
switch (scene) { switch(scene) {
case TotpSceneGenerateToken: case TotpSceneGenerateToken:
totp_scene_generate_token_activate(plugin_state, context); totp_scene_generate_token_activate(plugin_state, context);
break; break;
case TotpSceneAuthentication: case TotpSceneAuthentication:
totp_scene_authenticate_activate(plugin_state); totp_scene_authenticate_activate(plugin_state);
break; break;
case TotpSceneAddNewToken: case TotpSceneAddNewToken:
totp_scene_add_new_token_activate(plugin_state, context); totp_scene_add_new_token_activate(plugin_state, context);
break; break;
case TotpSceneTokenMenu: case TotpSceneTokenMenu:
totp_scene_token_menu_activate(plugin_state, context); totp_scene_token_menu_activate(plugin_state, context);
break; break;
case TotpSceneAppSettings: case TotpSceneAppSettings:
totp_scene_app_settings_activate(plugin_state, context); totp_scene_app_settings_activate(plugin_state, context);
break; break;
} }
plugin_state->current_scene = scene; plugin_state->current_scene = scene;
@@ -32,22 +35,22 @@ void totp_scene_director_activate_scene(PluginState* const plugin_state, Scene s
} }
void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state) { void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state) {
switch (plugin_state->current_scene) { switch(plugin_state->current_scene) {
case TotpSceneGenerateToken: case TotpSceneGenerateToken:
totp_scene_generate_token_deactivate(plugin_state); totp_scene_generate_token_deactivate(plugin_state);
break; break;
case TotpSceneAuthentication: case TotpSceneAuthentication:
totp_scene_authenticate_deactivate(plugin_state); totp_scene_authenticate_deactivate(plugin_state);
break; break;
case TotpSceneAddNewToken: case TotpSceneAddNewToken:
totp_scene_add_new_token_deactivate(plugin_state); totp_scene_add_new_token_deactivate(plugin_state);
break; break;
case TotpSceneTokenMenu: case TotpSceneTokenMenu:
totp_scene_token_menu_deactivate(plugin_state); totp_scene_token_menu_deactivate(plugin_state);
break; break;
case TotpSceneAppSettings: case TotpSceneAppSettings:
totp_scene_app_settings_deactivate(plugin_state); totp_scene_app_settings_deactivate(plugin_state);
break; break;
} }
} }
@@ -60,22 +63,22 @@ void totp_scene_director_init_scenes(PluginState* const plugin_state) {
} }
void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_state) { void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_state) {
switch (plugin_state->current_scene) { switch(plugin_state->current_scene) {
case TotpSceneGenerateToken: case TotpSceneGenerateToken:
totp_scene_generate_token_render(canvas, plugin_state); totp_scene_generate_token_render(canvas, plugin_state);
break; break;
case TotpSceneAuthentication: case TotpSceneAuthentication:
totp_scene_authenticate_render(canvas, plugin_state); totp_scene_authenticate_render(canvas, plugin_state);
break; break;
case TotpSceneAddNewToken: case TotpSceneAddNewToken:
totp_scene_add_new_token_render(canvas, plugin_state); totp_scene_add_new_token_render(canvas, plugin_state);
break; break;
case TotpSceneTokenMenu: case TotpSceneTokenMenu:
totp_scene_token_menu_render(canvas, plugin_state); totp_scene_token_menu_render(canvas, plugin_state);
break; break;
case TotpSceneAppSettings: case TotpSceneAppSettings:
totp_scene_app_settings_render(canvas, plugin_state); totp_scene_app_settings_render(canvas, plugin_state);
break; break;
} }
} }
@@ -89,22 +92,22 @@ void totp_scene_director_dispose(PluginState* const plugin_state) {
bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* const plugin_state) { bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* const plugin_state) {
bool processing = true; bool processing = true;
switch (plugin_state->current_scene) { switch(plugin_state->current_scene) {
case TotpSceneGenerateToken: case TotpSceneGenerateToken:
processing = totp_scene_generate_token_handle_event(event, plugin_state); processing = totp_scene_generate_token_handle_event(event, plugin_state);
break; break;
case TotpSceneAuthentication: case TotpSceneAuthentication:
processing = totp_scene_authenticate_handle_event(event, plugin_state); processing = totp_scene_authenticate_handle_event(event, plugin_state);
break; break;
case TotpSceneAddNewToken: case TotpSceneAddNewToken:
processing = totp_scene_add_new_token_handle_event(event, plugin_state); processing = totp_scene_add_new_token_handle_event(event, plugin_state);
break; break;
case TotpSceneTokenMenu: case TotpSceneTokenMenu:
processing = totp_scene_token_menu_handle_event(event, plugin_state); processing = totp_scene_token_menu_handle_event(event, plugin_state);
break; break;
case TotpSceneAppSettings: case TotpSceneAppSettings:
processing = totp_scene_app_settings_handle_event(event, plugin_state); processing = totp_scene_app_settings_handle_event(event, plugin_state);
break; break;
} }
return processing; return processing;

View File

@@ -5,7 +5,10 @@
#include "../types/plugin_event.h" #include "../types/plugin_event.h"
#include "totp_scenes_enum.h" #include "totp_scenes_enum.h"
void totp_scene_director_activate_scene(PluginState* const plugin_state, Scene scene, const void* context); void totp_scene_director_activate_scene(
PluginState* const plugin_state,
Scene scene,
const void* context);
void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state); void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state);
void totp_scene_director_init_scenes(PluginState* const plugin_state); void totp_scene_director_init_scenes(PluginState* const plugin_state);
void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_state); void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_state);

View File

@@ -14,11 +14,7 @@
#define SCREEN_HEIGHT_THIRD (SCREEN_HEIGHT / 3) #define SCREEN_HEIGHT_THIRD (SCREEN_HEIGHT / 3)
#define SCREEN_HEIGHT_THIRD_CENTER (SCREEN_HEIGHT_THIRD >> 1) #define SCREEN_HEIGHT_THIRD_CENTER (SCREEN_HEIGHT_THIRD >> 1)
typedef enum { typedef enum { AddNewToken, DeleteToken, AppSettings } Control;
AddNewToken,
DeleteToken,
AppSettings
} Control;
typedef struct { typedef struct {
Control selected_control; Control selected_control;
@@ -29,10 +25,12 @@ void totp_scene_token_menu_init(PluginState* plugin_state) {
UNUSED(plugin_state); UNUSED(plugin_state);
} }
void totp_scene_token_menu_activate(PluginState* plugin_state, const TokenMenuSceneContext* context) { void totp_scene_token_menu_activate(
PluginState* plugin_state,
const TokenMenuSceneContext* context) {
SceneState* scene_state = malloc(sizeof(SceneState)); SceneState* scene_state = malloc(sizeof(SceneState));
plugin_state->current_scene_state = scene_state; plugin_state->current_scene_state = scene_state;
if (context != NULL) { if(context != NULL) {
scene_state->current_token_index = context->current_token_index; scene_state->current_token_index = context->current_token_index;
} else { } else {
scene_state->current_token_index = -1; scene_state->current_token_index = -1;
@@ -40,99 +38,152 @@ void totp_scene_token_menu_activate(PluginState* plugin_state, const TokenMenuSc
} }
void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_state) { void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_state) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
if (scene_state->current_token_index < 0) { if(scene_state->current_token_index < 0) {
ui_control_button_render(canvas, SCREEN_WIDTH_CENTER - 36, 5, 72, 21, "Add new token", scene_state->selected_control == AddNewToken); ui_control_button_render(
ui_control_button_render(canvas, SCREEN_WIDTH_CENTER - 36, 39, 72, 21, "Settings", scene_state->selected_control == AppSettings); canvas,
SCREEN_WIDTH_CENTER - 36,
5,
72,
21,
"Add new token",
scene_state->selected_control == AddNewToken);
ui_control_button_render(
canvas,
SCREEN_WIDTH_CENTER - 36,
39,
72,
21,
"Settings",
scene_state->selected_control == AppSettings);
} else { } else {
ui_control_button_render(canvas, SCREEN_WIDTH_CENTER - 36, SCREEN_HEIGHT_THIRD_CENTER - 8, 72, 16, "Add new token", scene_state->selected_control == AddNewToken); ui_control_button_render(
ui_control_button_render(canvas, SCREEN_WIDTH_CENTER - 36, SCREEN_HEIGHT_THIRD + SCREEN_HEIGHT_THIRD_CENTER - 8, 72, 16, "Delete token", scene_state->selected_control == DeleteToken); canvas,
ui_control_button_render(canvas, SCREEN_WIDTH_CENTER - 36, SCREEN_HEIGHT_THIRD + SCREEN_HEIGHT_THIRD + SCREEN_HEIGHT_THIRD_CENTER - 8, 72, 16, "Settings", scene_state->selected_control == AppSettings); SCREEN_WIDTH_CENTER - 36,
SCREEN_HEIGHT_THIRD_CENTER - 8,
72,
16,
"Add new token",
scene_state->selected_control == AddNewToken);
ui_control_button_render(
canvas,
SCREEN_WIDTH_CENTER - 36,
SCREEN_HEIGHT_THIRD + SCREEN_HEIGHT_THIRD_CENTER - 8,
72,
16,
"Delete token",
scene_state->selected_control == DeleteToken);
ui_control_button_render(
canvas,
SCREEN_WIDTH_CENTER - 36,
SCREEN_HEIGHT_THIRD + SCREEN_HEIGHT_THIRD + SCREEN_HEIGHT_THIRD_CENTER - 8,
72,
16,
"Settings",
scene_state->selected_control == AppSettings);
} }
} }
bool totp_scene_token_menu_handle_event(PluginEvent* const event, PluginState* plugin_state) { bool totp_scene_token_menu_handle_event(PluginEvent* const event, PluginState* plugin_state) {
if (event->type == EventTypeKey) { if(event->type == EventTypeKey) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
if(event->input.type == InputTypePress) { if(event->input.type == InputTypePress) {
switch(event->input.key) { switch(event->input.key) {
case InputKeyUp: case InputKeyUp:
if (scene_state->selected_control > AddNewToken) { if(scene_state->selected_control > AddNewToken) {
scene_state->selected_control--;
if(scene_state->selected_control == DeleteToken &&
scene_state->current_token_index < 0) {
scene_state->selected_control--; scene_state->selected_control--;
if (scene_state->selected_control == DeleteToken && scene_state->current_token_index < 0) {
scene_state->selected_control--;
}
} else {
scene_state->selected_control = AppSettings;
} }
break; } else {
case InputKeyDown: scene_state->selected_control = AppSettings;
if (scene_state->selected_control < AppSettings) { }
break;
case InputKeyDown:
if(scene_state->selected_control < AppSettings) {
scene_state->selected_control++;
if(scene_state->selected_control == DeleteToken &&
scene_state->current_token_index < 0) {
scene_state->selected_control++; scene_state->selected_control++;
if (scene_state->selected_control == DeleteToken && scene_state->current_token_index < 0) {
scene_state->selected_control++;
}
} else {
scene_state->selected_control = AddNewToken;
} }
} else {
scene_state->selected_control = AddNewToken;
}
break;
case InputKeyRight:
break;
case InputKeyLeft:
break;
case InputKeyOk:
switch(scene_state->selected_control) {
case AddNewToken: {
TokenAddEditSceneContext add_new_token_scene_context = {
.current_token_index = scene_state->current_token_index};
totp_scene_director_activate_scene(
plugin_state, TotpSceneAddNewToken, &add_new_token_scene_context);
break; break;
case InputKeyRight: }
break; case DeleteToken: {
case InputKeyLeft: DialogMessage* message = dialog_message_alloc();
break; dialog_message_set_buttons(message, "No", NULL, "Yes");
case InputKeyOk: dialog_message_set_header(message, "Confirmation", 0, 0, AlignLeft, AlignTop);
switch (scene_state->selected_control) { dialog_message_set_text(
case AddNewToken: { message,
TokenAddEditSceneContext add_new_token_scene_context = { .current_token_index = scene_state->current_token_index }; "Are you sure want to delete?",
totp_scene_director_activate_scene(plugin_state, TotpSceneAddNewToken, &add_new_token_scene_context); SCREEN_WIDTH_CENTER,
break; SCREEN_HEIGHT_CENTER,
} AlignCenter,
case DeleteToken: { AlignCenter);
DialogMessage* message = dialog_message_alloc(); DialogMessageButton dialog_result =
dialog_message_set_buttons(message, "No", NULL, "Yes"); dialog_message_show(plugin_state->dialogs, message);
dialog_message_set_header(message, "Confirmation", 0, 0, AlignLeft, AlignTop); dialog_message_free(message);
dialog_message_set_text(message, "Are you sure want to delete?", SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter); if(dialog_result == DialogMessageButtonRight) {
DialogMessageButton dialog_result = dialog_message_show(plugin_state->dialogs, message); uint8_t i = 0;
dialog_message_free(message);
if (dialog_result == DialogMessageButtonRight) {
uint8_t i = 0;
ListNode* list_node = plugin_state->tokens_list; ListNode* list_node = plugin_state->tokens_list;
while (i < scene_state->current_token_index && list_node->next != NULL) { while(i < scene_state->current_token_index && list_node->next != NULL) {
list_node = list_node->next; list_node = list_node->next;
i++; i++;
}
TokenInfo* tokenInfo = list_node->data;
token_info_free(tokenInfo);
plugin_state->tokens_list = list_remove(plugin_state->tokens_list, list_node);
plugin_state->tokens_count--;
totp_full_save_config_file(plugin_state);
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
}
break;
} }
case AppSettings: {
if (scene_state->current_token_index >= 0) { TokenInfo* tokenInfo = list_node->data;
AppSettingsSceneContext app_settings_context = { .current_token_index = scene_state->current_token_index }; token_info_free(tokenInfo);
totp_scene_director_activate_scene(plugin_state, TotpSceneAppSettings, &app_settings_context); plugin_state->tokens_list =
} else { list_remove(plugin_state->tokens_list, list_node);
totp_scene_director_activate_scene(plugin_state, TotpSceneAppSettings, NULL); plugin_state->tokens_count--;
}
break; totp_full_save_config_file(plugin_state);
} totp_scene_director_activate_scene(
} plugin_state, TotpSceneGenerateToken, NULL);
break;
case InputKeyBack: {
if (scene_state->current_token_index >= 0) {
GenerateTokenSceneContext generate_scene_context = { .current_token_index = scene_state->current_token_index };
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, &generate_scene_context);
} else {
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
} }
break; break;
} }
case AppSettings: {
if(scene_state->current_token_index >= 0) {
AppSettingsSceneContext app_settings_context = {
.current_token_index = scene_state->current_token_index};
totp_scene_director_activate_scene(
plugin_state, TotpSceneAppSettings, &app_settings_context);
} else {
totp_scene_director_activate_scene(
plugin_state, TotpSceneAppSettings, NULL);
}
break;
}
}
break;
case InputKeyBack: {
if(scene_state->current_token_index >= 0) {
GenerateTokenSceneContext generate_scene_context = {
.current_token_index = scene_state->current_token_index};
totp_scene_director_activate_scene(
plugin_state, TotpSceneGenerateToken, &generate_scene_context);
} else {
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
}
break;
}
} }
} }
} }
@@ -140,8 +191,8 @@ bool totp_scene_token_menu_handle_event(PluginEvent* const event, PluginState* p
} }
void totp_scene_token_menu_deactivate(PluginState* plugin_state) { void totp_scene_token_menu_deactivate(PluginState* plugin_state) {
if (plugin_state->current_scene_state == NULL) return; if(plugin_state->current_scene_state == NULL) return;
free(plugin_state->current_scene_state); free(plugin_state->current_scene_state);
plugin_state->current_scene_state = NULL; plugin_state->current_scene_state = NULL;
} }

View File

@@ -11,7 +11,9 @@ typedef struct {
} TokenMenuSceneContext; } TokenMenuSceneContext;
void totp_scene_token_menu_init(PluginState* plugin_state); void totp_scene_token_menu_init(PluginState* plugin_state);
void totp_scene_token_menu_activate(PluginState* plugin_state, const TokenMenuSceneContext* context); void totp_scene_token_menu_activate(
PluginState* plugin_state,
const TokenMenuSceneContext* context);
void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_state); void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_state);
bool totp_scene_token_menu_handle_event(PluginEvent* const event, PluginState* plugin_state); bool totp_scene_token_menu_handle_event(PluginEvent* const event, PluginState* plugin_state);
void totp_scene_token_menu_deactivate(PluginState* plugin_state); void totp_scene_token_menu_deactivate(PluginState* plugin_state);

View File

@@ -19,77 +19,76 @@
#include "base32.h" #include "base32.h"
int base32_decode(const uint8_t *encoded, uint8_t *result, int bufSize) { int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize) {
int buffer = 0; int buffer = 0;
int bitsLeft = 0; int bitsLeft = 0;
int count = 0; int count = 0;
for (const uint8_t *ptr = encoded; count < bufSize && *ptr; ++ptr) { for(const uint8_t* ptr = encoded; count < bufSize && *ptr; ++ptr) {
uint8_t ch = *ptr; uint8_t ch = *ptr;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-') { if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-') {
continue; continue;
} }
buffer <<= 5; buffer <<= 5;
// Deal with commonly mistyped characters // Deal with commonly mistyped characters
if (ch == '0') { if(ch == '0') {
ch = 'O'; ch = 'O';
} else if (ch == '1') { } else if(ch == '1') {
ch = 'L'; ch = 'L';
} else if (ch == '8') { } else if(ch == '8') {
ch = 'B'; ch = 'B';
} }
// Look up one base32 digit // Look up one base32 digit
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { if((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
ch = (ch & 0x1F) - 1; ch = (ch & 0x1F) - 1;
} else if (ch >= '2' && ch <= '7') { } else if(ch >= '2' && ch <= '7') {
ch -= '2' - 26; ch -= '2' - 26;
} else { } else {
return -1; return -1;
} }
buffer |= ch; buffer |= ch;
bitsLeft += 5; bitsLeft += 5;
if (bitsLeft >= 8) { if(bitsLeft >= 8) {
result[count++] = buffer >> (bitsLeft - 8); result[count++] = buffer >> (bitsLeft - 8);
bitsLeft -= 8; bitsLeft -= 8;
}
}
if (count < bufSize) {
result[count] = '\000';
}
return count;
}
int base32_encode(const uint8_t *data, int length, uint8_t *result,
int bufSize) {
if (length < 0 || length > (1 << 28)) {
return -1;
}
int count = 0;
if (length > 0) {
int buffer = data[0];
int next = 1;
int bitsLeft = 8;
while (count < bufSize && (bitsLeft > 0 || next < length)) {
if (bitsLeft < 5) {
if (next < length) {
buffer <<= 8;
buffer |= data[next++] & 0xFF;
bitsLeft += 8;
} else {
int pad = 5 - bitsLeft;
buffer <<= pad;
bitsLeft += pad;
} }
}
int index = 0x1F & (buffer >> (bitsLeft - 5));
bitsLeft -= 5;
result[count++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[index];
} }
} if(count < bufSize) {
if (count < bufSize) { result[count] = '\000';
result[count] = '\000'; }
} return count;
return count; }
int base32_encode(const uint8_t* data, int length, uint8_t* result, int bufSize) {
if(length < 0 || length > (1 << 28)) {
return -1;
}
int count = 0;
if(length > 0) {
int buffer = data[0];
int next = 1;
int bitsLeft = 8;
while(count < bufSize && (bitsLeft > 0 || next < length)) {
if(bitsLeft < 5) {
if(next < length) {
buffer <<= 8;
buffer |= data[next++] & 0xFF;
bitsLeft += 8;
} else {
int pad = 5 - bitsLeft;
buffer <<= pad;
bitsLeft += pad;
}
}
int index = 0x1F & (buffer >> (bitsLeft - 5));
bitsLeft -= 5;
result[count++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[index];
}
}
if(count < bufSize) {
result[count] = '\000';
}
return count;
} }

View File

@@ -29,8 +29,7 @@
#include <stdint.h> #include <stdint.h>
int base32_decode(const uint8_t *encoded, uint8_t *result, int bufSize) int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize)
__attribute__((visibility("hidden"))); __attribute__((visibility("hidden")));
int base32_encode(const uint8_t *data, int length, uint8_t *result, int base32_encode(const uint8_t* data, int length, uint8_t* result, int bufSize)
int bufSize)
__attribute__((visibility("hidden"))); __attribute__((visibility("hidden")));

View File

@@ -11,41 +11,46 @@
#define CONFIG_FILE_BACKUP_PATH CONFIG_FILE_PATH ".backup" #define CONFIG_FILE_BACKUP_PATH CONFIG_FILE_PATH ".backup"
uint8_t token_info_get_digits_as_int(TokenInfo* token_info) { uint8_t token_info_get_digits_as_int(TokenInfo* token_info) {
switch (token_info->digits) { switch(token_info->digits) {
case TOTP_6_DIGITS: return 6; case TOTP_6_DIGITS:
case TOTP_8_DIGITS: return 8; return 6;
case TOTP_8_DIGITS:
return 8;
} }
return 6; return 6;
} }
void token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits) { void token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits) {
switch (digits) { switch(digits) {
case 6: case 6:
token_info->digits = TOTP_6_DIGITS; token_info->digits = TOTP_6_DIGITS;
break; break;
case 8: case 8:
token_info->digits = TOTP_8_DIGITS; token_info->digits = TOTP_8_DIGITS;
break; break;
} }
} }
char* token_info_get_algo_as_cstr(TokenInfo* token_info) { char* token_info_get_algo_as_cstr(TokenInfo* token_info) {
switch (token_info->algo) { switch(token_info->algo) {
case SHA1: return TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME; case SHA1:
case SHA256: return TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME; return TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME;
case SHA512: return TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME; case SHA256:
return TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME;
case SHA512:
return TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME;
} }
return NULL; return NULL;
} }
void token_info_set_algo_from_str(TokenInfo* token_info, FuriString* str) { void token_info_set_algo_from_str(TokenInfo* token_info, FuriString* str) {
if (furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) { if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) {
token_info->algo = SHA1; token_info->algo = SHA1;
} else if (furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME)) { } else if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME)) {
token_info->algo = SHA256; token_info->algo = SHA256;
} else if (furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME)) { } else if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME)) {
token_info->algo = SHA512; token_info->algo = SHA512;
} }
} }
@@ -61,7 +66,7 @@ void totp_close_storage() {
FlipperFormat* totp_open_config_file(Storage* storage) { FlipperFormat* totp_open_config_file(Storage* storage) {
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
if (storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK) { if(storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK) {
FURI_LOG_D(LOGGING_TAG, "Config file %s found", CONFIG_FILE_PATH); FURI_LOG_D(LOGGING_TAG, "Config file %s found", CONFIG_FILE_PATH);
if(!flipper_format_file_open_existing(fff_data_file, CONFIG_FILE_PATH)) { if(!flipper_format_file_open_existing(fff_data_file, CONFIG_FILE_PATH)) {
FURI_LOG_E(LOGGING_TAG, "Error opening existing file %s", CONFIG_FILE_PATH); FURI_LOG_E(LOGGING_TAG, "Error opening existing file %s", CONFIG_FILE_PATH);
@@ -70,47 +75,65 @@ FlipperFormat* totp_open_config_file(Storage* storage) {
} }
} else { } else {
FURI_LOG_D(LOGGING_TAG, "Config file %s is not found. Will create new.", CONFIG_FILE_PATH); FURI_LOG_D(LOGGING_TAG, "Config file %s is not found. Will create new.", CONFIG_FILE_PATH);
if (storage_common_stat(storage, CONFIG_FILE_DIRECTORY_PATH, NULL) == FSE_NOT_EXIST) { if(storage_common_stat(storage, CONFIG_FILE_DIRECTORY_PATH, NULL) == FSE_NOT_EXIST) {
FURI_LOG_D(LOGGING_TAG, "Directory %s doesn't exist. Will create new.", CONFIG_FILE_DIRECTORY_PATH); FURI_LOG_D(
if (!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) { LOGGING_TAG,
"Directory %s doesn't exist. Will create new.",
CONFIG_FILE_DIRECTORY_PATH);
if(!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) {
FURI_LOG_E(LOGGING_TAG, "Error creating directory %s", CONFIG_FILE_DIRECTORY_PATH); FURI_LOG_E(LOGGING_TAG, "Error creating directory %s", CONFIG_FILE_DIRECTORY_PATH);
return NULL; return NULL;
} }
} }
if (!flipper_format_file_open_new(fff_data_file, CONFIG_FILE_PATH)) { if(!flipper_format_file_open_new(fff_data_file, CONFIG_FILE_PATH)) {
totp_close_config_file(fff_data_file); totp_close_config_file(fff_data_file);
FURI_LOG_E(LOGGING_TAG, "Error creating new file %s", CONFIG_FILE_PATH); FURI_LOG_E(LOGGING_TAG, "Error creating new file %s", CONFIG_FILE_PATH);
return NULL; return NULL;
} }
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION); flipper_format_write_header_cstr(
fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION);
float tmp_tz = 0; float tmp_tz = 0;
flipper_format_write_comment_cstr(fff_data_file, " "); flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "Timezone offset in hours. Important note: do not put '+' sign for positive values"); flipper_format_write_comment_cstr(
fff_data_file,
"Timezone offset in hours. Important note: do not put '+' sign for positive values");
flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1); flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1);
FuriString* temp_str = furi_string_alloc(); FuriString* temp_str = furi_string_alloc();
flipper_format_write_comment_cstr(fff_data_file, " "); flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "=== TOKEN SAMPLE BEGIN ==="); flipper_format_write_comment_cstr(fff_data_file, "=== TOKEN SAMPLE BEGIN ===");
flipper_format_write_comment_cstr(fff_data_file, " "); flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "# Token name which will be visible in the UI."); flipper_format_write_comment_cstr(
fff_data_file, "# Token name which will be visible in the UI.");
furi_string_printf(temp_str, "%s: Sample token name", TOTP_CONFIG_KEY_TOKEN_NAME); furi_string_printf(temp_str, "%s: Sample token name", TOTP_CONFIG_KEY_TOKEN_NAME);
flipper_format_write_comment(fff_data_file, temp_str); flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " "); flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "# Plain token secret without spaces, dashes and etc, just pure alpha-numeric characters. Important note: plain token will be encrypted and replaced by TOTP app"); flipper_format_write_comment_cstr(
fff_data_file,
"# Plain token secret without spaces, dashes and etc, just pure alpha-numeric characters. Important note: plain token will be encrypted and replaced by TOTP app");
furi_string_printf(temp_str, "%s: plaintokensecret", TOTP_CONFIG_KEY_TOKEN_SECRET); furi_string_printf(temp_str, "%s: plaintokensecret", TOTP_CONFIG_KEY_TOKEN_SECRET);
flipper_format_write_comment(fff_data_file, temp_str); flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " "); flipper_format_write_comment_cstr(fff_data_file, " ");
furi_string_printf(temp_str, " # Token hashing algorithm to use during code generation. Supported options are %s, %s and %s. If you are not use which one to use - use %s", TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME, TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME, TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME); furi_string_printf(
temp_str,
" # Token hashing algorithm to use during code generation. Supported options are %s, %s and %s. If you are not use which one to use - use %s",
TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME,
TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME,
TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME,
TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME);
flipper_format_write_comment(fff_data_file, temp_str); flipper_format_write_comment(fff_data_file, temp_str);
furi_string_printf(temp_str, "%s: %s", TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME); furi_string_printf(
temp_str, "%s: %s", TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME);
flipper_format_write_comment(fff_data_file, temp_str); flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " "); flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "# How many digits there should be in generated code. Available options are 6 and 8. Majority websites requires 6 digits code, however some rare websites wants to get 8 digits code. If you are not sure which one to use - use 6"); flipper_format_write_comment_cstr(
fff_data_file,
"# How many digits there should be in generated code. Available options are 6 and 8. Majority websites requires 6 digits code, however some rare websites wants to get 8 digits code. If you are not sure which one to use - use 6");
furi_string_printf(temp_str, "%s: 6", TOTP_CONFIG_KEY_TOKEN_DIGITS); furi_string_printf(temp_str, "%s: 6", TOTP_CONFIG_KEY_TOKEN_DIGITS);
flipper_format_write_comment(fff_data_file, temp_str); flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " "); flipper_format_write_comment_cstr(fff_data_file, " ");
@@ -125,15 +148,17 @@ FlipperFormat* totp_open_config_file(Storage* storage) {
return NULL; return NULL;
} }
} }
return fff_data_file; return fff_data_file;
} }
void totp_config_file_save_new_token_i(FlipperFormat* file, TokenInfo* token_info) { void totp_config_file_save_new_token_i(FlipperFormat* file, TokenInfo* token_info) {
flipper_format_seek_to_end(file); flipper_format_seek_to_end(file);
flipper_format_write_string_cstr(file, TOTP_CONFIG_KEY_TOKEN_NAME, token_info->name); flipper_format_write_string_cstr(file, TOTP_CONFIG_KEY_TOKEN_NAME, token_info->name);
flipper_format_write_hex(file, TOTP_CONFIG_KEY_TOKEN_SECRET, token_info->token, token_info->token_length); flipper_format_write_hex(
flipper_format_write_string_cstr(file, TOTP_CONFIG_KEY_TOKEN_ALGO, token_info_get_algo_as_cstr(token_info)); file, TOTP_CONFIG_KEY_TOKEN_SECRET, token_info->token, token_info->token_length);
flipper_format_write_string_cstr(
file, TOTP_CONFIG_KEY_TOKEN_ALGO, token_info_get_algo_as_cstr(token_info));
uint32_t digits_count_as_uint32 = token_info_get_digits_as_int(token_info); uint32_t digits_count_as_uint32 = token_info_get_digits_as_int(token_info);
flipper_format_write_uint32(file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &digits_count_as_uint32, 1); flipper_format_write_uint32(file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &digits_count_as_uint32, 1);
} }
@@ -163,17 +188,24 @@ void totp_full_save_config_file(PluginState* const plugin_state) {
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
flipper_format_file_open_always(fff_data_file, CONFIG_FILE_PATH); flipper_format_file_open_always(fff_data_file, CONFIG_FILE_PATH);
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION); flipper_format_write_header_cstr(
flipper_format_write_hex(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE); fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION);
flipper_format_write_hex(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, plugin_state->crypto_verify_data, plugin_state->crypto_verify_data_length); flipper_format_write_hex(
flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1); fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE);
flipper_format_write_hex(
fff_data_file,
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
plugin_state->crypto_verify_data,
plugin_state->crypto_verify_data_length);
flipper_format_write_float(
fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1);
flipper_format_write_bool(fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1); flipper_format_write_bool(fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1);
ListNode* node = plugin_state->tokens_list; ListNode* node = plugin_state->tokens_list;
while (node != NULL) { while(node != NULL) {
TokenInfo* token_info = node->data; TokenInfo* token_info = node->data;
totp_config_file_save_new_token_i(fff_data_file, token_info); totp_config_file_save_new_token_i(fff_data_file, token_info);
node = node->next; node = node->next;
} }
totp_close_config_file(fff_data_file); totp_close_config_file(fff_data_file);
totp_close_storage(); totp_close_storage();
@@ -194,22 +226,27 @@ void totp_config_file_load_base(PluginState* const plugin_state) {
return; return;
} }
if (file_version < CONFIG_FILE_ACTUAL_VERSION) { if(file_version < CONFIG_FILE_ACTUAL_VERSION) {
FURI_LOG_I(LOGGING_TAG, "Obsolete config file version detected. Current version: %" PRIu32 "; Actual version: %" PRId16, file_version, CONFIG_FILE_ACTUAL_VERSION); FURI_LOG_I(
LOGGING_TAG,
"Obsolete config file version detected. Current version: %" PRIu32
"; Actual version: %" PRId16,
file_version,
CONFIG_FILE_ACTUAL_VERSION);
totp_close_config_file(fff_data_file); totp_close_config_file(fff_data_file);
if (storage_common_stat(storage, CONFIG_FILE_BACKUP_PATH, NULL) == FSE_OK) { if(storage_common_stat(storage, CONFIG_FILE_BACKUP_PATH, NULL) == FSE_OK) {
storage_simply_remove(storage, CONFIG_FILE_BACKUP_PATH); storage_simply_remove(storage, CONFIG_FILE_BACKUP_PATH);
} }
if (storage_common_copy(storage, CONFIG_FILE_PATH, CONFIG_FILE_BACKUP_PATH) == FSE_OK) { if(storage_common_copy(storage, CONFIG_FILE_PATH, CONFIG_FILE_BACKUP_PATH) == FSE_OK) {
FURI_LOG_I(LOGGING_TAG, "Took config file backup to %s", CONFIG_FILE_BACKUP_PATH); FURI_LOG_I(LOGGING_TAG, "Took config file backup to %s", CONFIG_FILE_BACKUP_PATH);
fff_data_file = totp_open_config_file(storage); fff_data_file = totp_open_config_file(storage);
FlipperFormat* fff_backup_data_file = flipper_format_file_alloc(storage); FlipperFormat* fff_backup_data_file = flipper_format_file_alloc(storage);
flipper_format_file_open_existing(fff_backup_data_file, CONFIG_FILE_BACKUP_PATH); flipper_format_file_open_existing(fff_backup_data_file, CONFIG_FILE_BACKUP_PATH);
if (file_version == 1) { if(file_version == 1) {
if (totp_config_migrate_v1_to_v2(fff_data_file, fff_backup_data_file)) { if(totp_config_migrate_v1_to_v2(fff_data_file, fff_backup_data_file)) {
FURI_LOG_I(LOGGING_TAG, "Applied migration from v1 to v2"); FURI_LOG_I(LOGGING_TAG, "Applied migration from v1 to v2");
} else { } else {
FURI_LOG_W(LOGGING_TAG, "An error occurred during migration from v1 to v2"); FURI_LOG_W(LOGGING_TAG, "An error occurred during migration from v1 to v2");
@@ -220,21 +257,31 @@ void totp_config_file_load_base(PluginState* const plugin_state) {
flipper_format_free(fff_backup_data_file); flipper_format_free(fff_backup_data_file);
flipper_format_rewind(fff_data_file); flipper_format_rewind(fff_data_file);
} else { } else {
FURI_LOG_E(LOGGING_TAG, "An error occurred during taking backup of %s into %s before migration", CONFIG_FILE_PATH, CONFIG_FILE_BACKUP_PATH); FURI_LOG_E(
LOGGING_TAG,
"An error occurred during taking backup of %s into %s before migration",
CONFIG_FILE_PATH,
CONFIG_FILE_BACKUP_PATH);
} }
} }
if (!flipper_format_read_hex(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE)) { if(!flipper_format_read_hex(
fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE)) {
FURI_LOG_D(LOGGING_TAG, "Missing base IV"); FURI_LOG_D(LOGGING_TAG, "Missing base IV");
} }
flipper_format_rewind(fff_data_file); flipper_format_rewind(fff_data_file);
uint32_t crypto_size; uint32_t crypto_size;
if (flipper_format_get_value_count(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, &crypto_size) && crypto_size > 0) { if(flipper_format_get_value_count(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, &crypto_size) &&
crypto_size > 0) {
plugin_state->crypto_verify_data = malloc(sizeof(uint8_t) * crypto_size); plugin_state->crypto_verify_data = malloc(sizeof(uint8_t) * crypto_size);
plugin_state->crypto_verify_data_length = crypto_size; plugin_state->crypto_verify_data_length = crypto_size;
if (!flipper_format_read_hex(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, plugin_state->crypto_verify_data, crypto_size)) { if(!flipper_format_read_hex(
fff_data_file,
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
plugin_state->crypto_verify_data,
crypto_size)) {
FURI_LOG_D(LOGGING_TAG, "Missing crypto verify token"); FURI_LOG_D(LOGGING_TAG, "Missing crypto verify token");
free(plugin_state->crypto_verify_data); free(plugin_state->crypto_verify_data);
plugin_state->crypto_verify_data = NULL; plugin_state->crypto_verify_data = NULL;
@@ -247,16 +294,18 @@ void totp_config_file_load_base(PluginState* const plugin_state) {
flipper_format_rewind(fff_data_file); flipper_format_rewind(fff_data_file);
if (!flipper_format_read_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1)) { if(!flipper_format_read_float(
fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1)) {
plugin_state->timezone_offset = 0; plugin_state->timezone_offset = 0;
FURI_LOG_D(LOGGING_TAG, "Missing timezone offset information, defaulting to 0"); FURI_LOG_D(LOGGING_TAG, "Missing timezone offset information, defaulting to 0");
} }
flipper_format_rewind(fff_data_file); flipper_format_rewind(fff_data_file);
if (!flipper_format_read_bool(fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) { if(!flipper_format_read_bool(
fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) {
plugin_state->pin_set = true; plugin_state->pin_set = true;
} }
furi_string_free(temp_str); furi_string_free(temp_str);
totp_close_config_file(fff_data_file); totp_close_config_file(fff_data_file);
@@ -279,25 +328,26 @@ void totp_config_file_load_tokens(PluginState* const plugin_state) {
uint8_t index = 0; uint8_t index = 0;
bool has_any_plain_secret = false; bool has_any_plain_secret = false;
while (true) { while(true) {
if (!flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) { if(!flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
break; break;
} }
TokenInfo* tokenInfo = token_info_alloc(); TokenInfo* tokenInfo = token_info_alloc();
const char* temp_cstr = furi_string_get_cstr(temp_str); const char* temp_cstr = furi_string_get_cstr(temp_str);
tokenInfo->name = (char *)malloc(strlen(temp_cstr) + 1); tokenInfo->name = (char*)malloc(strlen(temp_cstr) + 1);
strcpy(tokenInfo->name, temp_cstr); strcpy(tokenInfo->name, temp_cstr);
uint32_t secret_bytes_count; uint32_t secret_bytes_count;
if (!flipper_format_get_value_count(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, &secret_bytes_count)) { if(!flipper_format_get_value_count(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, &secret_bytes_count)) {
token_info_free(tokenInfo); token_info_free(tokenInfo);
continue; continue;
} }
if (secret_bytes_count == 1) { // Plain secret key if(secret_bytes_count == 1) { // Plain secret key
if (!flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str)) { if(!flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str)) {
token_info_free(tokenInfo); token_info_free(tokenInfo);
continue; continue;
} }
@@ -309,20 +359,25 @@ void totp_config_file_load_tokens(PluginState* const plugin_state) {
} else { // encrypted } else { // encrypted
tokenInfo->token_length = secret_bytes_count; tokenInfo->token_length = secret_bytes_count;
tokenInfo->token = malloc(tokenInfo->token_length); tokenInfo->token = malloc(tokenInfo->token_length);
if (!flipper_format_read_hex(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, tokenInfo->token, tokenInfo->token_length)) { if(!flipper_format_read_hex(
fff_data_file,
TOTP_CONFIG_KEY_TOKEN_SECRET,
tokenInfo->token,
tokenInfo->token_length)) {
token_info_free(tokenInfo); token_info_free(tokenInfo);
continue; continue;
} }
} }
if (!flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str)) { if(!flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str)) {
token_info_free(tokenInfo); token_info_free(tokenInfo);
continue; continue;
} }
token_info_set_algo_from_str(tokenInfo, temp_str); token_info_set_algo_from_str(tokenInfo, temp_str);
if (!flipper_format_read_uint32(fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &temp_data32, 1)) { if(!flipper_format_read_uint32(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &temp_data32, 1)) {
token_info_free(tokenInfo); token_info_free(tokenInfo);
continue; continue;
} }
@@ -331,7 +386,7 @@ void totp_config_file_load_tokens(PluginState* const plugin_state) {
FURI_LOG_D(LOGGING_TAG, "Found token \"%s\"", tokenInfo->name); FURI_LOG_D(LOGGING_TAG, "Found token \"%s\"", tokenInfo->name);
if (plugin_state->tokens_list == NULL) { if(plugin_state->tokens_list == NULL) {
plugin_state->tokens_list = list_init_head(tokenInfo); plugin_state->tokens_list = list_init_head(tokenInfo);
} else { } else {
list_add(plugin_state->tokens_list, tokenInfo); list_add(plugin_state->tokens_list, tokenInfo);
@@ -349,13 +404,13 @@ void totp_config_file_load_tokens(PluginState* const plugin_state) {
totp_close_config_file(fff_data_file); totp_close_config_file(fff_data_file);
totp_close_storage(); totp_close_storage();
if (has_any_plain_secret) { if(has_any_plain_secret) {
totp_full_save_config_file(plugin_state); totp_full_save_config_file(plugin_state);
} }
} }
void totp_close_config_file(FlipperFormat* file) { void totp_close_config_file(FlipperFormat* file) {
if (file == NULL) return; if(file == NULL) return;
flipper_format_file_close(file); flipper_format_file_close(file);
flipper_format_free(file); flipper_format_free(file);
} }

View File

@@ -4,25 +4,28 @@
#define NEW_VERSION 2 #define NEW_VERSION 2
bool totp_config_migrate_v1_to_v2(FlipperFormat* fff_data_file, FlipperFormat* fff_backup_data_file) { bool totp_config_migrate_v1_to_v2(
FlipperFormat* fff_data_file,
FlipperFormat* fff_backup_data_file) {
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, NEW_VERSION); flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, NEW_VERSION);
FuriString* temp_str = furi_string_alloc(); FuriString* temp_str = furi_string_alloc();
if (flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) { if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str); flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
} }
if (flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str)) { if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str); flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str);
} }
if (flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str)) { if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str); flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str);
} }
while (true) { while(true) {
if (!flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) { if(!flipper_format_read_string(
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
break; break;
} }
@@ -30,10 +33,12 @@ bool totp_config_migrate_v1_to_v2(FlipperFormat* fff_data_file, FlipperFormat* f
flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str); flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str); flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
flipper_format_write_string_cstr(fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME); flipper_format_write_string_cstr(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME);
uint32_t default_digits = 6; uint32_t default_digits = 6;
flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &default_digits, 1); flipper_format_write_uint32(
fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &default_digits, 1);
} }
furi_string_free(temp_str); furi_string_free(temp_str);

View File

@@ -2,4 +2,6 @@
#include <flipper_format/flipper_format.h> #include <flipper_format/flipper_format.h>
bool totp_config_migrate_v1_to_v2(FlipperFormat* fff_data_file, FlipperFormat* fff_backup_data_file); bool totp_config_migrate_v1_to_v2(
FlipperFormat* fff_data_file,
FlipperFormat* fff_backup_data_file);

View File

@@ -9,7 +9,11 @@
#define CRYPTO_VERIFY_KEY_LENGTH 16 #define CRYPTO_VERIFY_KEY_LENGTH 16
#define CRYPTO_ALIGNMENT_FACTOR 16 #define CRYPTO_ALIGNMENT_FACTOR 16
uint8_t* totp_crypto_encrypt(const uint8_t* plain_data, const uint8_t plain_data_length, const uint8_t* iv, uint8_t* encrypted_data_length) { uint8_t* totp_crypto_encrypt(
const uint8_t* plain_data,
const uint8_t plain_data_length,
const uint8_t* iv,
uint8_t* encrypted_data_length) {
uint8_t* encrypted_data; uint8_t* encrypted_data;
size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR; size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR;
if(remain) { if(remain) {
@@ -17,10 +21,10 @@ uint8_t* totp_crypto_encrypt(const uint8_t* plain_data, const uint8_t plain_data
uint8_t* plain_data_aligned = malloc(plain_data_aligned_length); uint8_t* plain_data_aligned = malloc(plain_data_aligned_length);
memset(plain_data_aligned, 0, plain_data_aligned_length); memset(plain_data_aligned, 0, plain_data_aligned_length);
memcpy(plain_data_aligned, plain_data, plain_data_length); memcpy(plain_data_aligned, plain_data, plain_data_length);
encrypted_data = malloc(plain_data_aligned_length); encrypted_data = malloc(plain_data_aligned_length);
*encrypted_data_length = plain_data_aligned_length; *encrypted_data_length = plain_data_aligned_length;
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv); furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length); furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length);
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT); furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
@@ -39,7 +43,11 @@ uint8_t* totp_crypto_encrypt(const uint8_t* plain_data, const uint8_t plain_data
return encrypted_data; return encrypted_data;
} }
uint8_t* totp_crypto_decrypt(const uint8_t* encrypted_data, const uint8_t encrypted_data_length, const uint8_t* iv, uint8_t* decrypted_data_length) { uint8_t* totp_crypto_decrypt(
const uint8_t* encrypted_data,
const uint8_t encrypted_data_length,
const uint8_t* iv,
uint8_t* decrypted_data_length) {
*decrypted_data_length = encrypted_data_length; *decrypted_data_length = encrypted_data_length;
uint8_t* decrypted_data = malloc(*decrypted_data_length); uint8_t* decrypted_data = malloc(*decrypted_data_length);
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv); furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
@@ -49,27 +57,27 @@ uint8_t* totp_crypto_decrypt(const uint8_t* encrypted_data, const uint8_t encryp
} }
void totp_crypto_seed_iv(PluginState* plugin_state, uint8_t* pin, uint8_t pin_length) { void totp_crypto_seed_iv(PluginState* plugin_state, uint8_t* pin, uint8_t pin_length) {
if (plugin_state->crypto_verify_data == NULL) { if(plugin_state->crypto_verify_data == NULL) {
FURI_LOG_D(LOGGING_TAG, "Generating new IV"); FURI_LOG_D(LOGGING_TAG, "Generating new IV");
furi_hal_random_fill_buf(&plugin_state->base_iv[0], TOTP_IV_SIZE); furi_hal_random_fill_buf(&plugin_state->base_iv[0], TOTP_IV_SIZE);
} }
memcpy(&plugin_state->iv[0], &plugin_state->base_iv[0], TOTP_IV_SIZE); memcpy(&plugin_state->iv[0], &plugin_state->base_iv[0], TOTP_IV_SIZE);
if (pin != NULL && pin_length > 0) { if(pin != NULL && pin_length > 0) {
uint8_t max_i; uint8_t max_i;
if (pin_length > TOTP_IV_SIZE) { if(pin_length > TOTP_IV_SIZE) {
max_i = TOTP_IV_SIZE; max_i = TOTP_IV_SIZE;
} else { } else {
max_i = pin_length; max_i = pin_length;
} }
for (uint8_t i = 0; i < max_i; i++) { for(uint8_t i = 0; i < max_i; i++) {
plugin_state->iv[i] = plugin_state->iv[i] ^ (uint8_t)(pin[i] * (i + 1)); plugin_state->iv[i] = plugin_state->iv[i] ^ (uint8_t)(pin[i] * (i + 1));
} }
} else { } else {
uint8_t max_i; uint8_t max_i;
size_t uid_size = furi_hal_version_uid_size(); size_t uid_size = furi_hal_version_uid_size();
if (uid_size > TOTP_IV_SIZE) { if(uid_size > TOTP_IV_SIZE) {
max_i = TOTP_IV_SIZE; max_i = TOTP_IV_SIZE;
} else { } else {
max_i = uid_size; max_i = uid_size;
@@ -81,19 +89,29 @@ void totp_crypto_seed_iv(PluginState* plugin_state, uint8_t* pin, uint8_t pin_le
} }
} }
if (plugin_state->crypto_verify_data == NULL) { if(plugin_state->crypto_verify_data == NULL) {
FURI_LOG_D(LOGGING_TAG, "Generating crypto verify data"); FURI_LOG_D(LOGGING_TAG, "Generating crypto verify data");
plugin_state->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH); plugin_state->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH);
plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH; plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
Storage* storage = totp_open_storage(); Storage* storage = totp_open_storage();
FlipperFormat* config_file = totp_open_config_file(storage); FlipperFormat* config_file = totp_open_config_file(storage);
plugin_state->crypto_verify_data = totp_crypto_encrypt((uint8_t* )CRYPTO_VERIFY_KEY, CRYPTO_VERIFY_KEY_LENGTH, &plugin_state->iv[0], &plugin_state->crypto_verify_data_length); plugin_state->crypto_verify_data = totp_crypto_encrypt(
(uint8_t*)CRYPTO_VERIFY_KEY,
CRYPTO_VERIFY_KEY_LENGTH,
&plugin_state->iv[0],
&plugin_state->crypto_verify_data_length);
flipper_format_insert_or_update_hex(config_file, TOTP_CONFIG_KEY_BASE_IV, plugin_state->base_iv, TOTP_IV_SIZE); flipper_format_insert_or_update_hex(
flipper_format_insert_or_update_hex(config_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, plugin_state->crypto_verify_data, CRYPTO_VERIFY_KEY_LENGTH); config_file, TOTP_CONFIG_KEY_BASE_IV, plugin_state->base_iv, TOTP_IV_SIZE);
flipper_format_insert_or_update_hex(
config_file,
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
plugin_state->crypto_verify_data,
CRYPTO_VERIFY_KEY_LENGTH);
plugin_state->pin_set = pin != NULL && pin_length > 0; plugin_state->pin_set = pin != NULL && pin_length > 0;
flipper_format_insert_or_update_bool(config_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1); flipper_format_insert_or_update_bool(
config_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1);
totp_close_config_file(config_file); totp_close_config_file(config_file);
totp_close_storage(); totp_close_storage();
} }
@@ -101,11 +119,15 @@ void totp_crypto_seed_iv(PluginState* plugin_state, uint8_t* pin, uint8_t pin_le
bool totp_crypto_verify_key(const PluginState* plugin_state) { bool totp_crypto_verify_key(const PluginState* plugin_state) {
uint8_t decrypted_key_length; uint8_t decrypted_key_length;
uint8_t* decrypted_key = totp_crypto_decrypt(plugin_state->crypto_verify_data, plugin_state->crypto_verify_data_length, &plugin_state->iv[0], &decrypted_key_length); uint8_t* decrypted_key = totp_crypto_decrypt(
plugin_state->crypto_verify_data,
plugin_state->crypto_verify_data_length,
&plugin_state->iv[0],
&decrypted_key_length);
bool key_valid = true; bool key_valid = true;
for (uint8_t i = 0; i < CRYPTO_VERIFY_KEY_LENGTH && key_valid; i++) { for(uint8_t i = 0; i < CRYPTO_VERIFY_KEY_LENGTH && key_valid; i++) {
if (decrypted_key[i] != CRYPTO_VERIFY_KEY[i]) key_valid = false; if(decrypted_key[i] != CRYPTO_VERIFY_KEY[i]) key_valid = false;
} }
return key_valid; return key_valid;

View File

@@ -2,7 +2,15 @@
#include "../../types/plugin_state.h" #include "../../types/plugin_state.h"
uint8_t* totp_crypto_encrypt(const uint8_t* plain_data, const uint8_t plain_data_length, const uint8_t* iv, uint8_t* encrypted_data_length); uint8_t* totp_crypto_encrypt(
uint8_t* totp_crypto_decrypt(const uint8_t* encrypted_data, const uint8_t encrypted_data_length, const uint8_t* iv, uint8_t* decrypted_data_length); const uint8_t* plain_data,
const uint8_t plain_data_length,
const uint8_t* iv,
uint8_t* encrypted_data_length);
uint8_t* totp_crypto_decrypt(
const uint8_t* encrypted_data,
const uint8_t encrypted_data_length,
const uint8_t* iv,
uint8_t* decrypted_data_length);
void totp_crypto_seed_iv(PluginState* plugin_state, uint8_t* pin, uint8_t pin_length); void totp_crypto_seed_iv(PluginState* plugin_state, uint8_t* pin, uint8_t pin_length);
bool totp_crypto_verify_key(const PluginState* plugin_state); bool totp_crypto_verify_key(const PluginState* plugin_state);

View File

@@ -1,14 +1,12 @@
#include "byteswap.h" #include "byteswap.h"
uint32_t swap_uint32( uint32_t val ) uint32_t swap_uint32(uint32_t val) {
{ val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF );
return (val << 16) | (val >> 16); return (val << 16) | (val >> 16);
} }
uint64_t swap_uint64( uint64_t val ) uint64_t swap_uint64(uint64_t val) {
{ val = ((val << 8) & 0xFF00FF00FF00FF00ULL) | ((val >> 8) & 0x00FF00FF00FF00FFULL);
val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL ); val = ((val << 16) & 0xFFFF0000FFFF0000ULL) | ((val >> 16) & 0x0000FFFF0000FFFFULL);
val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
return (val << 32) | (val >> 32); return (val << 32) | (val >> 32);
} }

View File

@@ -2,5 +2,5 @@
#include <stdint.h> #include <stdint.h>
uint32_t swap_uint32( uint32_t val ); uint32_t swap_uint32(uint32_t val);
uint64_t swap_uint64( uint64_t val ); uint64_t swap_uint64(uint64_t val);

View File

@@ -0,0 +1,64 @@
#include <string.h>
#include "sha256.h"
#include "memxor.h"
#define IPAD 0x36
#define OPAD 0x5c
/* Concatenate two preprocessor tokens. */
#define _GLHMAC_CONCAT_(prefix, suffix) prefix##suffix
#define _GLHMAC_CONCAT(prefix, suffix) _GLHMAC_CONCAT_(prefix, suffix)
#if GL_HMAC_NAME == 5
#define HMAC_ALG md5
#else
#define HMAC_ALG _GLHMAC_CONCAT(sha, GL_HMAC_NAME)
#endif
#define GL_HMAC_CTX _GLHMAC_CONCAT(HMAC_ALG, _ctx)
#define GL_HMAC_FN _GLHMAC_CONCAT(hmac_, HMAC_ALG)
#define GL_HMAC_FN_INIT _GLHMAC_CONCAT(HMAC_ALG, _init_ctx)
#define GL_HMAC_FN_BLOC _GLHMAC_CONCAT(HMAC_ALG, _process_block)
#define GL_HMAC_FN_PROC _GLHMAC_CONCAT(HMAC_ALG, _process_bytes)
#define GL_HMAC_FN_FINI _GLHMAC_CONCAT(HMAC_ALG, _finish_ctx)
static void
hmac_hash(const void* key, size_t keylen, const void* in, size_t inlen, int pad, void* resbuf) {
struct GL_HMAC_CTX hmac_ctx;
char block[GL_HMAC_BLOCKSIZE];
memset(block, pad, sizeof block);
memxor(block, key, keylen);
GL_HMAC_FN_INIT(&hmac_ctx);
GL_HMAC_FN_BLOC(block, sizeof block, &hmac_ctx);
GL_HMAC_FN_PROC(in, inlen, &hmac_ctx);
GL_HMAC_FN_FINI(&hmac_ctx, resbuf);
}
int GL_HMAC_FN(const void* key, size_t keylen, const void* in, size_t inlen, void* resbuf) {
char optkeybuf[GL_HMAC_HASHSIZE];
char innerhash[GL_HMAC_HASHSIZE];
/* Ensure key size is <= block size. */
if(keylen > GL_HMAC_BLOCKSIZE) {
struct GL_HMAC_CTX keyhash;
GL_HMAC_FN_INIT(&keyhash);
GL_HMAC_FN_PROC(key, keylen, &keyhash);
GL_HMAC_FN_FINI(&keyhash, optkeybuf);
key = optkeybuf;
/* zero padding of the key to the block size
is implicit in the memxor. */
keylen = sizeof optkeybuf;
}
/* Compute INNERHASH from KEY and IN. */
hmac_hash(key, keylen, in, inlen, IPAD, innerhash);
/* Compute result from KEY and INNERHASH. */
hmac_hash(key, keylen, innerhash, sizeof innerhash, OPAD, resbuf);
return 0;
}

View File

@@ -0,0 +1,24 @@
/* hmac_sha1.c -- hashed message authentication codes
Copyright (C) 2018-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "hmac_sha1.h"
#include "sha1.h"
#define GL_HMAC_NAME 1
#define GL_HMAC_BLOCKSIZE 64
#define GL_HMAC_HASHSIZE 20
#include "hmac_common.h"

View File

@@ -0,0 +1,11 @@
#pragma once
#include <stddef.h>
#define HMAC_SHA1_RESULT_SIZE 20
/* Compute Hashed Message Authentication Code with SHA-1, over BUFFER
data of BUFLEN bytes using the KEY of KEYLEN bytes, writing the
output to pre-allocated 20 byte minimum RESBUF buffer. Return 0 on
success. */
int hmac_sha1(const void* key, size_t keylen, const void* in, size_t inlen, void* restrict resbuf);

View File

@@ -0,0 +1,23 @@
/* hmac_sha256.c -- hashed message authentication codes
Copyright (C) 2018-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "hmac_sha256.h"
#define GL_HMAC_NAME 256
#define GL_HMAC_BLOCKSIZE 64
#define GL_HMAC_HASHSIZE 32
#include "hmac_common.h"

View File

@@ -0,0 +1,11 @@
#pragma once
#include <stddef.h>
#define HMAC_SHA256_RESULT_SIZE 32
/* Compute Hashed Message Authentication Code with SHA-256, over BUFFER
data of BUFLEN bytes using the KEY of KEYLEN bytes, writing the
output to pre-allocated 32 byte minimum RESBUF buffer. Return 0 on
success. */
int hmac_sha256(const void* key, size_t keylen, const void* in, size_t inlen, void* restrict resbuf);

View File

@@ -0,0 +1,24 @@
/* hmac_sha512.c -- hashed message authentication codes
Copyright (C) 2018-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "hmac_sha512.h"
#include "sha512.h"
#define GL_HMAC_NAME 512
#define GL_HMAC_BLOCKSIZE 128
#define GL_HMAC_HASHSIZE 64
#include "hmac_common.h"

View File

@@ -0,0 +1,11 @@
#pragma once
#include <stddef.h>
#define HMAC_SHA512_RESULT_SIZE 64
/* Compute Hashed Message Authentication Code with SHA-512, over BUFFER
data of BUFLEN bytes using the KEY of KEYLEN bytes, writing the
output to pre-allocated 64 byte minimum RESBUF buffer. Return 0 on
success. */
int hmac_sha512(const void* key, size_t keylen, const void* in, size_t inlen, void* restrict resbuf);

View File

@@ -22,13 +22,11 @@
#include "memxor.h" #include "memxor.h"
void* memxor (void */*restrict*/ dest, const void */*restrict*/ src, size_t n) void* memxor(void* /*restrict*/ dest, const void* /*restrict*/ src, size_t n) {
{ char const* s = (char const*)src;
char const *s = (char const*)src; char* d = (char*)dest;
char *d = (char*)dest;
for (; n > 0; n--) for(; n > 0; n--) *d++ ^= *s++;
*d++ ^= *s++;
return dest; return dest;
} }

View File

@@ -25,4 +25,4 @@
/* Compute binary exclusive OR of memory areas DEST and SRC, putting /* Compute binary exclusive OR of memory areas DEST and SRC, putting
the result in DEST, of length N bytes. Returns a pointer to the result in DEST, of length N bytes. Returns a pointer to
DEST. */ DEST. */
void *memxor (void */*restrict*/ dest, const void */*restrict*/ src, size_t n); void* memxor(void* /*restrict*/ dest, const void* /*restrict*/ src, size_t n);

View File

@@ -23,7 +23,7 @@
/* Specification. */ /* Specification. */
#if HAVE_OPENSSL_SHA1 #if HAVE_OPENSSL_SHA1
# define GL_OPENSSL_INLINE _GL_EXTERN_INLINE #define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
#endif #endif
#include "sha1.h" #include "sha1.h"
@@ -31,170 +31,148 @@
#include <string.h> #include <string.h>
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
# define SWAP(n) (n) #define SWAP(n) (n)
#else #else
#include "byteswap.h" #include "byteswap.h"
# define SWAP(n) swap_uint32(n) #define SWAP(n) swap_uint32(n)
#endif #endif
#if ! HAVE_OPENSSL_SHA1 #if !HAVE_OPENSSL_SHA1
/* This array contains the bytes used to pad the buffer to the next /* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (RFC 1321, 3.1: Step 1) */ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; static const unsigned char fillbuf[64] = {0x80, 0 /* , 0, 0, ... */};
/* Take a pointer to a 160 bit block of data (five 32 bit ints) and /* Take a pointer to a 160 bit block of data (five 32 bit ints) and
initialize it to the start constants of the SHA1 algorithm. This initialize it to the start constants of the SHA1 algorithm. This
must be called before using hash in the call to sha1_hash. */ must be called before using hash in the call to sha1_hash. */
void void sha1_init_ctx(struct sha1_ctx* ctx) {
sha1_init_ctx (struct sha1_ctx *ctx) ctx->A = 0x67452301;
{ ctx->B = 0xefcdab89;
ctx->A = 0x67452301; ctx->C = 0x98badcfe;
ctx->B = 0xefcdab89; ctx->D = 0x10325476;
ctx->C = 0x98badcfe; ctx->E = 0xc3d2e1f0;
ctx->D = 0x10325476;
ctx->E = 0xc3d2e1f0;
ctx->total[0] = ctx->total[1] = 0; ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0; ctx->buflen = 0;
} }
/* Copy the 4 byte value from v into the memory location pointed to by *cp, /* Copy the 4 byte value from v into the memory location pointed to by *cp,
If your architecture allows unaligned access this is equivalent to If your architecture allows unaligned access this is equivalent to
* (uint32_t *) cp = v */ * (uint32_t *) cp = v */
static void static void set_uint32(char* cp, uint32_t v) {
set_uint32 (char *cp, uint32_t v) memcpy(cp, &v, sizeof v);
{
memcpy (cp, &v, sizeof v);
} }
/* Put result from CTX in first 20 bytes following RESBUF. The result /* Put result from CTX in first 20 bytes following RESBUF. The result
must be in little endian byte order. */ must be in little endian byte order. */
void * void* sha1_read_ctx(const struct sha1_ctx* ctx, void* resbuf) {
sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) char* r = resbuf;
{ set_uint32(r + 0 * sizeof ctx->A, SWAP(ctx->A));
char *r = resbuf; set_uint32(r + 1 * sizeof ctx->B, SWAP(ctx->B));
set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A)); set_uint32(r + 2 * sizeof ctx->C, SWAP(ctx->C));
set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B)); set_uint32(r + 3 * sizeof ctx->D, SWAP(ctx->D));
set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C)); set_uint32(r + 4 * sizeof ctx->E, SWAP(ctx->E));
set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D));
set_uint32 (r + 4 * sizeof ctx->E, SWAP (ctx->E));
return resbuf; return resbuf;
} }
/* Process the remaining bytes in the internal buffer and the usual /* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF. */ prolog according to the standard and write the result to RESBUF. */
void * void* sha1_finish_ctx(struct sha1_ctx* ctx, void* resbuf) {
sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) /* Take yet unprocessed bytes into account. */
{ uint32_t bytes = ctx->buflen;
/* Take yet unprocessed bytes into account. */ size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
uint32_t bytes = ctx->buflen;
size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
/* Now count remaining bytes. */ /* Now count remaining bytes. */
ctx->total[0] += bytes; ctx->total[0] += bytes;
if (ctx->total[0] < bytes) if(ctx->total[0] < bytes) ++ctx->total[1];
++ctx->total[1];
/* Put the 64-bit file length in *bits* at the end of the buffer. */ /* Put the 64-bit file length in *bits* at the end of the buffer. */
ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); ctx->buffer[size - 2] = SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29));
ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3); ctx->buffer[size - 1] = SWAP(ctx->total[0] << 3);
memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
/* Process last bytes. */ /* Process last bytes. */
sha1_process_block (ctx->buffer, size * 4, ctx); sha1_process_block(ctx->buffer, size * 4, ctx);
return sha1_read_ctx (ctx, resbuf); return sha1_read_ctx(ctx, resbuf);
} }
/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The /* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message output yields to the wanted ASCII representation of the message
digest. */ digest. */
void * void* sha1_buffer(const char* buffer, size_t len, void* resblock) {
sha1_buffer (const char *buffer, size_t len, void *resblock) struct sha1_ctx ctx;
{
struct sha1_ctx ctx;
/* Initialize the computation context. */ /* Initialize the computation context. */
sha1_init_ctx (&ctx); sha1_init_ctx(&ctx);
/* Process whole buffer but last len % 64 bytes. */ /* Process whole buffer but last len % 64 bytes. */
sha1_process_bytes (buffer, len, &ctx); sha1_process_bytes(buffer, len, &ctx);
/* Put result in desired memory area. */ /* Put result in desired memory area. */
return sha1_finish_ctx (&ctx, resblock); return sha1_finish_ctx(&ctx, resblock);
} }
void void sha1_process_bytes(const void* buffer, size_t len, struct sha1_ctx* ctx) {
sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) /* When we already have some bits in our internal buffer concatenate
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */ both inputs first. */
if (ctx->buflen != 0) if(ctx->buflen != 0) {
{ size_t left_over = ctx->buflen;
size_t left_over = ctx->buflen; size_t add = 128 - left_over > len ? len : 128 - left_over;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy (&((char *) ctx->buffer)[left_over], buffer, add); memcpy(&((char*)ctx->buffer)[left_over], buffer, add);
ctx->buflen += add; ctx->buflen += add;
if (ctx->buflen > 64) if(ctx->buflen > 64) {
{ sha1_process_block(ctx->buffer, ctx->buflen & ~63, ctx);
sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63; ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap, /* The regions in the following copy operation cannot overlap,
because ctx->buflen < 64 ≤ (left_over + add) & ~63. */ because ctx->buflen < 64 ≤ (left_over + add) & ~63. */
memcpy (ctx->buffer, memcpy(ctx->buffer, &((char*)ctx->buffer)[(left_over + add) & ~63], ctx->buflen);
&((char *) ctx->buffer)[(left_over + add) & ~63],
ctx->buflen);
} }
buffer = (const char *) buffer + add; buffer = (const char*)buffer + add;
len -= add; len -= add;
} }
/* Process available complete blocks. */ /* Process available complete blocks. */
if (len >= 64) if(len >= 64) {
{
#if !(_STRING_ARCH_unaligned || _STRING_INLINE_unaligned) #if !(_STRING_ARCH_unaligned || _STRING_INLINE_unaligned)
# define UNALIGNED_P(p) ((uintptr_t) (p) % sizeof (uint32_t) != 0) #define UNALIGNED_P(p) ((uintptr_t)(p) % sizeof(uint32_t) != 0)
if (UNALIGNED_P (buffer)) if(UNALIGNED_P(buffer))
while (len > 64) while(len > 64) {
{ sha1_process_block(memcpy(ctx->buffer, buffer, 64), 64, ctx);
sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); buffer = (const char*)buffer + 64;
buffer = (const char *) buffer + 64; len -= 64;
len -= 64; }
} else
else
#endif #endif
{ {
sha1_process_block (buffer, len & ~63, ctx); sha1_process_block(buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63); buffer = (const char*)buffer + (len & ~63);
len &= 63; len &= 63;
} }
} }
/* Move remaining bytes in internal buffer. */ /* Move remaining bytes in internal buffer. */
if (len > 0) if(len > 0) {
{ size_t left_over = ctx->buflen;
size_t left_over = ctx->buflen;
memcpy (&((char *) ctx->buffer)[left_over], buffer, len); memcpy(&((char*)ctx->buffer)[left_over], buffer, len);
left_over += len; left_over += len;
if (left_over >= 64) if(left_over >= 64) {
{ sha1_process_block(ctx->buffer, 64, ctx);
sha1_process_block (ctx->buffer, 64, ctx); left_over -= 64;
left_over -= 64; /* The regions in the following copy operation cannot overlap,
/* The regions in the following copy operation cannot overlap,
because left_over ≤ 64. */ because left_over ≤ 64. */
memcpy (ctx->buffer, &ctx->buffer[16], left_over); memcpy(ctx->buffer, &ctx->buffer[16], left_over);
} }
ctx->buflen = left_over; ctx->buflen = left_over;
} }
} }
@@ -207,144 +185,139 @@ sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx)
#define K4 0xca62c1d6 #define K4 0xca62c1d6
/* Round functions. Note that F2 is the same as F4. */ /* Round functions. Note that F2 is the same as F4. */
#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) ) #define F1(B, C, D) (D ^ (B & (C ^ D)))
#define F2(B,C,D) (B ^ C ^ D) #define F2(B, C, D) (B ^ C ^ D)
#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) ) #define F3(B, C, D) ((B & C) | (D & (B | C)))
#define F4(B,C,D) (B ^ C ^ D) #define F4(B, C, D) (B ^ C ^ D)
/* Process LEN bytes of BUFFER, accumulating context into CTX. /* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0. It is assumed that LEN % 64 == 0.
Most of this code comes from GnuPG's cipher/sha1.c. */ Most of this code comes from GnuPG's cipher/sha1.c. */
void void sha1_process_block(const void* buffer, size_t len, struct sha1_ctx* ctx) {
sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) const uint32_t* words = buffer;
{ size_t nwords = len / sizeof(uint32_t);
const uint32_t *words = buffer; const uint32_t* endp = words + nwords;
size_t nwords = len / sizeof (uint32_t); uint32_t x[16];
const uint32_t *endp = words + nwords; uint32_t a = ctx->A;
uint32_t x[16]; uint32_t b = ctx->B;
uint32_t a = ctx->A; uint32_t c = ctx->C;
uint32_t b = ctx->B; uint32_t d = ctx->D;
uint32_t c = ctx->C; uint32_t e = ctx->E;
uint32_t d = ctx->D; uint32_t lolen = len;
uint32_t e = ctx->E;
uint32_t lolen = len;
/* First increment the byte count. RFC 1321 specifies the possible /* First increment the byte count. RFC 1321 specifies the possible
length of the file up to 2^64 bits. Here we only compute the length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */ number of bytes. Do a double word increment. */
ctx->total[0] += lolen; ctx->total[0] += lolen;
ctx->total[1] += (len >> 31 >> 1) + (ctx->total[0] < lolen); ctx->total[1] += (len >> 31 >> 1) + (ctx->total[0] < lolen);
#define rol(x, n) (((x) << (n)) | ((uint32_t) (x) >> (32 - (n)))) #define rol(x, n) (((x) << (n)) | ((uint32_t)(x) >> (32 - (n))))
#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ #define M(I) \
^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ (tm = x[I & 0x0f] ^ x[(I - 14) & 0x0f] ^ x[(I - 8) & 0x0f] ^ x[(I - 3) & 0x0f], \
, (x[I&0x0f] = rol(tm, 1)) ) (x[I & 0x0f] = rol(tm, 1)))
#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \ #define R(A, B, C, D, E, F, K, M) \
+ F( B, C, D ) \ do { \
+ K \ E += rol(A, 5) + F(B, C, D) + K + M; \
+ M; \ B = rol(B, 30); \
B = rol( B, 30 ); \ } while(0)
} while(0)
while (words < endp) while(words < endp) {
{ uint32_t tm;
uint32_t tm; int t;
int t; for(t = 0; t < 16; t++) {
for (t = 0; t < 16; t++) x[t] = SWAP(*words);
{ words++;
x[t] = SWAP (*words);
words++;
} }
R( a, b, c, d, e, F1, K1, x[ 0] ); R(a, b, c, d, e, F1, K1, x[0]);
R( e, a, b, c, d, F1, K1, x[ 1] ); R(e, a, b, c, d, F1, K1, x[1]);
R( d, e, a, b, c, F1, K1, x[ 2] ); R(d, e, a, b, c, F1, K1, x[2]);
R( c, d, e, a, b, F1, K1, x[ 3] ); R(c, d, e, a, b, F1, K1, x[3]);
R( b, c, d, e, a, F1, K1, x[ 4] ); R(b, c, d, e, a, F1, K1, x[4]);
R( a, b, c, d, e, F1, K1, x[ 5] ); R(a, b, c, d, e, F1, K1, x[5]);
R( e, a, b, c, d, F1, K1, x[ 6] ); R(e, a, b, c, d, F1, K1, x[6]);
R( d, e, a, b, c, F1, K1, x[ 7] ); R(d, e, a, b, c, F1, K1, x[7]);
R( c, d, e, a, b, F1, K1, x[ 8] ); R(c, d, e, a, b, F1, K1, x[8]);
R( b, c, d, e, a, F1, K1, x[ 9] ); R(b, c, d, e, a, F1, K1, x[9]);
R( a, b, c, d, e, F1, K1, x[10] ); R(a, b, c, d, e, F1, K1, x[10]);
R( e, a, b, c, d, F1, K1, x[11] ); R(e, a, b, c, d, F1, K1, x[11]);
R( d, e, a, b, c, F1, K1, x[12] ); R(d, e, a, b, c, F1, K1, x[12]);
R( c, d, e, a, b, F1, K1, x[13] ); R(c, d, e, a, b, F1, K1, x[13]);
R( b, c, d, e, a, F1, K1, x[14] ); R(b, c, d, e, a, F1, K1, x[14]);
R( a, b, c, d, e, F1, K1, x[15] ); R(a, b, c, d, e, F1, K1, x[15]);
R( e, a, b, c, d, F1, K1, M(16) ); R(e, a, b, c, d, F1, K1, M(16));
R( d, e, a, b, c, F1, K1, M(17) ); R(d, e, a, b, c, F1, K1, M(17));
R( c, d, e, a, b, F1, K1, M(18) ); R(c, d, e, a, b, F1, K1, M(18));
R( b, c, d, e, a, F1, K1, M(19) ); R(b, c, d, e, a, F1, K1, M(19));
R( a, b, c, d, e, F2, K2, M(20) ); R(a, b, c, d, e, F2, K2, M(20));
R( e, a, b, c, d, F2, K2, M(21) ); R(e, a, b, c, d, F2, K2, M(21));
R( d, e, a, b, c, F2, K2, M(22) ); R(d, e, a, b, c, F2, K2, M(22));
R( c, d, e, a, b, F2, K2, M(23) ); R(c, d, e, a, b, F2, K2, M(23));
R( b, c, d, e, a, F2, K2, M(24) ); R(b, c, d, e, a, F2, K2, M(24));
R( a, b, c, d, e, F2, K2, M(25) ); R(a, b, c, d, e, F2, K2, M(25));
R( e, a, b, c, d, F2, K2, M(26) ); R(e, a, b, c, d, F2, K2, M(26));
R( d, e, a, b, c, F2, K2, M(27) ); R(d, e, a, b, c, F2, K2, M(27));
R( c, d, e, a, b, F2, K2, M(28) ); R(c, d, e, a, b, F2, K2, M(28));
R( b, c, d, e, a, F2, K2, M(29) ); R(b, c, d, e, a, F2, K2, M(29));
R( a, b, c, d, e, F2, K2, M(30) ); R(a, b, c, d, e, F2, K2, M(30));
R( e, a, b, c, d, F2, K2, M(31) ); R(e, a, b, c, d, F2, K2, M(31));
R( d, e, a, b, c, F2, K2, M(32) ); R(d, e, a, b, c, F2, K2, M(32));
R( c, d, e, a, b, F2, K2, M(33) ); R(c, d, e, a, b, F2, K2, M(33));
R( b, c, d, e, a, F2, K2, M(34) ); R(b, c, d, e, a, F2, K2, M(34));
R( a, b, c, d, e, F2, K2, M(35) ); R(a, b, c, d, e, F2, K2, M(35));
R( e, a, b, c, d, F2, K2, M(36) ); R(e, a, b, c, d, F2, K2, M(36));
R( d, e, a, b, c, F2, K2, M(37) ); R(d, e, a, b, c, F2, K2, M(37));
R( c, d, e, a, b, F2, K2, M(38) ); R(c, d, e, a, b, F2, K2, M(38));
R( b, c, d, e, a, F2, K2, M(39) ); R(b, c, d, e, a, F2, K2, M(39));
R( a, b, c, d, e, F3, K3, M(40) ); R(a, b, c, d, e, F3, K3, M(40));
R( e, a, b, c, d, F3, K3, M(41) ); R(e, a, b, c, d, F3, K3, M(41));
R( d, e, a, b, c, F3, K3, M(42) ); R(d, e, a, b, c, F3, K3, M(42));
R( c, d, e, a, b, F3, K3, M(43) ); R(c, d, e, a, b, F3, K3, M(43));
R( b, c, d, e, a, F3, K3, M(44) ); R(b, c, d, e, a, F3, K3, M(44));
R( a, b, c, d, e, F3, K3, M(45) ); R(a, b, c, d, e, F3, K3, M(45));
R( e, a, b, c, d, F3, K3, M(46) ); R(e, a, b, c, d, F3, K3, M(46));
R( d, e, a, b, c, F3, K3, M(47) ); R(d, e, a, b, c, F3, K3, M(47));
R( c, d, e, a, b, F3, K3, M(48) ); R(c, d, e, a, b, F3, K3, M(48));
R( b, c, d, e, a, F3, K3, M(49) ); R(b, c, d, e, a, F3, K3, M(49));
R( a, b, c, d, e, F3, K3, M(50) ); R(a, b, c, d, e, F3, K3, M(50));
R( e, a, b, c, d, F3, K3, M(51) ); R(e, a, b, c, d, F3, K3, M(51));
R( d, e, a, b, c, F3, K3, M(52) ); R(d, e, a, b, c, F3, K3, M(52));
R( c, d, e, a, b, F3, K3, M(53) ); R(c, d, e, a, b, F3, K3, M(53));
R( b, c, d, e, a, F3, K3, M(54) ); R(b, c, d, e, a, F3, K3, M(54));
R( a, b, c, d, e, F3, K3, M(55) ); R(a, b, c, d, e, F3, K3, M(55));
R( e, a, b, c, d, F3, K3, M(56) ); R(e, a, b, c, d, F3, K3, M(56));
R( d, e, a, b, c, F3, K3, M(57) ); R(d, e, a, b, c, F3, K3, M(57));
R( c, d, e, a, b, F3, K3, M(58) ); R(c, d, e, a, b, F3, K3, M(58));
R( b, c, d, e, a, F3, K3, M(59) ); R(b, c, d, e, a, F3, K3, M(59));
R( a, b, c, d, e, F4, K4, M(60) ); R(a, b, c, d, e, F4, K4, M(60));
R( e, a, b, c, d, F4, K4, M(61) ); R(e, a, b, c, d, F4, K4, M(61));
R( d, e, a, b, c, F4, K4, M(62) ); R(d, e, a, b, c, F4, K4, M(62));
R( c, d, e, a, b, F4, K4, M(63) ); R(c, d, e, a, b, F4, K4, M(63));
R( b, c, d, e, a, F4, K4, M(64) ); R(b, c, d, e, a, F4, K4, M(64));
R( a, b, c, d, e, F4, K4, M(65) ); R(a, b, c, d, e, F4, K4, M(65));
R( e, a, b, c, d, F4, K4, M(66) ); R(e, a, b, c, d, F4, K4, M(66));
R( d, e, a, b, c, F4, K4, M(67) ); R(d, e, a, b, c, F4, K4, M(67));
R( c, d, e, a, b, F4, K4, M(68) ); R(c, d, e, a, b, F4, K4, M(68));
R( b, c, d, e, a, F4, K4, M(69) ); R(b, c, d, e, a, F4, K4, M(69));
R( a, b, c, d, e, F4, K4, M(70) ); R(a, b, c, d, e, F4, K4, M(70));
R( e, a, b, c, d, F4, K4, M(71) ); R(e, a, b, c, d, F4, K4, M(71));
R( d, e, a, b, c, F4, K4, M(72) ); R(d, e, a, b, c, F4, K4, M(72));
R( c, d, e, a, b, F4, K4, M(73) ); R(c, d, e, a, b, F4, K4, M(73));
R( b, c, d, e, a, F4, K4, M(74) ); R(b, c, d, e, a, F4, K4, M(74));
R( a, b, c, d, e, F4, K4, M(75) ); R(a, b, c, d, e, F4, K4, M(75));
R( e, a, b, c, d, F4, K4, M(76) ); R(e, a, b, c, d, F4, K4, M(76));
R( d, e, a, b, c, F4, K4, M(77) ); R(d, e, a, b, c, F4, K4, M(77));
R( c, d, e, a, b, F4, K4, M(78) ); R(c, d, e, a, b, F4, K4, M(78));
R( b, c, d, e, a, F4, K4, M(79) ); R(b, c, d, e, a, F4, K4, M(79));
a = ctx->A += a; a = ctx->A += a;
b = ctx->B += b; b = ctx->B += b;
c = ctx->C += c; c = ctx->C += c;
d = ctx->D += d; d = ctx->D += d;
e = ctx->E += e; e = ctx->E += e;
} }
} }

View File

@@ -18,78 +18,72 @@
#pragma once #pragma once
# include <stdio.h> #include <stdio.h>
# include <stdint.h> #include <stdint.h>
# if HAVE_OPENSSL_SHA1 #if HAVE_OPENSSL_SHA1
# ifndef OPENSSL_API_COMPAT #ifndef OPENSSL_API_COMPAT
# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */ #define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
# endif #endif
# include <openssl/sha.h> #include <openssl/sha.h>
# endif #endif
# ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
# endif #endif
# define SHA1_DIGEST_SIZE 20 #define SHA1_DIGEST_SIZE 20
# if HAVE_OPENSSL_SHA1 #if HAVE_OPENSSL_SHA1
# define GL_OPENSSL_NAME 1 #define GL_OPENSSL_NAME 1
# include "gl_openssl.h" #include "gl_openssl.h"
# else #else
/* Structure to save state of computation between the single steps. */ /* Structure to save state of computation between the single steps. */
struct sha1_ctx struct sha1_ctx {
{ uint32_t A;
uint32_t A; uint32_t B;
uint32_t B; uint32_t C;
uint32_t C; uint32_t D;
uint32_t D; uint32_t E;
uint32_t E;
uint32_t total[2]; uint32_t total[2];
uint32_t buflen; /* ≥ 0, ≤ 128 */ uint32_t buflen; /* ≥ 0, ≤ 128 */
uint32_t buffer[32]; /* 128 bytes; the first buflen bytes are in use */ uint32_t buffer[32]; /* 128 bytes; the first buflen bytes are in use */
}; };
/* Initialize structure containing state of computation. */ /* Initialize structure containing state of computation. */
extern void sha1_init_ctx (struct sha1_ctx *ctx); extern void sha1_init_ctx(struct sha1_ctx* ctx);
/* Starting with the result of former calls of this function (or the /* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes initialization function update the context for the next LEN bytes
starting at BUFFER. starting at BUFFER.
It is necessary that LEN is a multiple of 64!!! */ It is necessary that LEN is a multiple of 64!!! */
extern void sha1_process_block (const void *buffer, size_t len, extern void sha1_process_block(const void* buffer, size_t len, struct sha1_ctx* ctx);
struct sha1_ctx *ctx);
/* Starting with the result of former calls of this function (or the /* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes initialization function update the context for the next LEN bytes
starting at BUFFER. starting at BUFFER.
It is NOT required that LEN is a multiple of 64. */ It is NOT required that LEN is a multiple of 64. */
extern void sha1_process_bytes (const void *buffer, size_t len, extern void sha1_process_bytes(const void* buffer, size_t len, struct sha1_ctx* ctx);
struct sha1_ctx *ctx);
/* Process the remaining bytes in the buffer and put result from CTX /* Process the remaining bytes in the buffer and put result from CTX
in first 20 bytes following RESBUF. The result is always in little in first 20 bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest. */ ASCII representation of the message digest. */
extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *restrict resbuf); extern void* sha1_finish_ctx(struct sha1_ctx* ctx, void* restrict resbuf);
/* Put result from CTX in first 20 bytes following RESBUF. The result is /* Put result from CTX in first 20 bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields always in little endian byte order, so that a byte-wise output yields
to the wanted ASCII representation of the message digest. */ to the wanted ASCII representation of the message digest. */
extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *restrict resbuf); extern void* sha1_read_ctx(const struct sha1_ctx* ctx, void* restrict resbuf);
/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The /* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message output yields to the wanted ASCII representation of the message
digest. */ digest. */
extern void *sha1_buffer (const char *buffer, size_t len, extern void* sha1_buffer(const char* buffer, size_t len, void* restrict resblock);
void *restrict resblock);
# endif #endif
/* Compute SHA1 message digest for bytes read from STREAM. /* Compute SHA1 message digest for bytes read from STREAM.
STREAM is an open file stream. Regular files are handled more efficiently. STREAM is an open file stream. Regular files are handled more efficiently.
@@ -97,12 +91,11 @@ extern void *sha1_buffer (const char *buffer, size_t len,
The case that the last operation on STREAM was an 'ungetc' is not supported. The case that the last operation on STREAM was an 'ungetc' is not supported.
The resulting message digest number will be written into the 20 bytes The resulting message digest number will be written into the 20 bytes
beginning at RESBLOCK. */ beginning at RESBLOCK. */
extern int sha1_stream (FILE *stream, void *resblock); extern int sha1_stream(FILE* stream, void* resblock);
#ifdef __cplusplus
# ifdef __cplusplus
} }
# endif #endif
/* /*
* Hey Emacs! * Hey Emacs!

View File

@@ -22,7 +22,7 @@
/* Specification. */ /* Specification. */
#if HAVE_OPENSSL_SHA256 #if HAVE_OPENSSL_SHA256
# define GL_OPENSSL_INLINE _GL_EXTERN_INLINE #define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
#endif #endif
#include "sha256.h" #include "sha256.h"
@@ -30,233 +30,197 @@
#include <string.h> #include <string.h>
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
# define SWAP(n) (n) #define SWAP(n) (n)
#else #else
#include "byteswap.h" #include "byteswap.h"
# define SWAP(n) swap_uint32 (n) #define SWAP(n) swap_uint32(n)
#endif #endif
#if ! HAVE_OPENSSL_SHA256 #if !HAVE_OPENSSL_SHA256
/* This array contains the bytes used to pad the buffer to the next /* This array contains the bytes used to pad the buffer to the next
64-byte boundary. */ 64-byte boundary. */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; static const unsigned char fillbuf[64] = {0x80, 0 /* , 0, 0, ... */};
/* /*
Takes a pointer to a 256 bit block of data (eight 32 bit ints) and Takes a pointer to a 256 bit block of data (eight 32 bit ints) and
initializes it to the start constants of the SHA256 algorithm. This initializes it to the start constants of the SHA256 algorithm. This
must be called before using hash in the call to sha256_hash must be called before using hash in the call to sha256_hash
*/ */
void void sha256_init_ctx(struct sha256_ctx* ctx) {
sha256_init_ctx (struct sha256_ctx *ctx) ctx->state[0] = 0x6a09e667UL;
{ ctx->state[1] = 0xbb67ae85UL;
ctx->state[0] = 0x6a09e667UL; ctx->state[2] = 0x3c6ef372UL;
ctx->state[1] = 0xbb67ae85UL; ctx->state[3] = 0xa54ff53aUL;
ctx->state[2] = 0x3c6ef372UL; ctx->state[4] = 0x510e527fUL;
ctx->state[3] = 0xa54ff53aUL; ctx->state[5] = 0x9b05688cUL;
ctx->state[4] = 0x510e527fUL; ctx->state[6] = 0x1f83d9abUL;
ctx->state[5] = 0x9b05688cUL; ctx->state[7] = 0x5be0cd19UL;
ctx->state[6] = 0x1f83d9abUL;
ctx->state[7] = 0x5be0cd19UL;
ctx->total[0] = ctx->total[1] = 0; ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0; ctx->buflen = 0;
} }
void void sha224_init_ctx(struct sha256_ctx* ctx) {
sha224_init_ctx (struct sha256_ctx *ctx) ctx->state[0] = 0xc1059ed8UL;
{ ctx->state[1] = 0x367cd507UL;
ctx->state[0] = 0xc1059ed8UL; ctx->state[2] = 0x3070dd17UL;
ctx->state[1] = 0x367cd507UL; ctx->state[3] = 0xf70e5939UL;
ctx->state[2] = 0x3070dd17UL; ctx->state[4] = 0xffc00b31UL;
ctx->state[3] = 0xf70e5939UL; ctx->state[5] = 0x68581511UL;
ctx->state[4] = 0xffc00b31UL; ctx->state[6] = 0x64f98fa7UL;
ctx->state[5] = 0x68581511UL; ctx->state[7] = 0xbefa4fa4UL;
ctx->state[6] = 0x64f98fa7UL;
ctx->state[7] = 0xbefa4fa4UL;
ctx->total[0] = ctx->total[1] = 0; ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0; ctx->buflen = 0;
} }
/* Copy the value from v into the memory location pointed to by *CP, /* Copy the value from v into the memory location pointed to by *CP,
If your architecture allows unaligned access, this is equivalent to If your architecture allows unaligned access, this is equivalent to
* (__typeof__ (v) *) cp = v */ * (__typeof__ (v) *) cp = v */
static void static void set_uint32(char* cp, uint32_t v) {
set_uint32 (char *cp, uint32_t v) memcpy(cp, &v, sizeof v);
{
memcpy (cp, &v, sizeof v);
} }
/* Put result from CTX in first 32 bytes following RESBUF. /* Put result from CTX in first 32 bytes following RESBUF.
The result must be in little endian byte order. */ The result must be in little endian byte order. */
void * void* sha256_read_ctx(const struct sha256_ctx* ctx, void* resbuf) {
sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf) int i;
{ char* r = resbuf;
int i;
char *r = resbuf;
for (i = 0; i < 8; i++) for(i = 0; i < 8; i++) set_uint32(r + i * sizeof ctx->state[0], SWAP(ctx->state[i]));
set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i]));
return resbuf; return resbuf;
} }
void * void* sha224_read_ctx(const struct sha256_ctx* ctx, void* resbuf) {
sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf) int i;
{ char* r = resbuf;
int i;
char *r = resbuf;
for (i = 0; i < 7; i++) for(i = 0; i < 7; i++) set_uint32(r + i * sizeof ctx->state[0], SWAP(ctx->state[i]));
set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i]));
return resbuf; return resbuf;
} }
/* Process the remaining bytes in the internal buffer and the usual /* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF. */ prolog according to the standard and write the result to RESBUF. */
static void static void sha256_conclude_ctx(struct sha256_ctx* ctx) {
sha256_conclude_ctx (struct sha256_ctx *ctx) /* Take yet unprocessed bytes into account. */
{ size_t bytes = ctx->buflen;
/* Take yet unprocessed bytes into account. */ size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
size_t bytes = ctx->buflen;
size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
/* Now count remaining bytes. */ /* Now count remaining bytes. */
ctx->total[0] += bytes; ctx->total[0] += bytes;
if (ctx->total[0] < bytes) if(ctx->total[0] < bytes) ++ctx->total[1];
++ctx->total[1];
/* Put the 64-bit file length in *bits* at the end of the buffer. /* Put the 64-bit file length in *bits* at the end of the buffer.
Use set_uint32 rather than a simple assignment, to avoid risk of Use set_uint32 rather than a simple assignment, to avoid risk of
unaligned access. */ unaligned access. */
set_uint32 ((char *) &ctx->buffer[size - 2], set_uint32((char*)&ctx->buffer[size - 2], SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29))); set_uint32((char*)&ctx->buffer[size - 1], SWAP(ctx->total[0] << 3));
set_uint32 ((char *) &ctx->buffer[size - 1],
SWAP (ctx->total[0] << 3));
memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
/* Process last bytes. */ /* Process last bytes. */
sha256_process_block (ctx->buffer, size * 4, ctx); sha256_process_block(ctx->buffer, size * 4, ctx);
} }
void * void* sha256_finish_ctx(struct sha256_ctx* ctx, void* resbuf) {
sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf) sha256_conclude_ctx(ctx);
{ return sha256_read_ctx(ctx, resbuf);
sha256_conclude_ctx (ctx);
return sha256_read_ctx (ctx, resbuf);
} }
void * void* sha224_finish_ctx(struct sha256_ctx* ctx, void* resbuf) {
sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf) sha256_conclude_ctx(ctx);
{ return sha224_read_ctx(ctx, resbuf);
sha256_conclude_ctx (ctx);
return sha224_read_ctx (ctx, resbuf);
} }
/* Compute SHA256 message digest for LEN bytes beginning at BUFFER. The /* Compute SHA256 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message output yields to the wanted ASCII representation of the message
digest. */ digest. */
void * void* sha256_buffer(const char* buffer, size_t len, void* resblock) {
sha256_buffer (const char *buffer, size_t len, void *resblock) struct sha256_ctx ctx;
{
struct sha256_ctx ctx;
/* Initialize the computation context. */ /* Initialize the computation context. */
sha256_init_ctx (&ctx); sha256_init_ctx(&ctx);
/* Process whole buffer but last len % 64 bytes. */ /* Process whole buffer but last len % 64 bytes. */
sha256_process_bytes (buffer, len, &ctx); sha256_process_bytes(buffer, len, &ctx);
/* Put result in desired memory area. */ /* Put result in desired memory area. */
return sha256_finish_ctx (&ctx, resblock); return sha256_finish_ctx(&ctx, resblock);
} }
void * void* sha224_buffer(const char* buffer, size_t len, void* resblock) {
sha224_buffer (const char *buffer, size_t len, void *resblock) struct sha256_ctx ctx;
{
struct sha256_ctx ctx;
/* Initialize the computation context. */ /* Initialize the computation context. */
sha224_init_ctx (&ctx); sha224_init_ctx(&ctx);
/* Process whole buffer but last len % 64 bytes. */ /* Process whole buffer but last len % 64 bytes. */
sha256_process_bytes (buffer, len, &ctx); sha256_process_bytes(buffer, len, &ctx);
/* Put result in desired memory area. */ /* Put result in desired memory area. */
return sha224_finish_ctx (&ctx, resblock); return sha224_finish_ctx(&ctx, resblock);
} }
void void sha256_process_bytes(const void* buffer, size_t len, struct sha256_ctx* ctx) {
sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx) /* When we already have some bits in our internal buffer concatenate
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */ both inputs first. */
if (ctx->buflen != 0) if(ctx->buflen != 0) {
{ size_t left_over = ctx->buflen;
size_t left_over = ctx->buflen; size_t add = 128 - left_over > len ? len : 128 - left_over;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy (&((char *) ctx->buffer)[left_over], buffer, add); memcpy(&((char*)ctx->buffer)[left_over], buffer, add);
ctx->buflen += add; ctx->buflen += add;
if (ctx->buflen > 64) if(ctx->buflen > 64) {
{ sha256_process_block(ctx->buffer, ctx->buflen & ~63, ctx);
sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63; ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap, /* The regions in the following copy operation cannot overlap,
because ctx->buflen < 64 ≤ (left_over + add) & ~63. */ because ctx->buflen < 64 ≤ (left_over + add) & ~63. */
memcpy (ctx->buffer, memcpy(ctx->buffer, &((char*)ctx->buffer)[(left_over + add) & ~63], ctx->buflen);
&((char *) ctx->buffer)[(left_over + add) & ~63],
ctx->buflen);
} }
buffer = (const char *) buffer + add; buffer = (const char*)buffer + add;
len -= add; len -= add;
} }
/* Process available complete blocks. */ /* Process available complete blocks. */
if (len >= 64) if(len >= 64) {
{
#if !(_STRING_ARCH_unaligned || _STRING_INLINE_unaligned) #if !(_STRING_ARCH_unaligned || _STRING_INLINE_unaligned)
# define UNALIGNED_P(p) ((uintptr_t) (p) % sizeof (uint32_t) != 0) #define UNALIGNED_P(p) ((uintptr_t)(p) % sizeof(uint32_t) != 0)
if (UNALIGNED_P (buffer)) if(UNALIGNED_P(buffer))
while (len > 64) while(len > 64) {
{ sha256_process_block(memcpy(ctx->buffer, buffer, 64), 64, ctx);
sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); buffer = (const char*)buffer + 64;
buffer = (const char *) buffer + 64; len -= 64;
len -= 64; }
} else
else
#endif #endif
{ {
sha256_process_block (buffer, len & ~63, ctx); sha256_process_block(buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63); buffer = (const char*)buffer + (len & ~63);
len &= 63; len &= 63;
} }
} }
/* Move remaining bytes in internal buffer. */ /* Move remaining bytes in internal buffer. */
if (len > 0) if(len > 0) {
{ size_t left_over = ctx->buflen;
size_t left_over = ctx->buflen;
memcpy (&((char *) ctx->buffer)[left_over], buffer, len); memcpy(&((char*)ctx->buffer)[left_over], buffer, len);
left_over += len; left_over += len;
if (left_over >= 64) if(left_over >= 64) {
{ sha256_process_block(ctx->buffer, 64, ctx);
sha256_process_block (ctx->buffer, 64, ctx); left_over -= 64;
left_over -= 64; /* The regions in the following copy operation cannot overlap,
/* The regions in the following copy operation cannot overlap,
because left_over ≤ 64. */ because left_over ≤ 64. */
memcpy (ctx->buffer, &ctx->buffer[16], left_over); memcpy(ctx->buffer, &ctx->buffer[16], left_over);
} }
ctx->buflen = left_over; ctx->buflen = left_over;
} }
} }
@@ -265,158 +229,149 @@ sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx)
/* SHA256 round constants */ /* SHA256 round constants */
#define K(I) sha256_round_constants[I] #define K(I) sha256_round_constants[I]
static const uint32_t sha256_round_constants[64] = { static const uint32_t sha256_round_constants[64] = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL,
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL,
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL,
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL,
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
}; };
/* Round functions. */ /* Round functions. */
#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) ) #define F2(A, B, C) ((A & B) | (C & (A | B)))
#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) ) #define F1(E, F, G) (G ^ (E & (F ^ G)))
/* Process LEN bytes of BUFFER, accumulating context into CTX. /* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0. It is assumed that LEN % 64 == 0.
Most of this code comes from GnuPG's cipher/sha1.c. */ Most of this code comes from GnuPG's cipher/sha1.c. */
void void sha256_process_block(const void* buffer, size_t len, struct sha256_ctx* ctx) {
sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx) const uint32_t* words = buffer;
{ size_t nwords = len / sizeof(uint32_t);
const uint32_t *words = buffer; const uint32_t* endp = words + nwords;
size_t nwords = len / sizeof (uint32_t); uint32_t x[16];
const uint32_t *endp = words + nwords; uint32_t a = ctx->state[0];
uint32_t x[16]; uint32_t b = ctx->state[1];
uint32_t a = ctx->state[0]; uint32_t c = ctx->state[2];
uint32_t b = ctx->state[1]; uint32_t d = ctx->state[3];
uint32_t c = ctx->state[2]; uint32_t e = ctx->state[4];
uint32_t d = ctx->state[3]; uint32_t f = ctx->state[5];
uint32_t e = ctx->state[4]; uint32_t g = ctx->state[6];
uint32_t f = ctx->state[5]; uint32_t h = ctx->state[7];
uint32_t g = ctx->state[6]; uint32_t lolen = len;
uint32_t h = ctx->state[7];
uint32_t lolen = len;
/* First increment the byte count. FIPS PUB 180-2 specifies the possible /* First increment the byte count. FIPS PUB 180-2 specifies the possible
length of the file up to 2^64 bits. Here we only compute the length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */ number of bytes. Do a double word increment. */
ctx->total[0] += lolen; ctx->total[0] += lolen;
ctx->total[1] += (len >> 31 >> 1) + (ctx->total[0] < lolen); ctx->total[1] += (len >> 31 >> 1) + (ctx->total[0] < lolen);
#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) #define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
#define S0(x) (rol(x,25)^rol(x,14)^(x>>3)) #define S0(x) (rol(x, 25) ^ rol(x, 14) ^ (x >> 3))
#define S1(x) (rol(x,15)^rol(x,13)^(x>>10)) #define S1(x) (rol(x, 15) ^ rol(x, 13) ^ (x >> 10))
#define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10)) #define SS0(x) (rol(x, 30) ^ rol(x, 19) ^ rol(x, 10))
#define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7)) #define SS1(x) (rol(x, 26) ^ rol(x, 21) ^ rol(x, 7))
#define M(I) ( tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] \ #define M(I) \
+ S0(x[(I-15)&0x0f]) + x[I&0x0f] \ (tm = S1(x[(I - 2) & 0x0f]) + x[(I - 7) & 0x0f] + S0(x[(I - 15) & 0x0f]) + x[I & 0x0f], \
, x[I&0x0f] = tm ) x[I & 0x0f] = tm)
#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \ #define R(A, B, C, D, E, F, G, H, K, M) \
t1 = H + SS1(E) \ do { \
+ F1(E,F,G) \ t0 = SS0(A) + F2(A, B, C); \
+ K \ t1 = H + SS1(E) + F1(E, F, G) + K + M; \
+ M; \ D += t1; \
D += t1; H = t0 + t1; \ H = t0 + t1; \
} while(0) } while(0)
while (words < endp) while(words < endp) {
{ uint32_t tm;
uint32_t tm; uint32_t t0, t1;
uint32_t t0, t1; int t;
int t; /* FIXME: see sha1.c for a better implementation. */
/* FIXME: see sha1.c for a better implementation. */ for(t = 0; t < 16; t++) {
for (t = 0; t < 16; t++) x[t] = SWAP(*words);
{ words++;
x[t] = SWAP (*words);
words++;
} }
R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); R(a, b, c, d, e, f, g, h, K(0), x[0]);
R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); R(h, a, b, c, d, e, f, g, K(1), x[1]);
R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); R(g, h, a, b, c, d, e, f, K(2), x[2]);
R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); R(f, g, h, a, b, c, d, e, K(3), x[3]);
R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); R(e, f, g, h, a, b, c, d, K(4), x[4]);
R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); R(d, e, f, g, h, a, b, c, K(5), x[5]);
R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); R(c, d, e, f, g, h, a, b, K(6), x[6]);
R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); R(b, c, d, e, f, g, h, a, K(7), x[7]);
R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); R(a, b, c, d, e, f, g, h, K(8), x[8]);
R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); R(h, a, b, c, d, e, f, g, K(9), x[9]);
R( g, h, a, b, c, d, e, f, K(10), x[10] ); R(g, h, a, b, c, d, e, f, K(10), x[10]);
R( f, g, h, a, b, c, d, e, K(11), x[11] ); R(f, g, h, a, b, c, d, e, K(11), x[11]);
R( e, f, g, h, a, b, c, d, K(12), x[12] ); R(e, f, g, h, a, b, c, d, K(12), x[12]);
R( d, e, f, g, h, a, b, c, K(13), x[13] ); R(d, e, f, g, h, a, b, c, K(13), x[13]);
R( c, d, e, f, g, h, a, b, K(14), x[14] ); R(c, d, e, f, g, h, a, b, K(14), x[14]);
R( b, c, d, e, f, g, h, a, K(15), x[15] ); R(b, c, d, e, f, g, h, a, K(15), x[15]);
R( a, b, c, d, e, f, g, h, K(16), M(16) ); R(a, b, c, d, e, f, g, h, K(16), M(16));
R( h, a, b, c, d, e, f, g, K(17), M(17) ); R(h, a, b, c, d, e, f, g, K(17), M(17));
R( g, h, a, b, c, d, e, f, K(18), M(18) ); R(g, h, a, b, c, d, e, f, K(18), M(18));
R( f, g, h, a, b, c, d, e, K(19), M(19) ); R(f, g, h, a, b, c, d, e, K(19), M(19));
R( e, f, g, h, a, b, c, d, K(20), M(20) ); R(e, f, g, h, a, b, c, d, K(20), M(20));
R( d, e, f, g, h, a, b, c, K(21), M(21) ); R(d, e, f, g, h, a, b, c, K(21), M(21));
R( c, d, e, f, g, h, a, b, K(22), M(22) ); R(c, d, e, f, g, h, a, b, K(22), M(22));
R( b, c, d, e, f, g, h, a, K(23), M(23) ); R(b, c, d, e, f, g, h, a, K(23), M(23));
R( a, b, c, d, e, f, g, h, K(24), M(24) ); R(a, b, c, d, e, f, g, h, K(24), M(24));
R( h, a, b, c, d, e, f, g, K(25), M(25) ); R(h, a, b, c, d, e, f, g, K(25), M(25));
R( g, h, a, b, c, d, e, f, K(26), M(26) ); R(g, h, a, b, c, d, e, f, K(26), M(26));
R( f, g, h, a, b, c, d, e, K(27), M(27) ); R(f, g, h, a, b, c, d, e, K(27), M(27));
R( e, f, g, h, a, b, c, d, K(28), M(28) ); R(e, f, g, h, a, b, c, d, K(28), M(28));
R( d, e, f, g, h, a, b, c, K(29), M(29) ); R(d, e, f, g, h, a, b, c, K(29), M(29));
R( c, d, e, f, g, h, a, b, K(30), M(30) ); R(c, d, e, f, g, h, a, b, K(30), M(30));
R( b, c, d, e, f, g, h, a, K(31), M(31) ); R(b, c, d, e, f, g, h, a, K(31), M(31));
R( a, b, c, d, e, f, g, h, K(32), M(32) ); R(a, b, c, d, e, f, g, h, K(32), M(32));
R( h, a, b, c, d, e, f, g, K(33), M(33) ); R(h, a, b, c, d, e, f, g, K(33), M(33));
R( g, h, a, b, c, d, e, f, K(34), M(34) ); R(g, h, a, b, c, d, e, f, K(34), M(34));
R( f, g, h, a, b, c, d, e, K(35), M(35) ); R(f, g, h, a, b, c, d, e, K(35), M(35));
R( e, f, g, h, a, b, c, d, K(36), M(36) ); R(e, f, g, h, a, b, c, d, K(36), M(36));
R( d, e, f, g, h, a, b, c, K(37), M(37) ); R(d, e, f, g, h, a, b, c, K(37), M(37));
R( c, d, e, f, g, h, a, b, K(38), M(38) ); R(c, d, e, f, g, h, a, b, K(38), M(38));
R( b, c, d, e, f, g, h, a, K(39), M(39) ); R(b, c, d, e, f, g, h, a, K(39), M(39));
R( a, b, c, d, e, f, g, h, K(40), M(40) ); R(a, b, c, d, e, f, g, h, K(40), M(40));
R( h, a, b, c, d, e, f, g, K(41), M(41) ); R(h, a, b, c, d, e, f, g, K(41), M(41));
R( g, h, a, b, c, d, e, f, K(42), M(42) ); R(g, h, a, b, c, d, e, f, K(42), M(42));
R( f, g, h, a, b, c, d, e, K(43), M(43) ); R(f, g, h, a, b, c, d, e, K(43), M(43));
R( e, f, g, h, a, b, c, d, K(44), M(44) ); R(e, f, g, h, a, b, c, d, K(44), M(44));
R( d, e, f, g, h, a, b, c, K(45), M(45) ); R(d, e, f, g, h, a, b, c, K(45), M(45));
R( c, d, e, f, g, h, a, b, K(46), M(46) ); R(c, d, e, f, g, h, a, b, K(46), M(46));
R( b, c, d, e, f, g, h, a, K(47), M(47) ); R(b, c, d, e, f, g, h, a, K(47), M(47));
R( a, b, c, d, e, f, g, h, K(48), M(48) ); R(a, b, c, d, e, f, g, h, K(48), M(48));
R( h, a, b, c, d, e, f, g, K(49), M(49) ); R(h, a, b, c, d, e, f, g, K(49), M(49));
R( g, h, a, b, c, d, e, f, K(50), M(50) ); R(g, h, a, b, c, d, e, f, K(50), M(50));
R( f, g, h, a, b, c, d, e, K(51), M(51) ); R(f, g, h, a, b, c, d, e, K(51), M(51));
R( e, f, g, h, a, b, c, d, K(52), M(52) ); R(e, f, g, h, a, b, c, d, K(52), M(52));
R( d, e, f, g, h, a, b, c, K(53), M(53) ); R(d, e, f, g, h, a, b, c, K(53), M(53));
R( c, d, e, f, g, h, a, b, K(54), M(54) ); R(c, d, e, f, g, h, a, b, K(54), M(54));
R( b, c, d, e, f, g, h, a, K(55), M(55) ); R(b, c, d, e, f, g, h, a, K(55), M(55));
R( a, b, c, d, e, f, g, h, K(56), M(56) ); R(a, b, c, d, e, f, g, h, K(56), M(56));
R( h, a, b, c, d, e, f, g, K(57), M(57) ); R(h, a, b, c, d, e, f, g, K(57), M(57));
R( g, h, a, b, c, d, e, f, K(58), M(58) ); R(g, h, a, b, c, d, e, f, K(58), M(58));
R( f, g, h, a, b, c, d, e, K(59), M(59) ); R(f, g, h, a, b, c, d, e, K(59), M(59));
R( e, f, g, h, a, b, c, d, K(60), M(60) ); R(e, f, g, h, a, b, c, d, K(60), M(60));
R( d, e, f, g, h, a, b, c, K(61), M(61) ); R(d, e, f, g, h, a, b, c, K(61), M(61));
R( c, d, e, f, g, h, a, b, K(62), M(62) ); R(c, d, e, f, g, h, a, b, K(62), M(62));
R( b, c, d, e, f, g, h, a, K(63), M(63) ); R(b, c, d, e, f, g, h, a, K(63), M(63));
a = ctx->state[0] += a; a = ctx->state[0] += a;
b = ctx->state[1] += b; b = ctx->state[1] += b;
c = ctx->state[2] += c; c = ctx->state[2] += c;
d = ctx->state[3] += d; d = ctx->state[3] += d;
e = ctx->state[4] += e; e = ctx->state[4] += e;
f = ctx->state[5] += f; f = ctx->state[5] += f;
g = ctx->state[6] += g; g = ctx->state[6] += g;
h = ctx->state[7] += h; h = ctx->state[7] += h;
} }
} }

View File

@@ -17,84 +17,75 @@
#pragma once #pragma once
# include <stdio.h> #include <stdio.h>
# include <stdint.h> #include <stdint.h>
# if HAVE_OPENSSL_SHA256 #if HAVE_OPENSSL_SHA256
# ifndef OPENSSL_API_COMPAT #ifndef OPENSSL_API_COMPAT
# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */ #define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
# endif #endif
# include <openssl/sha.h> #include <openssl/sha.h>
# endif #endif
# ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
# endif #endif
enum { SHA224_DIGEST_SIZE = 224 / 8 }; enum { SHA224_DIGEST_SIZE = 224 / 8 };
enum { SHA256_DIGEST_SIZE = 256 / 8 }; enum { SHA256_DIGEST_SIZE = 256 / 8 };
# if HAVE_OPENSSL_SHA256 #if HAVE_OPENSSL_SHA256
# define GL_OPENSSL_NAME 224 #define GL_OPENSSL_NAME 224
# include "gl_openssl.h" #include "gl_openssl.h"
# define GL_OPENSSL_NAME 256 #define GL_OPENSSL_NAME 256
# include "gl_openssl.h" #include "gl_openssl.h"
# else #else
/* Structure to save state of computation between the single steps. */ /* Structure to save state of computation between the single steps. */
struct sha256_ctx struct sha256_ctx {
{ uint32_t state[8];
uint32_t state[8];
uint32_t total[2]; uint32_t total[2];
size_t buflen; /* ≥ 0, ≤ 128 */ size_t buflen; /* ≥ 0, ≤ 128 */
uint32_t buffer[32]; /* 128 bytes; the first buflen bytes are in use */ uint32_t buffer[32]; /* 128 bytes; the first buflen bytes are in use */
}; };
/* Initialize structure containing state of computation. */ /* Initialize structure containing state of computation. */
extern void sha256_init_ctx (struct sha256_ctx *ctx); extern void sha256_init_ctx(struct sha256_ctx* ctx);
extern void sha224_init_ctx (struct sha256_ctx *ctx); extern void sha224_init_ctx(struct sha256_ctx* ctx);
/* Starting with the result of former calls of this function (or the /* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes initialization function update the context for the next LEN bytes
starting at BUFFER. starting at BUFFER.
It is necessary that LEN is a multiple of 64!!! */ It is necessary that LEN is a multiple of 64!!! */
extern void sha256_process_block (const void *buffer, size_t len, extern void sha256_process_block(const void* buffer, size_t len, struct sha256_ctx* ctx);
struct sha256_ctx *ctx);
/* Starting with the result of former calls of this function (or the /* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes initialization function update the context for the next LEN bytes
starting at BUFFER. starting at BUFFER.
It is NOT required that LEN is a multiple of 64. */ It is NOT required that LEN is a multiple of 64. */
extern void sha256_process_bytes (const void *buffer, size_t len, extern void sha256_process_bytes(const void* buffer, size_t len, struct sha256_ctx* ctx);
struct sha256_ctx *ctx);
/* Process the remaining bytes in the buffer and put result from CTX /* Process the remaining bytes in the buffer and put result from CTX
in first 32 (28) bytes following RESBUF. The result is always in little in first 32 (28) bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest. */ ASCII representation of the message digest. */
extern void *sha256_finish_ctx (struct sha256_ctx *ctx, void *restrict resbuf); extern void* sha256_finish_ctx(struct sha256_ctx* ctx, void* restrict resbuf);
extern void *sha224_finish_ctx (struct sha256_ctx *ctx, void *restrict resbuf); extern void* sha224_finish_ctx(struct sha256_ctx* ctx, void* restrict resbuf);
/* Put result from CTX in first 32 (28) bytes following RESBUF. The result is /* Put result from CTX in first 32 (28) bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields always in little endian byte order, so that a byte-wise output yields
to the wanted ASCII representation of the message digest. */ to the wanted ASCII representation of the message digest. */
extern void *sha256_read_ctx (const struct sha256_ctx *ctx, extern void* sha256_read_ctx(const struct sha256_ctx* ctx, void* restrict resbuf);
void *restrict resbuf); extern void* sha224_read_ctx(const struct sha256_ctx* ctx, void* restrict resbuf);
extern void *sha224_read_ctx (const struct sha256_ctx *ctx,
void *restrict resbuf);
/* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. /* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER.
The result is always in little endian byte order, so that a byte-wise The result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message output yields to the wanted ASCII representation of the message
digest. */ digest. */
extern void *sha256_buffer (const char *buffer, size_t len, extern void* sha256_buffer(const char* buffer, size_t len, void* restrict resblock);
void *restrict resblock); extern void* sha224_buffer(const char* buffer, size_t len, void* restrict resblock);
extern void *sha224_buffer (const char *buffer, size_t len,
void *restrict resblock);
# endif #endif
/* Compute SHA256 (SHA224) message digest for bytes read from STREAM. /* Compute SHA256 (SHA224) message digest for bytes read from STREAM.
STREAM is an open file stream. Regular files are handled more efficiently. STREAM is an open file stream. Regular files are handled more efficiently.
@@ -102,13 +93,12 @@ extern void *sha224_buffer (const char *buffer, size_t len,
The case that the last operation on STREAM was an 'ungetc' is not supported. The case that the last operation on STREAM was an 'ungetc' is not supported.
The resulting message digest number will be written into the 32 (28) bytes The resulting message digest number will be written into the 32 (28) bytes
beginning at RESBLOCK. */ beginning at RESBLOCK. */
extern int sha256_stream (FILE *stream, void *resblock); extern int sha256_stream(FILE* stream, void* resblock);
extern int sha224_stream (FILE *stream, void *resblock); extern int sha224_stream(FILE* stream, void* resblock);
#ifdef __cplusplus
# ifdef __cplusplus
} }
# endif #endif
/* /*
* Hey Emacs! * Hey Emacs!

View File

@@ -22,7 +22,7 @@
/* Specification. */ /* Specification. */
#if HAVE_OPENSSL_SHA512 #if HAVE_OPENSSL_SHA512
# define GL_OPENSSL_INLINE _GL_EXTERN_INLINE #define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
#endif #endif
#include "sha512.h" #include "sha512.h"
@@ -30,234 +30,199 @@
#include <string.h> #include <string.h>
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
# define SWAP(n) (n) #define SWAP(n) (n)
#else #else
#include "byteswap.h" #include "byteswap.h"
# define SWAP(n) swap_uint64 (n) #define SWAP(n) swap_uint64(n)
#endif #endif
#if ! HAVE_OPENSSL_SHA512 #if !HAVE_OPENSSL_SHA512
/* This array contains the bytes used to pad the buffer to the next /* This array contains the bytes used to pad the buffer to the next
128-byte boundary. */ 128-byte boundary. */
static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ... */ }; static const unsigned char fillbuf[128] = {0x80, 0 /* , 0, 0, ... */};
/* /*
Takes a pointer to a 512 bit block of data (eight 64 bit ints) and Takes a pointer to a 512 bit block of data (eight 64 bit ints) and
initializes it to the start constants of the SHA512 algorithm. This initializes it to the start constants of the SHA512 algorithm. This
must be called before using hash in the call to sha512_hash must be called before using hash in the call to sha512_hash
*/ */
void void sha512_init_ctx(struct sha512_ctx* ctx) {
sha512_init_ctx (struct sha512_ctx *ctx) ctx->state[0] = u64hilo(0x6a09e667, 0xf3bcc908);
{ ctx->state[1] = u64hilo(0xbb67ae85, 0x84caa73b);
ctx->state[0] = u64hilo (0x6a09e667, 0xf3bcc908); ctx->state[2] = u64hilo(0x3c6ef372, 0xfe94f82b);
ctx->state[1] = u64hilo (0xbb67ae85, 0x84caa73b); ctx->state[3] = u64hilo(0xa54ff53a, 0x5f1d36f1);
ctx->state[2] = u64hilo (0x3c6ef372, 0xfe94f82b); ctx->state[4] = u64hilo(0x510e527f, 0xade682d1);
ctx->state[3] = u64hilo (0xa54ff53a, 0x5f1d36f1); ctx->state[5] = u64hilo(0x9b05688c, 0x2b3e6c1f);
ctx->state[4] = u64hilo (0x510e527f, 0xade682d1); ctx->state[6] = u64hilo(0x1f83d9ab, 0xfb41bd6b);
ctx->state[5] = u64hilo (0x9b05688c, 0x2b3e6c1f); ctx->state[7] = u64hilo(0x5be0cd19, 0x137e2179);
ctx->state[6] = u64hilo (0x1f83d9ab, 0xfb41bd6b);
ctx->state[7] = u64hilo (0x5be0cd19, 0x137e2179);
ctx->total[0] = ctx->total[1] = u64lo (0); ctx->total[0] = ctx->total[1] = u64lo(0);
ctx->buflen = 0; ctx->buflen = 0;
} }
void void sha384_init_ctx(struct sha512_ctx* ctx) {
sha384_init_ctx (struct sha512_ctx *ctx) ctx->state[0] = u64hilo(0xcbbb9d5d, 0xc1059ed8);
{ ctx->state[1] = u64hilo(0x629a292a, 0x367cd507);
ctx->state[0] = u64hilo (0xcbbb9d5d, 0xc1059ed8); ctx->state[2] = u64hilo(0x9159015a, 0x3070dd17);
ctx->state[1] = u64hilo (0x629a292a, 0x367cd507); ctx->state[3] = u64hilo(0x152fecd8, 0xf70e5939);
ctx->state[2] = u64hilo (0x9159015a, 0x3070dd17); ctx->state[4] = u64hilo(0x67332667, 0xffc00b31);
ctx->state[3] = u64hilo (0x152fecd8, 0xf70e5939); ctx->state[5] = u64hilo(0x8eb44a87, 0x68581511);
ctx->state[4] = u64hilo (0x67332667, 0xffc00b31); ctx->state[6] = u64hilo(0xdb0c2e0d, 0x64f98fa7);
ctx->state[5] = u64hilo (0x8eb44a87, 0x68581511); ctx->state[7] = u64hilo(0x47b5481d, 0xbefa4fa4);
ctx->state[6] = u64hilo (0xdb0c2e0d, 0x64f98fa7);
ctx->state[7] = u64hilo (0x47b5481d, 0xbefa4fa4);
ctx->total[0] = ctx->total[1] = u64lo (0); ctx->total[0] = ctx->total[1] = u64lo(0);
ctx->buflen = 0; ctx->buflen = 0;
} }
/* Copy the value from V into the memory location pointed to by *CP, /* Copy the value from V into the memory location pointed to by *CP,
If your architecture allows unaligned access, this is equivalent to If your architecture allows unaligned access, this is equivalent to
* (__typeof__ (v) *) cp = v */ * (__typeof__ (v) *) cp = v */
static void static void set_uint64(char* cp, u64 v) {
set_uint64 (char *cp, u64 v) memcpy(cp, &v, sizeof v);
{
memcpy (cp, &v, sizeof v);
} }
/* Put result from CTX in first 64 bytes following RESBUF. /* Put result from CTX in first 64 bytes following RESBUF.
The result must be in little endian byte order. */ The result must be in little endian byte order. */
void * void* sha512_read_ctx(const struct sha512_ctx* ctx, void* resbuf) {
sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf) int i;
{ char* r = resbuf;
int i;
char *r = resbuf;
for (i = 0; i < 8; i++) for(i = 0; i < 8; i++) set_uint64(r + i * sizeof ctx->state[0], SWAP(ctx->state[i]));
set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i]));
return resbuf; return resbuf;
} }
void * void* sha384_read_ctx(const struct sha512_ctx* ctx, void* resbuf) {
sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf) int i;
{ char* r = resbuf;
int i;
char *r = resbuf;
for (i = 0; i < 6; i++) for(i = 0; i < 6; i++) set_uint64(r + i * sizeof ctx->state[0], SWAP(ctx->state[i]));
set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i]));
return resbuf; return resbuf;
} }
/* Process the remaining bytes in the internal buffer and the usual /* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF. */ prolog according to the standard and write the result to RESBUF. */
static void static void sha512_conclude_ctx(struct sha512_ctx* ctx) {
sha512_conclude_ctx (struct sha512_ctx *ctx) /* Take yet unprocessed bytes into account. */
{ size_t bytes = ctx->buflen;
/* Take yet unprocessed bytes into account. */ size_t size = (bytes < 112) ? 128 / 8 : 128 * 2 / 8;
size_t bytes = ctx->buflen;
size_t size = (bytes < 112) ? 128 / 8 : 128 * 2 / 8;
/* Now count remaining bytes. */ /* Now count remaining bytes. */
ctx->total[0] = u64plus (ctx->total[0], u64lo (bytes)); ctx->total[0] = u64plus(ctx->total[0], u64lo(bytes));
if (u64lt (ctx->total[0], u64lo (bytes))) if(u64lt(ctx->total[0], u64lo(bytes))) ctx->total[1] = u64plus(ctx->total[1], u64lo(1));
ctx->total[1] = u64plus (ctx->total[1], u64lo (1));
/* Put the 128-bit file length in *bits* at the end of the buffer. /* Put the 128-bit file length in *bits* at the end of the buffer.
Use set_uint64 rather than a simple assignment, to avoid risk of Use set_uint64 rather than a simple assignment, to avoid risk of
unaligned access. */ unaligned access. */
set_uint64 ((char *) &ctx->buffer[size - 2], set_uint64(
SWAP (u64or (u64shl (ctx->total[1], 3), (char*)&ctx->buffer[size - 2],
u64shr (ctx->total[0], 61)))); SWAP(u64or(u64shl(ctx->total[1], 3), u64shr(ctx->total[0], 61))));
set_uint64 ((char *) &ctx->buffer[size - 1], set_uint64((char*)&ctx->buffer[size - 1], SWAP(u64shl(ctx->total[0], 3)));
SWAP (u64shl (ctx->total[0], 3)));
memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes); memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes);
/* Process last bytes. */ /* Process last bytes. */
sha512_process_block (ctx->buffer, size * 8, ctx); sha512_process_block(ctx->buffer, size * 8, ctx);
} }
void * void* sha512_finish_ctx(struct sha512_ctx* ctx, void* resbuf) {
sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf) sha512_conclude_ctx(ctx);
{ return sha512_read_ctx(ctx, resbuf);
sha512_conclude_ctx (ctx);
return sha512_read_ctx (ctx, resbuf);
} }
void * void* sha384_finish_ctx(struct sha512_ctx* ctx, void* resbuf) {
sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf) sha512_conclude_ctx(ctx);
{ return sha384_read_ctx(ctx, resbuf);
sha512_conclude_ctx (ctx);
return sha384_read_ctx (ctx, resbuf);
} }
/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The /* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message output yields to the wanted ASCII representation of the message
digest. */ digest. */
void * void* sha512_buffer(const char* buffer, size_t len, void* resblock) {
sha512_buffer (const char *buffer, size_t len, void *resblock) struct sha512_ctx ctx;
{
struct sha512_ctx ctx;
/* Initialize the computation context. */ /* Initialize the computation context. */
sha512_init_ctx (&ctx); sha512_init_ctx(&ctx);
/* Process whole buffer but last len % 128 bytes. */ /* Process whole buffer but last len % 128 bytes. */
sha512_process_bytes (buffer, len, &ctx); sha512_process_bytes(buffer, len, &ctx);
/* Put result in desired memory area. */ /* Put result in desired memory area. */
return sha512_finish_ctx (&ctx, resblock); return sha512_finish_ctx(&ctx, resblock);
} }
void * void* sha384_buffer(const char* buffer, size_t len, void* resblock) {
sha384_buffer (const char *buffer, size_t len, void *resblock) struct sha512_ctx ctx;
{
struct sha512_ctx ctx;
/* Initialize the computation context. */ /* Initialize the computation context. */
sha384_init_ctx (&ctx); sha384_init_ctx(&ctx);
/* Process whole buffer but last len % 128 bytes. */ /* Process whole buffer but last len % 128 bytes. */
sha512_process_bytes (buffer, len, &ctx); sha512_process_bytes(buffer, len, &ctx);
/* Put result in desired memory area. */ /* Put result in desired memory area. */
return sha384_finish_ctx (&ctx, resblock); return sha384_finish_ctx(&ctx, resblock);
} }
void void sha512_process_bytes(const void* buffer, size_t len, struct sha512_ctx* ctx) {
sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx) /* When we already have some bits in our internal buffer concatenate
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */ both inputs first. */
if (ctx->buflen != 0) if(ctx->buflen != 0) {
{ size_t left_over = ctx->buflen;
size_t left_over = ctx->buflen; size_t add = 256 - left_over > len ? len : 256 - left_over;
size_t add = 256 - left_over > len ? len : 256 - left_over;
memcpy (&((char *) ctx->buffer)[left_over], buffer, add); memcpy(&((char*)ctx->buffer)[left_over], buffer, add);
ctx->buflen += add; ctx->buflen += add;
if (ctx->buflen > 128) if(ctx->buflen > 128) {
{ sha512_process_block(ctx->buffer, ctx->buflen & ~127, ctx);
sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx);
ctx->buflen &= 127; ctx->buflen &= 127;
/* The regions in the following copy operation cannot overlap, /* The regions in the following copy operation cannot overlap,
because ctx->buflen < 128 ≤ (left_over + add) & ~127. */ because ctx->buflen < 128 ≤ (left_over + add) & ~127. */
memcpy (ctx->buffer, memcpy(ctx->buffer, &((char*)ctx->buffer)[(left_over + add) & ~127], ctx->buflen);
&((char *) ctx->buffer)[(left_over + add) & ~127],
ctx->buflen);
} }
buffer = (const char *) buffer + add; buffer = (const char*)buffer + add;
len -= add; len -= add;
} }
/* Process available complete blocks. */ /* Process available complete blocks. */
if (len >= 128) if(len >= 128) {
{
#if !(_STRING_ARCH_unaligned || _STRING_INLINE_unaligned) #if !(_STRING_ARCH_unaligned || _STRING_INLINE_unaligned)
# define UNALIGNED_P(p) ((uintptr_t) (p) % sizeof (u64) != 0) #define UNALIGNED_P(p) ((uintptr_t)(p) % sizeof(u64) != 0)
if (UNALIGNED_P (buffer)) if(UNALIGNED_P(buffer))
while (len > 128) while(len > 128) {
{ sha512_process_block(memcpy(ctx->buffer, buffer, 128), 128, ctx);
sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128, ctx); buffer = (const char*)buffer + 128;
buffer = (const char *) buffer + 128; len -= 128;
len -= 128; }
} else
else
#endif #endif
{ {
sha512_process_block (buffer, len & ~127, ctx); sha512_process_block(buffer, len & ~127, ctx);
buffer = (const char *) buffer + (len & ~127); buffer = (const char*)buffer + (len & ~127);
len &= 127; len &= 127;
} }
} }
/* Move remaining bytes in internal buffer. */ /* Move remaining bytes in internal buffer. */
if (len > 0) if(len > 0) {
{ size_t left_over = ctx->buflen;
size_t left_over = ctx->buflen;
memcpy (&((char *) ctx->buffer)[left_over], buffer, len); memcpy(&((char*)ctx->buffer)[left_over], buffer, len);
left_over += len; left_over += len;
if (left_over >= 128) if(left_over >= 128) {
{ sha512_process_block(ctx->buffer, 128, ctx);
sha512_process_block (ctx->buffer, 128, ctx); left_over -= 128;
left_over -= 128; /* The regions in the following copy operation cannot overlap,
/* The regions in the following copy operation cannot overlap,
because left_over ≤ 128. */ because left_over ≤ 128. */
memcpy (ctx->buffer, &ctx->buffer[16], left_over); memcpy(ctx->buffer, &ctx->buffer[16], left_over);
} }
ctx->buflen = left_over; ctx->buflen = left_over;
} }
} }
@@ -266,202 +231,192 @@ sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx)
/* SHA512 round constants */ /* SHA512 round constants */
#define K(I) sha512_round_constants[I] #define K(I) sha512_round_constants[I]
static u64 const sha512_round_constants[80] = { static u64 const sha512_round_constants[80] = {
u64init (0x428a2f98, 0xd728ae22), u64init (0x71374491, 0x23ef65cd), u64init(0x428a2f98, 0xd728ae22), u64init(0x71374491, 0x23ef65cd),
u64init (0xb5c0fbcf, 0xec4d3b2f), u64init (0xe9b5dba5, 0x8189dbbc), u64init(0xb5c0fbcf, 0xec4d3b2f), u64init(0xe9b5dba5, 0x8189dbbc),
u64init (0x3956c25b, 0xf348b538), u64init (0x59f111f1, 0xb605d019), u64init(0x3956c25b, 0xf348b538), u64init(0x59f111f1, 0xb605d019),
u64init (0x923f82a4, 0xaf194f9b), u64init (0xab1c5ed5, 0xda6d8118), u64init(0x923f82a4, 0xaf194f9b), u64init(0xab1c5ed5, 0xda6d8118),
u64init (0xd807aa98, 0xa3030242), u64init (0x12835b01, 0x45706fbe), u64init(0xd807aa98, 0xa3030242), u64init(0x12835b01, 0x45706fbe),
u64init (0x243185be, 0x4ee4b28c), u64init (0x550c7dc3, 0xd5ffb4e2), u64init(0x243185be, 0x4ee4b28c), u64init(0x550c7dc3, 0xd5ffb4e2),
u64init (0x72be5d74, 0xf27b896f), u64init (0x80deb1fe, 0x3b1696b1), u64init(0x72be5d74, 0xf27b896f), u64init(0x80deb1fe, 0x3b1696b1),
u64init (0x9bdc06a7, 0x25c71235), u64init (0xc19bf174, 0xcf692694), u64init(0x9bdc06a7, 0x25c71235), u64init(0xc19bf174, 0xcf692694),
u64init (0xe49b69c1, 0x9ef14ad2), u64init (0xefbe4786, 0x384f25e3), u64init(0xe49b69c1, 0x9ef14ad2), u64init(0xefbe4786, 0x384f25e3),
u64init (0x0fc19dc6, 0x8b8cd5b5), u64init (0x240ca1cc, 0x77ac9c65), u64init(0x0fc19dc6, 0x8b8cd5b5), u64init(0x240ca1cc, 0x77ac9c65),
u64init (0x2de92c6f, 0x592b0275), u64init (0x4a7484aa, 0x6ea6e483), u64init(0x2de92c6f, 0x592b0275), u64init(0x4a7484aa, 0x6ea6e483),
u64init (0x5cb0a9dc, 0xbd41fbd4), u64init (0x76f988da, 0x831153b5), u64init(0x5cb0a9dc, 0xbd41fbd4), u64init(0x76f988da, 0x831153b5),
u64init (0x983e5152, 0xee66dfab), u64init (0xa831c66d, 0x2db43210), u64init(0x983e5152, 0xee66dfab), u64init(0xa831c66d, 0x2db43210),
u64init (0xb00327c8, 0x98fb213f), u64init (0xbf597fc7, 0xbeef0ee4), u64init(0xb00327c8, 0x98fb213f), u64init(0xbf597fc7, 0xbeef0ee4),
u64init (0xc6e00bf3, 0x3da88fc2), u64init (0xd5a79147, 0x930aa725), u64init(0xc6e00bf3, 0x3da88fc2), u64init(0xd5a79147, 0x930aa725),
u64init (0x06ca6351, 0xe003826f), u64init (0x14292967, 0x0a0e6e70), u64init(0x06ca6351, 0xe003826f), u64init(0x14292967, 0x0a0e6e70),
u64init (0x27b70a85, 0x46d22ffc), u64init (0x2e1b2138, 0x5c26c926), u64init(0x27b70a85, 0x46d22ffc), u64init(0x2e1b2138, 0x5c26c926),
u64init (0x4d2c6dfc, 0x5ac42aed), u64init (0x53380d13, 0x9d95b3df), u64init(0x4d2c6dfc, 0x5ac42aed), u64init(0x53380d13, 0x9d95b3df),
u64init (0x650a7354, 0x8baf63de), u64init (0x766a0abb, 0x3c77b2a8), u64init(0x650a7354, 0x8baf63de), u64init(0x766a0abb, 0x3c77b2a8),
u64init (0x81c2c92e, 0x47edaee6), u64init (0x92722c85, 0x1482353b), u64init(0x81c2c92e, 0x47edaee6), u64init(0x92722c85, 0x1482353b),
u64init (0xa2bfe8a1, 0x4cf10364), u64init (0xa81a664b, 0xbc423001), u64init(0xa2bfe8a1, 0x4cf10364), u64init(0xa81a664b, 0xbc423001),
u64init (0xc24b8b70, 0xd0f89791), u64init (0xc76c51a3, 0x0654be30), u64init(0xc24b8b70, 0xd0f89791), u64init(0xc76c51a3, 0x0654be30),
u64init (0xd192e819, 0xd6ef5218), u64init (0xd6990624, 0x5565a910), u64init(0xd192e819, 0xd6ef5218), u64init(0xd6990624, 0x5565a910),
u64init (0xf40e3585, 0x5771202a), u64init (0x106aa070, 0x32bbd1b8), u64init(0xf40e3585, 0x5771202a), u64init(0x106aa070, 0x32bbd1b8),
u64init (0x19a4c116, 0xb8d2d0c8), u64init (0x1e376c08, 0x5141ab53), u64init(0x19a4c116, 0xb8d2d0c8), u64init(0x1e376c08, 0x5141ab53),
u64init (0x2748774c, 0xdf8eeb99), u64init (0x34b0bcb5, 0xe19b48a8), u64init(0x2748774c, 0xdf8eeb99), u64init(0x34b0bcb5, 0xe19b48a8),
u64init (0x391c0cb3, 0xc5c95a63), u64init (0x4ed8aa4a, 0xe3418acb), u64init(0x391c0cb3, 0xc5c95a63), u64init(0x4ed8aa4a, 0xe3418acb),
u64init (0x5b9cca4f, 0x7763e373), u64init (0x682e6ff3, 0xd6b2b8a3), u64init(0x5b9cca4f, 0x7763e373), u64init(0x682e6ff3, 0xd6b2b8a3),
u64init (0x748f82ee, 0x5defb2fc), u64init (0x78a5636f, 0x43172f60), u64init(0x748f82ee, 0x5defb2fc), u64init(0x78a5636f, 0x43172f60),
u64init (0x84c87814, 0xa1f0ab72), u64init (0x8cc70208, 0x1a6439ec), u64init(0x84c87814, 0xa1f0ab72), u64init(0x8cc70208, 0x1a6439ec),
u64init (0x90befffa, 0x23631e28), u64init (0xa4506ceb, 0xde82bde9), u64init(0x90befffa, 0x23631e28), u64init(0xa4506ceb, 0xde82bde9),
u64init (0xbef9a3f7, 0xb2c67915), u64init (0xc67178f2, 0xe372532b), u64init(0xbef9a3f7, 0xb2c67915), u64init(0xc67178f2, 0xe372532b),
u64init (0xca273ece, 0xea26619c), u64init (0xd186b8c7, 0x21c0c207), u64init(0xca273ece, 0xea26619c), u64init(0xd186b8c7, 0x21c0c207),
u64init (0xeada7dd6, 0xcde0eb1e), u64init (0xf57d4f7f, 0xee6ed178), u64init(0xeada7dd6, 0xcde0eb1e), u64init(0xf57d4f7f, 0xee6ed178),
u64init (0x06f067aa, 0x72176fba), u64init (0x0a637dc5, 0xa2c898a6), u64init(0x06f067aa, 0x72176fba), u64init(0x0a637dc5, 0xa2c898a6),
u64init (0x113f9804, 0xbef90dae), u64init (0x1b710b35, 0x131c471b), u64init(0x113f9804, 0xbef90dae), u64init(0x1b710b35, 0x131c471b),
u64init (0x28db77f5, 0x23047d84), u64init (0x32caab7b, 0x40c72493), u64init(0x28db77f5, 0x23047d84), u64init(0x32caab7b, 0x40c72493),
u64init (0x3c9ebe0a, 0x15c9bebc), u64init (0x431d67c4, 0x9c100d4c), u64init(0x3c9ebe0a, 0x15c9bebc), u64init(0x431d67c4, 0x9c100d4c),
u64init (0x4cc5d4be, 0xcb3e42b6), u64init (0x597f299c, 0xfc657e2a), u64init(0x4cc5d4be, 0xcb3e42b6), u64init(0x597f299c, 0xfc657e2a),
u64init (0x5fcb6fab, 0x3ad6faec), u64init (0x6c44198c, 0x4a475817), u64init(0x5fcb6fab, 0x3ad6faec), u64init(0x6c44198c, 0x4a475817),
}; };
/* Round functions. */ /* Round functions. */
#define F2(A, B, C) u64or (u64and (A, B), u64and (C, u64or (A, B))) #define F2(A, B, C) u64or(u64and(A, B), u64and(C, u64or(A, B)))
#define F1(E, F, G) u64xor (G, u64and (E, u64xor (F, G))) #define F1(E, F, G) u64xor(G, u64and(E, u64xor(F, G)))
/* Process LEN bytes of BUFFER, accumulating context into CTX. /* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 128 == 0. It is assumed that LEN % 128 == 0.
Most of this code comes from GnuPG's cipher/sha1.c. */ Most of this code comes from GnuPG's cipher/sha1.c. */
void void sha512_process_block(const void* buffer, size_t len, struct sha512_ctx* ctx) {
sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx) u64 const* words = buffer;
{ u64 const* endp = words + len / sizeof(u64);
u64 const *words = buffer; u64 x[16];
u64 const *endp = words + len / sizeof (u64); u64 a = ctx->state[0];
u64 x[16]; u64 b = ctx->state[1];
u64 a = ctx->state[0]; u64 c = ctx->state[2];
u64 b = ctx->state[1]; u64 d = ctx->state[3];
u64 c = ctx->state[2]; u64 e = ctx->state[4];
u64 d = ctx->state[3]; u64 f = ctx->state[5];
u64 e = ctx->state[4]; u64 g = ctx->state[6];
u64 f = ctx->state[5]; u64 h = ctx->state[7];
u64 g = ctx->state[6]; u64 lolen = u64size(len);
u64 h = ctx->state[7];
u64 lolen = u64size (len);
/* First increment the byte count. FIPS PUB 180-2 specifies the possible /* First increment the byte count. FIPS PUB 180-2 specifies the possible
length of the file up to 2^128 bits. Here we only compute the length of the file up to 2^128 bits. Here we only compute the
number of bytes. Do a double word increment. */ number of bytes. Do a double word increment. */
ctx->total[0] = u64plus (ctx->total[0], lolen); ctx->total[0] = u64plus(ctx->total[0], lolen);
ctx->total[1] = u64plus (ctx->total[1], ctx->total[1] = u64plus(
u64plus (u64size (len >> 31 >> 31 >> 2), ctx->total[1], u64plus(u64size(len >> 31 >> 31 >> 2), u64lo(u64lt(ctx->total[0], lolen))));
u64lo (u64lt (ctx->total[0], lolen))));
#define S0(x) u64xor (u64rol(x, 63), u64xor (u64rol (x, 56), u64shr (x, 7))) #define S0(x) u64xor(u64rol(x, 63), u64xor(u64rol(x, 56), u64shr(x, 7)))
#define S1(x) u64xor (u64rol (x, 45), u64xor (u64rol (x, 3), u64shr (x, 6))) #define S1(x) u64xor(u64rol(x, 45), u64xor(u64rol(x, 3), u64shr(x, 6)))
#define SS0(x) u64xor (u64rol (x, 36), u64xor (u64rol (x, 30), u64rol (x, 25))) #define SS0(x) u64xor(u64rol(x, 36), u64xor(u64rol(x, 30), u64rol(x, 25)))
#define SS1(x) u64xor (u64rol(x, 50), u64xor (u64rol (x, 46), u64rol (x, 23))) #define SS1(x) u64xor(u64rol(x, 50), u64xor(u64rol(x, 46), u64rol(x, 23)))
#define M(I) (x[(I) & 15] \ #define M(I) \
= u64plus (x[(I) & 15], \ (x[(I)&15] = u64plus( \
u64plus (S1 (x[((I) - 2) & 15]), \ x[(I)&15], \
u64plus (x[((I) - 7) & 15], \ u64plus(S1(x[((I)-2) & 15]), u64plus(x[((I)-7) & 15], S0(x[((I)-15) & 15])))))
S0 (x[((I) - 15) & 15])))))
#define R(A, B, C, D, E, F, G, H, K, M) \ #define R(A, B, C, D, E, F, G, H, K, M) \
do \ do { \
{ \ u64 t0 = u64plus(SS0(A), F2(A, B, C)); \
u64 t0 = u64plus (SS0 (A), F2 (A, B, C)); \ u64 t1 = u64plus(H, u64plus(SS1(E), u64plus(F1(E, F, G), u64plus(K, M)))); \
u64 t1 = \ D = u64plus(D, t1); \
u64plus (H, u64plus (SS1 (E), \ H = u64plus(t0, t1); \
u64plus (F1 (E, F, G), u64plus (K, M)))); \ } while(0)
D = u64plus (D, t1); \
H = u64plus (t0, t1); \
} \
while (0)
while (words < endp) while(words < endp) {
{ int t;
int t; /* FIXME: see sha1.c for a better implementation. */
/* FIXME: see sha1.c for a better implementation. */ for(t = 0; t < 16; t++) {
for (t = 0; t < 16; t++) x[t] = SWAP(*words);
{ words++;
x[t] = SWAP (*words);
words++;
} }
R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); R(a, b, c, d, e, f, g, h, K(0), x[0]);
R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); R(h, a, b, c, d, e, f, g, K(1), x[1]);
R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); R(g, h, a, b, c, d, e, f, K(2), x[2]);
R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); R(f, g, h, a, b, c, d, e, K(3), x[3]);
R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); R(e, f, g, h, a, b, c, d, K(4), x[4]);
R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); R(d, e, f, g, h, a, b, c, K(5), x[5]);
R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); R(c, d, e, f, g, h, a, b, K(6), x[6]);
R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); R(b, c, d, e, f, g, h, a, K(7), x[7]);
R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); R(a, b, c, d, e, f, g, h, K(8), x[8]);
R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); R(h, a, b, c, d, e, f, g, K(9), x[9]);
R( g, h, a, b, c, d, e, f, K(10), x[10] ); R(g, h, a, b, c, d, e, f, K(10), x[10]);
R( f, g, h, a, b, c, d, e, K(11), x[11] ); R(f, g, h, a, b, c, d, e, K(11), x[11]);
R( e, f, g, h, a, b, c, d, K(12), x[12] ); R(e, f, g, h, a, b, c, d, K(12), x[12]);
R( d, e, f, g, h, a, b, c, K(13), x[13] ); R(d, e, f, g, h, a, b, c, K(13), x[13]);
R( c, d, e, f, g, h, a, b, K(14), x[14] ); R(c, d, e, f, g, h, a, b, K(14), x[14]);
R( b, c, d, e, f, g, h, a, K(15), x[15] ); R(b, c, d, e, f, g, h, a, K(15), x[15]);
R( a, b, c, d, e, f, g, h, K(16), M(16) ); R(a, b, c, d, e, f, g, h, K(16), M(16));
R( h, a, b, c, d, e, f, g, K(17), M(17) ); R(h, a, b, c, d, e, f, g, K(17), M(17));
R( g, h, a, b, c, d, e, f, K(18), M(18) ); R(g, h, a, b, c, d, e, f, K(18), M(18));
R( f, g, h, a, b, c, d, e, K(19), M(19) ); R(f, g, h, a, b, c, d, e, K(19), M(19));
R( e, f, g, h, a, b, c, d, K(20), M(20) ); R(e, f, g, h, a, b, c, d, K(20), M(20));
R( d, e, f, g, h, a, b, c, K(21), M(21) ); R(d, e, f, g, h, a, b, c, K(21), M(21));
R( c, d, e, f, g, h, a, b, K(22), M(22) ); R(c, d, e, f, g, h, a, b, K(22), M(22));
R( b, c, d, e, f, g, h, a, K(23), M(23) ); R(b, c, d, e, f, g, h, a, K(23), M(23));
R( a, b, c, d, e, f, g, h, K(24), M(24) ); R(a, b, c, d, e, f, g, h, K(24), M(24));
R( h, a, b, c, d, e, f, g, K(25), M(25) ); R(h, a, b, c, d, e, f, g, K(25), M(25));
R( g, h, a, b, c, d, e, f, K(26), M(26) ); R(g, h, a, b, c, d, e, f, K(26), M(26));
R( f, g, h, a, b, c, d, e, K(27), M(27) ); R(f, g, h, a, b, c, d, e, K(27), M(27));
R( e, f, g, h, a, b, c, d, K(28), M(28) ); R(e, f, g, h, a, b, c, d, K(28), M(28));
R( d, e, f, g, h, a, b, c, K(29), M(29) ); R(d, e, f, g, h, a, b, c, K(29), M(29));
R( c, d, e, f, g, h, a, b, K(30), M(30) ); R(c, d, e, f, g, h, a, b, K(30), M(30));
R( b, c, d, e, f, g, h, a, K(31), M(31) ); R(b, c, d, e, f, g, h, a, K(31), M(31));
R( a, b, c, d, e, f, g, h, K(32), M(32) ); R(a, b, c, d, e, f, g, h, K(32), M(32));
R( h, a, b, c, d, e, f, g, K(33), M(33) ); R(h, a, b, c, d, e, f, g, K(33), M(33));
R( g, h, a, b, c, d, e, f, K(34), M(34) ); R(g, h, a, b, c, d, e, f, K(34), M(34));
R( f, g, h, a, b, c, d, e, K(35), M(35) ); R(f, g, h, a, b, c, d, e, K(35), M(35));
R( e, f, g, h, a, b, c, d, K(36), M(36) ); R(e, f, g, h, a, b, c, d, K(36), M(36));
R( d, e, f, g, h, a, b, c, K(37), M(37) ); R(d, e, f, g, h, a, b, c, K(37), M(37));
R( c, d, e, f, g, h, a, b, K(38), M(38) ); R(c, d, e, f, g, h, a, b, K(38), M(38));
R( b, c, d, e, f, g, h, a, K(39), M(39) ); R(b, c, d, e, f, g, h, a, K(39), M(39));
R( a, b, c, d, e, f, g, h, K(40), M(40) ); R(a, b, c, d, e, f, g, h, K(40), M(40));
R( h, a, b, c, d, e, f, g, K(41), M(41) ); R(h, a, b, c, d, e, f, g, K(41), M(41));
R( g, h, a, b, c, d, e, f, K(42), M(42) ); R(g, h, a, b, c, d, e, f, K(42), M(42));
R( f, g, h, a, b, c, d, e, K(43), M(43) ); R(f, g, h, a, b, c, d, e, K(43), M(43));
R( e, f, g, h, a, b, c, d, K(44), M(44) ); R(e, f, g, h, a, b, c, d, K(44), M(44));
R( d, e, f, g, h, a, b, c, K(45), M(45) ); R(d, e, f, g, h, a, b, c, K(45), M(45));
R( c, d, e, f, g, h, a, b, K(46), M(46) ); R(c, d, e, f, g, h, a, b, K(46), M(46));
R( b, c, d, e, f, g, h, a, K(47), M(47) ); R(b, c, d, e, f, g, h, a, K(47), M(47));
R( a, b, c, d, e, f, g, h, K(48), M(48) ); R(a, b, c, d, e, f, g, h, K(48), M(48));
R( h, a, b, c, d, e, f, g, K(49), M(49) ); R(h, a, b, c, d, e, f, g, K(49), M(49));
R( g, h, a, b, c, d, e, f, K(50), M(50) ); R(g, h, a, b, c, d, e, f, K(50), M(50));
R( f, g, h, a, b, c, d, e, K(51), M(51) ); R(f, g, h, a, b, c, d, e, K(51), M(51));
R( e, f, g, h, a, b, c, d, K(52), M(52) ); R(e, f, g, h, a, b, c, d, K(52), M(52));
R( d, e, f, g, h, a, b, c, K(53), M(53) ); R(d, e, f, g, h, a, b, c, K(53), M(53));
R( c, d, e, f, g, h, a, b, K(54), M(54) ); R(c, d, e, f, g, h, a, b, K(54), M(54));
R( b, c, d, e, f, g, h, a, K(55), M(55) ); R(b, c, d, e, f, g, h, a, K(55), M(55));
R( a, b, c, d, e, f, g, h, K(56), M(56) ); R(a, b, c, d, e, f, g, h, K(56), M(56));
R( h, a, b, c, d, e, f, g, K(57), M(57) ); R(h, a, b, c, d, e, f, g, K(57), M(57));
R( g, h, a, b, c, d, e, f, K(58), M(58) ); R(g, h, a, b, c, d, e, f, K(58), M(58));
R( f, g, h, a, b, c, d, e, K(59), M(59) ); R(f, g, h, a, b, c, d, e, K(59), M(59));
R( e, f, g, h, a, b, c, d, K(60), M(60) ); R(e, f, g, h, a, b, c, d, K(60), M(60));
R( d, e, f, g, h, a, b, c, K(61), M(61) ); R(d, e, f, g, h, a, b, c, K(61), M(61));
R( c, d, e, f, g, h, a, b, K(62), M(62) ); R(c, d, e, f, g, h, a, b, K(62), M(62));
R( b, c, d, e, f, g, h, a, K(63), M(63) ); R(b, c, d, e, f, g, h, a, K(63), M(63));
R( a, b, c, d, e, f, g, h, K(64), M(64) ); R(a, b, c, d, e, f, g, h, K(64), M(64));
R( h, a, b, c, d, e, f, g, K(65), M(65) ); R(h, a, b, c, d, e, f, g, K(65), M(65));
R( g, h, a, b, c, d, e, f, K(66), M(66) ); R(g, h, a, b, c, d, e, f, K(66), M(66));
R( f, g, h, a, b, c, d, e, K(67), M(67) ); R(f, g, h, a, b, c, d, e, K(67), M(67));
R( e, f, g, h, a, b, c, d, K(68), M(68) ); R(e, f, g, h, a, b, c, d, K(68), M(68));
R( d, e, f, g, h, a, b, c, K(69), M(69) ); R(d, e, f, g, h, a, b, c, K(69), M(69));
R( c, d, e, f, g, h, a, b, K(70), M(70) ); R(c, d, e, f, g, h, a, b, K(70), M(70));
R( b, c, d, e, f, g, h, a, K(71), M(71) ); R(b, c, d, e, f, g, h, a, K(71), M(71));
R( a, b, c, d, e, f, g, h, K(72), M(72) ); R(a, b, c, d, e, f, g, h, K(72), M(72));
R( h, a, b, c, d, e, f, g, K(73), M(73) ); R(h, a, b, c, d, e, f, g, K(73), M(73));
R( g, h, a, b, c, d, e, f, K(74), M(74) ); R(g, h, a, b, c, d, e, f, K(74), M(74));
R( f, g, h, a, b, c, d, e, K(75), M(75) ); R(f, g, h, a, b, c, d, e, K(75), M(75));
R( e, f, g, h, a, b, c, d, K(76), M(76) ); R(e, f, g, h, a, b, c, d, K(76), M(76));
R( d, e, f, g, h, a, b, c, K(77), M(77) ); R(d, e, f, g, h, a, b, c, K(77), M(77));
R( c, d, e, f, g, h, a, b, K(78), M(78) ); R(c, d, e, f, g, h, a, b, K(78), M(78));
R( b, c, d, e, f, g, h, a, K(79), M(79) ); R(b, c, d, e, f, g, h, a, K(79), M(79));
a = ctx->state[0] = u64plus (ctx->state[0], a); a = ctx->state[0] = u64plus(ctx->state[0], a);
b = ctx->state[1] = u64plus (ctx->state[1], b); b = ctx->state[1] = u64plus(ctx->state[1], b);
c = ctx->state[2] = u64plus (ctx->state[2], c); c = ctx->state[2] = u64plus(ctx->state[2], c);
d = ctx->state[3] = u64plus (ctx->state[3], d); d = ctx->state[3] = u64plus(ctx->state[3], d);
e = ctx->state[4] = u64plus (ctx->state[4], e); e = ctx->state[4] = u64plus(ctx->state[4], e);
f = ctx->state[5] = u64plus (ctx->state[5], f); f = ctx->state[5] = u64plus(ctx->state[5], f);
g = ctx->state[6] = u64plus (ctx->state[6], g); g = ctx->state[6] = u64plus(ctx->state[6], g);
h = ctx->state[7] = u64plus (ctx->state[7], h); h = ctx->state[7] = u64plus(ctx->state[7], h);
} }
} }

View File

@@ -17,64 +17,60 @@
#pragma once #pragma once
# include <stdio.h> #include <stdio.h>
# include "u64.h" #include "u64.h"
# if HAVE_OPENSSL_SHA512 #if HAVE_OPENSSL_SHA512
# ifndef OPENSSL_API_COMPAT #ifndef OPENSSL_API_COMPAT
# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */ #define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
# endif #endif
# include <openssl/sha.h> #include <openssl/sha.h>
# endif #endif
# ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
# endif #endif
enum { SHA384_DIGEST_SIZE = 384 / 8 }; enum { SHA384_DIGEST_SIZE = 384 / 8 };
enum { SHA512_DIGEST_SIZE = 512 / 8 }; enum { SHA512_DIGEST_SIZE = 512 / 8 };
# if HAVE_OPENSSL_SHA512 #if HAVE_OPENSSL_SHA512
# define GL_OPENSSL_NAME 384 #define GL_OPENSSL_NAME 384
# include "gl_openssl.h" #include "gl_openssl.h"
# define GL_OPENSSL_NAME 512 #define GL_OPENSSL_NAME 512
# include "gl_openssl.h" #include "gl_openssl.h"
# else #else
/* Structure to save state of computation between the single steps. */ /* Structure to save state of computation between the single steps. */
struct sha512_ctx struct sha512_ctx {
{ u64 state[8];
u64 state[8];
u64 total[2]; u64 total[2];
size_t buflen; /* ≥ 0, ≤ 256 */ size_t buflen; /* ≥ 0, ≤ 256 */
u64 buffer[32]; /* 256 bytes; the first buflen bytes are in use */ u64 buffer[32]; /* 256 bytes; the first buflen bytes are in use */
}; };
/* Initialize structure containing state of computation. */ /* Initialize structure containing state of computation. */
extern void sha512_init_ctx (struct sha512_ctx *ctx); extern void sha512_init_ctx(struct sha512_ctx* ctx);
extern void sha384_init_ctx (struct sha512_ctx *ctx); extern void sha384_init_ctx(struct sha512_ctx* ctx);
/* Starting with the result of former calls of this function (or the /* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes initialization function update the context for the next LEN bytes
starting at BUFFER. starting at BUFFER.
It is necessary that LEN is a multiple of 128!!! */ It is necessary that LEN is a multiple of 128!!! */
extern void sha512_process_block (const void *buffer, size_t len, extern void sha512_process_block(const void* buffer, size_t len, struct sha512_ctx* ctx);
struct sha512_ctx *ctx);
/* Starting with the result of former calls of this function (or the /* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes initialization function update the context for the next LEN bytes
starting at BUFFER. starting at BUFFER.
It is NOT required that LEN is a multiple of 128. */ It is NOT required that LEN is a multiple of 128. */
extern void sha512_process_bytes (const void *buffer, size_t len, extern void sha512_process_bytes(const void* buffer, size_t len, struct sha512_ctx* ctx);
struct sha512_ctx *ctx);
/* Process the remaining bytes in the buffer and put result from CTX /* Process the remaining bytes in the buffer and put result from CTX
in first 64 (48) bytes following RESBUF. The result is always in little in first 64 (48) bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest. */ ASCII representation of the message digest. */
extern void *sha512_finish_ctx (struct sha512_ctx *ctx, void *restrict resbuf); extern void* sha512_finish_ctx(struct sha512_ctx* ctx, void* restrict resbuf);
extern void *sha384_finish_ctx (struct sha512_ctx *ctx, void *restrict resbuf); extern void* sha384_finish_ctx(struct sha512_ctx* ctx, void* restrict resbuf);
/* Put result from CTX in first 64 (48) bytes following RESBUF. The result is /* Put result from CTX in first 64 (48) bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields always in little endian byte order, so that a byte-wise output yields
@@ -82,22 +78,17 @@ extern void *sha384_finish_ctx (struct sha512_ctx *ctx, void *restrict resbuf);
IMPORTANT: On some systems it is required that RESBUF is correctly IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */ aligned for a 32 bits value. */
extern void *sha512_read_ctx (const struct sha512_ctx *ctx, extern void* sha512_read_ctx(const struct sha512_ctx* ctx, void* restrict resbuf);
void *restrict resbuf); extern void* sha384_read_ctx(const struct sha512_ctx* ctx, void* restrict resbuf);
extern void *sha384_read_ctx (const struct sha512_ctx *ctx,
void *restrict resbuf);
/* Compute SHA512 (SHA384) message digest for LEN bytes beginning at BUFFER. /* Compute SHA512 (SHA384) message digest for LEN bytes beginning at BUFFER.
The result is always in little endian byte order, so that a byte-wise The result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message output yields to the wanted ASCII representation of the message
digest. */ digest. */
extern void *sha512_buffer (const char *buffer, size_t len, extern void* sha512_buffer(const char* buffer, size_t len, void* restrict resblock);
void *restrict resblock); extern void* sha384_buffer(const char* buffer, size_t len, void* restrict resblock);
extern void *sha384_buffer (const char *buffer, size_t len,
void *restrict resblock);
# endif #endif
/* Compute SHA512 (SHA384) message digest for bytes read from STREAM. /* Compute SHA512 (SHA384) message digest for bytes read from STREAM.
STREAM is an open file stream. Regular files are handled more efficiently. STREAM is an open file stream. Regular files are handled more efficiently.
@@ -105,13 +96,12 @@ extern void *sha384_buffer (const char *buffer, size_t len,
The case that the last operation on STREAM was an 'ungetc' is not supported. The case that the last operation on STREAM was an 'ungetc' is not supported.
The resulting message digest number will be written into the 64 (48) bytes The resulting message digest number will be written into the 64 (48) bytes
beginning at RESBLOCK. */ beginning at RESBLOCK. */
extern int sha512_stream (FILE *stream, void *resblock); extern int sha512_stream(FILE* stream, void* resblock);
extern int sha384_stream (FILE *stream, void *resblock); extern int sha384_stream(FILE* stream, void* resblock);
#ifdef __cplusplus
# ifdef __cplusplus
} }
# endif #endif
/* /*
* Hey Emacs! * Hey Emacs!

View File

@@ -22,23 +22,23 @@
#include <stdint.h> #include <stdint.h>
#ifndef _GL_U64_INLINE #ifndef _GL_U64_INLINE
# define _GL_U64_INLINE _GL_INLINE #define _GL_U64_INLINE _GL_INLINE
#endif #endif
/* Return X rotated left by N bits, where 0 < N < 64. */ /* Return X rotated left by N bits, where 0 < N < 64. */
#define u64rol(x, n) u64or (u64shl (x, n), u64shr (x, 64 - n)) #define u64rol(x, n) u64or(u64shl(x, n), u64shr(x, 64 - n))
/* Native implementations are trivial. See below for comments on what /* Native implementations are trivial. See below for comments on what
these operations do. */ these operations do. */
typedef uint64_t u64; typedef uint64_t u64;
# define u64hilo(hi, lo) ((u64) (((u64) (hi) << 32) + (lo))) #define u64hilo(hi, lo) ((u64)(((u64)(hi) << 32) + (lo)))
# define u64init(hi, lo) u64hilo (hi, lo) #define u64init(hi, lo) u64hilo(hi, lo)
# define u64lo(x) ((u64) (x)) #define u64lo(x) ((u64)(x))
# define u64size(x) u64lo (x) #define u64size(x) u64lo(x)
# define u64lt(x, y) ((x) < (y)) #define u64lt(x, y) ((x) < (y))
# define u64and(x, y) ((x) & (y)) #define u64and(x, y) ((x) & (y))
# define u64or(x, y) ((x) | (y)) #define u64or(x, y) ((x) | (y))
# define u64xor(x, y) ((x) ^ (y)) #define u64xor(x, y) ((x) ^ (y))
# define u64plus(x, y) ((x) + (y)) #define u64plus(x, y) ((x) + (y))
# define u64shl(x, n) ((x) << (n)) #define u64shl(x, n) ((x) << (n))
# define u64shr(x, n) ((x) >> (n)) #define u64shr(x, n) ((x) >> (n))

View File

@@ -1,23 +1,23 @@
#include "list.h" #include "list.h"
ListNode *list_init_head(void* data) { ListNode* list_init_head(void* data) {
ListNode *new = (ListNode *) malloc(sizeof(ListNode)); ListNode* new = (ListNode*)malloc(sizeof(ListNode));
new->data = data; new->data = data;
new->next = NULL; new->next = NULL;
return new; return new;
} }
ListNode *list_add(ListNode *head, void* data) { ListNode* list_add(ListNode* head, void* data) {
ListNode *new = (ListNode *) malloc(sizeof(ListNode)); ListNode* new = (ListNode*)malloc(sizeof(ListNode));
new->data = data; new->data = data;
new->next = NULL; new->next = NULL;
if (head == NULL) if(head == NULL)
head = new; head = new;
else { else {
ListNode *it; ListNode* it;
for (it = head; it->next != NULL; it = it->next) for(it = head; it->next != NULL; it = it->next)
; ;
it->next = new; it->next = new;
@@ -26,33 +26,33 @@ ListNode *list_add(ListNode *head, void* data) {
return head; return head;
} }
ListNode *list_find(ListNode *head, void* data) { ListNode* list_find(ListNode* head, void* data) {
ListNode *it; ListNode* it;
for (it = head; it != NULL; it = it->next) for(it = head; it != NULL; it = it->next)
if (it->data == data) if(it->data == data) break;
break;
return it; return it;
} }
ListNode *list_element_at(ListNode *head, uint16_t index) { ListNode* list_element_at(ListNode* head, uint16_t index) {
ListNode *it; ListNode* it;
uint16_t i; uint16_t i;
for (it = head, i = 0; it != NULL && i < index; it = it->next, i++); for(it = head, i = 0; it != NULL && i < index; it = it->next, i++)
;
return it; return it;
} }
ListNode *list_remove(ListNode *head, ListNode *ep) { ListNode* list_remove(ListNode* head, ListNode* ep) {
if (head == ep) { if(head == ep) {
ListNode *new_head = head->next; ListNode* new_head = head->next;
free(head); free(head);
return new_head; return new_head;
} }
ListNode *it; ListNode* it;
for (it = head; it->next != ep; it = it->next) for(it = head; it->next != ep; it = it->next)
; ;
it->next = ep->next; it->next = ep->next;
@@ -61,10 +61,10 @@ ListNode *list_remove(ListNode *head, ListNode *ep) {
return head; return head;
} }
void list_free(ListNode *head) { void list_free(ListNode* head) {
ListNode *it = head, *tmp; ListNode *it = head, *tmp;
while (it != NULL) { while(it != NULL) {
tmp = it; tmp = it;
it = it->next; it = it->next;
free(tmp); free(tmp);

View File

@@ -5,12 +5,20 @@
typedef struct ListNode { typedef struct ListNode {
void* data; void* data;
struct ListNode *next; struct ListNode* next;
} ListNode; } ListNode;
ListNode *list_init_head(void* data); ListNode* list_init_head(void* data);
ListNode *list_add(ListNode *head, void* data); /* adds element with specified data to the end of the list and returns new head node. */ ListNode* list_add(
ListNode *list_find(ListNode *head, void* data); /* returns pointer of element with specified data in list. */ ListNode* head,
ListNode *list_element_at(ListNode *head, uint16_t index); /* returns pointer of element with specified index in list. */ void* data); /* adds element with specified data to the end of the list and returns new head node. */
ListNode *list_remove(ListNode *head, ListNode *ep); /* removes element from the list and returns new head node. */ ListNode* list_find(
void list_free(ListNode *head); /* deletes all elements of the list. */ ListNode* head,
void* data); /* returns pointer of element with specified data in list. */
ListNode* list_element_at(
ListNode* head,
uint16_t index); /* returns pointer of element with specified index in list. */
ListNode* list_remove(
ListNode* head,
ListNode* ep); /* removes element from the list and returns new head node. */
void list_free(ListNode* head); /* deletes all elements of the list. */

View File

@@ -6,7 +6,7 @@ int32_t timezone_offset_from_hours(float hours) {
uint64_t timezone_offset_apply(uint64_t time, int32_t offset) { uint64_t timezone_offset_apply(uint64_t time, int32_t offset) {
uint64_t for_time_adjusted; uint64_t for_time_adjusted;
if (offset > 0) { if(offset > 0) {
for_time_adjusted = time - offset; for_time_adjusted = time - offset;
} else { } else {
for_time_adjusted = time + (-offset); for_time_adjusted = time + (-offset);

View File

@@ -5,9 +5,9 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include "../hmac/hmac-sha1.h" #include "../hmac/hmac_sha1.h"
#include "../hmac/hmac-sha256.h" #include "../hmac/hmac_sha256.h"
#include "../hmac/hmac-sha512.h" #include "../hmac/hmac_sha512.h"
#include "../timezone_utils/timezone_utils.h" #include "../timezone_utils/timezone_utils.h"
#define UINT64_GET_BYTE(integer, index) ((integer >> (8 * index)) & 0xFF) #define UINT64_GET_BYTE(integer, index) ((integer >> (8 * index)) & 0xFF)
@@ -25,9 +25,8 @@
timeblock given for_time, using data->interval timeblock given for_time, using data->interval
error, 0 error, 0
*/ */
uint64_t totp_timecode(uint8_t interval, uint64_t for_time) uint64_t totp_timecode(uint8_t interval, uint64_t for_time) {
{ return for_time / interval;
return for_time/interval;
} }
/* /*
@@ -35,8 +34,7 @@ uint64_t totp_timecode(uint8_t interval, uint64_t for_time)
out_bytes is the null-terminated output string already allocated out_bytes is the null-terminated output string already allocated
*/ */
void otp_num_to_bytes(uint64_t integer, uint8_t* out_bytes) void otp_num_to_bytes(uint64_t integer, uint8_t* out_bytes) {
{
out_bytes[7] = UINT64_GET_BYTE(integer, 0); out_bytes[7] = UINT64_GET_BYTE(integer, 0);
out_bytes[6] = UINT64_GET_BYTE(integer, 1); out_bytes[6] = UINT64_GET_BYTE(integer, 1);
out_bytes[5] = UINT64_GET_BYTE(integer, 2); out_bytes[5] = UINT64_GET_BYTE(integer, 2);
@@ -57,33 +55,35 @@ void otp_num_to_bytes(uint64_t integer, uint8_t* out_bytes)
OTP code if otp code was successfully generated OTP code if otp code was successfully generated
0 otherwise 0 otherwise
*/ */
uint32_t otp_generate(TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, uint8_t plain_secret_length, uint64_t input) uint32_t otp_generate(
{ TOTP_ALGO algo,
uint8_t* bytes = malloc(8); uint8_t digits,
const uint8_t* plain_secret,
uint8_t plain_secret_length,
uint64_t input) {
uint8_t* bytes = malloc(8);
memset(bytes, 0, 8); memset(bytes, 0, 8);
uint8_t* hmac = malloc(64); uint8_t* hmac = malloc(64);
memset(hmac, 0, 64); memset(hmac, 0, 64);
otp_num_to_bytes(input, bytes); otp_num_to_bytes(input, bytes);
int hmac_len = (*(algo))(plain_secret, plain_secret_length, bytes, 8, hmac); int hmac_len = (*(algo))(plain_secret, plain_secret_length, bytes, 8, hmac);
if (hmac_len == 0) { if(hmac_len == 0) {
free(hmac); free(hmac);
free(bytes); free(bytes);
return OTP_ERROR; return OTP_ERROR;
} }
uint64_t offset = (hmac[hmac_len-1] & 0xF);
uint64_t i_code =
((hmac[offset] & 0x7F) << 24 |
(hmac[offset + 1] & 0xFF) << 16 |
(hmac[offset + 2] & 0xFF) << 8 |
(hmac[offset + 3] & 0xFF));
i_code %= (uint64_t) pow(10, digits);
free(hmac); uint64_t offset = (hmac[hmac_len - 1] & 0xF);
free(bytes); uint64_t i_code =
return i_code; ((hmac[offset] & 0x7F) << 24 | (hmac[offset + 1] & 0xFF) << 16 |
(hmac[offset + 2] & 0xFF) << 8 | (hmac[offset + 3] & 0xFF));
i_code %= (uint64_t)pow(10, digits);
free(hmac);
free(bytes);
return i_code;
} }
/* /*
@@ -97,25 +97,52 @@ uint32_t otp_generate(TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secre
TOTP code if otp code was successfully generated TOTP code if otp code was successfully generated
0 otherwise 0 otherwise
*/ */
uint32_t totp_at(TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, uint8_t plain_secret_length, uint64_t for_time, float timezone, uint8_t interval) uint32_t totp_at(
{ TOTP_ALGO algo,
uint64_t for_time_adjusted = timezone_offset_apply(for_time, timezone_offset_from_hours(timezone)); uint8_t digits,
return otp_generate(algo, digits, plain_secret, plain_secret_length, totp_timecode(interval, for_time_adjusted)); const uint8_t* plain_secret,
uint8_t plain_secret_length,
uint64_t for_time,
float timezone,
uint8_t interval) {
uint64_t for_time_adjusted =
timezone_offset_apply(for_time, timezone_offset_from_hours(timezone));
return otp_generate(
algo,
digits,
plain_secret,
plain_secret_length,
totp_timecode(interval, for_time_adjusted));
} }
static int totp_algo_sha1(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, uint8_t* output) { static int totp_algo_sha1(
hmac_sha1(key, key_length, input, input_length, output); const uint8_t* key,
return HMAC_SHA1_RESULT_SIZE; uint8_t key_length,
const uint8_t* input,
uint8_t input_length,
uint8_t* output) {
hmac_sha1(key, key_length, input, input_length, output);
return HMAC_SHA1_RESULT_SIZE;
} }
static int totp_algo_sha256(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, uint8_t* output) { static int totp_algo_sha256(
hmac_sha256(key, key_length, input, input_length, output); const uint8_t* key,
return HMAC_SHA256_RESULT_SIZE; uint8_t key_length,
const uint8_t* input,
uint8_t input_length,
uint8_t* output) {
hmac_sha256(key, key_length, input, input_length, output);
return HMAC_SHA256_RESULT_SIZE;
} }
static int totp_algo_sha512(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, uint8_t* output) { static int totp_algo_sha512(
hmac_sha512(key, key_length, input, input_length, output); const uint8_t* key,
return HMAC_SHA512_RESULT_SIZE; uint8_t key_length,
const uint8_t* input,
uint8_t input_length,
uint8_t* output) {
hmac_sha512(key, key_length, input, input_length, output);
return HMAC_SHA512_RESULT_SIZE;
} }
const TOTP_ALGO TOTP_ALGO_SHA1 = (TOTP_ALGO)(&totp_algo_sha1); const TOTP_ALGO TOTP_ALGO_SHA1 = (TOTP_ALGO)(&totp_algo_sha1);

View File

@@ -3,7 +3,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#define OTP_ERROR (0) #define OTP_ERROR (0)
/* /*
Must compute HMAC using passed arguments, Must compute HMAC using passed arguments,
@@ -15,7 +15,12 @@
Must return 0 if error, or the length in bytes of the HMAC operation. Must return 0 if error, or the length in bytes of the HMAC operation.
*/ */
typedef int (*TOTP_ALGO)(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, uint8_t* output); typedef int (*TOTP_ALGO)(
const uint8_t* key,
uint8_t key_length,
const uint8_t* input,
uint8_t input_length,
uint8_t* output);
/* /*
Computes HMAC using SHA1 Computes HMAC using SHA1
@@ -38,4 +43,11 @@ extern const TOTP_ALGO TOTP_ALGO_SHA512;
TOTP token on success TOTP token on success
0 otherwise 0 otherwise
*/ */
uint32_t totp_at(TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, uint8_t plain_secret_length, uint64_t for_time, float timezone, uint8_t interval); uint32_t totp_at(
TOTP_ALGO algo,
uint8_t digits,
const uint8_t* plain_secret,
uint8_t plain_secret_length,
uint64_t for_time,
float timezone,
uint8_t interval);

View File

@@ -4,8 +4,9 @@
#define ICON_ARROW_LEFT_8x9_WIDTH 8 #define ICON_ARROW_LEFT_8x9_WIDTH 8
#define ICON_ARROW_LEFT_8x9_HEIGHT 9 #define ICON_ARROW_LEFT_8x9_HEIGHT 9
static const uint8_t ICON_ARROW_LEFT_8x9[] = { 0x80,0xe0,0xf8,0xfe,0xff,0xfe,0xf8,0xe0,0x80 }; static const uint8_t ICON_ARROW_LEFT_8x9[] = {0x80, 0xe0, 0xf8, 0xfe, 0xff, 0xfe, 0xf8, 0xe0, 0x80};
#define ICON_ARROW_RIGHT_8x9_WIDTH 8 #define ICON_ARROW_RIGHT_8x9_WIDTH 8
#define ICON_ARROW_RIGHT_8x9_HEIGHT 9 #define ICON_ARROW_RIGHT_8x9_HEIGHT 9
static const uint8_t ICON_ARROW_RIGHT_8x9[] = { 0x01,0x07,0x1f,0x7f,0xff,0x7f,0x1f,0x07,0x01 }; static const uint8_t ICON_ARROW_RIGHT_8x9[] =
{0x01, 0x07, 0x1f, 0x7f, 0xff, 0x7f, 0x1f, 0x07, 0x01};

View File

@@ -6,51 +6,115 @@
#define TEXT_BOX_MARGIN 4 #define TEXT_BOX_MARGIN 4
void ui_control_text_box_render(Canvas* const canvas, int8_t y, char* text, bool is_selected) { void ui_control_text_box_render(Canvas* const canvas, int8_t y, char* text, bool is_selected) {
if (y < -TEXT_BOX_HEIGHT) { if(y < -TEXT_BOX_HEIGHT) {
return; return;
} }
if (is_selected) { if(is_selected) {
canvas_draw_rframe(canvas, TEXT_BOX_MARGIN, TEXT_BOX_MARGIN + y, SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN, TEXT_BOX_HEIGHT, 0); canvas_draw_rframe(
canvas_draw_rframe(canvas, TEXT_BOX_MARGIN - 1, TEXT_BOX_MARGIN + y - 1, SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN + 2, TEXT_BOX_HEIGHT + 2, 1); canvas,
TEXT_BOX_MARGIN,
TEXT_BOX_MARGIN + y,
SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN,
TEXT_BOX_HEIGHT,
0);
canvas_draw_rframe(
canvas,
TEXT_BOX_MARGIN - 1,
TEXT_BOX_MARGIN + y - 1,
SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN + 2,
TEXT_BOX_HEIGHT + 2,
1);
} else { } else {
canvas_draw_rframe(canvas, TEXT_BOX_MARGIN, TEXT_BOX_MARGIN + y, SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN, TEXT_BOX_HEIGHT, 1); canvas_draw_rframe(
canvas,
TEXT_BOX_MARGIN,
TEXT_BOX_MARGIN + y,
SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN,
TEXT_BOX_HEIGHT,
1);
} }
canvas_draw_str_aligned(canvas, TEXT_BOX_MARGIN + 2, TEXT_BOX_MARGIN + 3 + y, AlignLeft, AlignTop, text); canvas_draw_str_aligned(
canvas, TEXT_BOX_MARGIN + 2, TEXT_BOX_MARGIN + 3 + y, AlignLeft, AlignTop, text);
} }
void ui_control_select_render(Canvas* const canvas, int16_t x, int16_t y, uint8_t width, char* text, bool is_selected) { void ui_control_select_render(
if (y < -TEXT_BOX_HEIGHT) { Canvas* const canvas,
int16_t x,
int16_t y,
uint8_t width,
char* text,
bool is_selected) {
if(y < -TEXT_BOX_HEIGHT) {
return; return;
} }
if (is_selected) { if(is_selected) {
canvas_draw_rframe(canvas, x + TEXT_BOX_MARGIN, TEXT_BOX_MARGIN + y, width - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN, TEXT_BOX_HEIGHT, 0); canvas_draw_rframe(
canvas_draw_rframe(canvas, x + TEXT_BOX_MARGIN - 1, TEXT_BOX_MARGIN + y - 1, width - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN + 2, TEXT_BOX_HEIGHT + 2, 1); canvas,
x + TEXT_BOX_MARGIN,
TEXT_BOX_MARGIN + y,
width - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN,
TEXT_BOX_HEIGHT,
0);
canvas_draw_rframe(
canvas,
x + TEXT_BOX_MARGIN - 1,
TEXT_BOX_MARGIN + y - 1,
width - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN + 2,
TEXT_BOX_HEIGHT + 2,
1);
} else { } else {
canvas_draw_rframe(canvas, x + TEXT_BOX_MARGIN, TEXT_BOX_MARGIN + y, width - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN, TEXT_BOX_HEIGHT, 1); canvas_draw_rframe(
canvas,
x + TEXT_BOX_MARGIN,
TEXT_BOX_MARGIN + y,
width - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN,
TEXT_BOX_HEIGHT,
1);
} }
canvas_draw_str_aligned(canvas, x + (width >> 1), TEXT_BOX_MARGIN + 3 + y, AlignCenter, AlignTop, text); canvas_draw_str_aligned(
canvas_draw_xbm(canvas, x + TEXT_BOX_MARGIN + 2, TEXT_BOX_MARGIN + 2 + y, ICON_ARROW_LEFT_8x9_WIDTH, ICON_ARROW_LEFT_8x9_HEIGHT, &ICON_ARROW_LEFT_8x9[0]); canvas, x + (width >> 1), TEXT_BOX_MARGIN + 3 + y, AlignCenter, AlignTop, text);
canvas_draw_xbm(canvas, x + width - TEXT_BOX_MARGIN - 10, TEXT_BOX_MARGIN + 2 + y, ICON_ARROW_RIGHT_8x9_WIDTH, ICON_ARROW_RIGHT_8x9_HEIGHT, &ICON_ARROW_RIGHT_8x9[0]); canvas_draw_xbm(
canvas,
x + TEXT_BOX_MARGIN + 2,
TEXT_BOX_MARGIN + 2 + y,
ICON_ARROW_LEFT_8x9_WIDTH,
ICON_ARROW_LEFT_8x9_HEIGHT,
&ICON_ARROW_LEFT_8x9[0]);
canvas_draw_xbm(
canvas,
x + width - TEXT_BOX_MARGIN - 10,
TEXT_BOX_MARGIN + 2 + y,
ICON_ARROW_RIGHT_8x9_WIDTH,
ICON_ARROW_RIGHT_8x9_HEIGHT,
&ICON_ARROW_RIGHT_8x9[0]);
} }
void ui_control_button_render(Canvas* const canvas, int16_t x, int16_t y, uint8_t width, uint8_t height, char* text, bool is_selected) { void ui_control_button_render(
if (y < -height) { Canvas* const canvas,
int16_t x,
int16_t y,
uint8_t width,
uint8_t height,
char* text,
bool is_selected) {
if(y < -height) {
return; return;
} }
if (is_selected) { if(is_selected) {
canvas_draw_rbox(canvas, x, y, width, height, 1); canvas_draw_rbox(canvas, x, y, width, height, 1);
canvas_set_color(canvas, ColorWhite); canvas_set_color(canvas, ColorWhite);
} else { } else {
canvas_draw_rframe(canvas, x, y, width, height, 1); canvas_draw_rframe(canvas, x, y, width, height, 1);
} }
canvas_draw_str_aligned(canvas, x + (width >> 1), y + (height >> 1) + 1, AlignCenter, AlignCenter, text); canvas_draw_str_aligned(
if (is_selected) { canvas, x + (width >> 1), y + (height >> 1) + 1, AlignCenter, AlignCenter, text);
if(is_selected) {
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
} }
} }

View File

@@ -4,5 +4,18 @@
#include <gui/gui.h> #include <gui/gui.h>
void ui_control_text_box_render(Canvas* const canvas, int8_t y, char* text, bool is_selected); void ui_control_text_box_render(Canvas* const canvas, int8_t y, char* text, bool is_selected);
void ui_control_button_render(Canvas* const canvas, int16_t x, int16_t y, uint8_t width, uint8_t height, char* text, bool is_selected); void ui_control_button_render(
void ui_control_select_render(Canvas* const canvas, int16_t x, int16_t y, uint8_t width, char* text, bool is_selected); Canvas* const canvas,
int16_t x,
int16_t y,
uint8_t width,
uint8_t height,
char* text,
bool is_selected);
void ui_control_select_render(
Canvas* const canvas,
int16_t x,
int16_t y,
uint8_t width,
char* text,
bool is_selected);

View File

@@ -23,7 +23,7 @@
static void render_callback(Canvas* const canvas, void* ctx) { static void render_callback(Canvas* const canvas, void* ctx) {
PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25); PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25);
if (plugin_state != NULL && !plugin_state->changing_scene) { if(plugin_state != NULL && !plugin_state->changing_scene) {
totp_scene_director_render(canvas, plugin_state); totp_scene_director_render(canvas, plugin_state);
} }
@@ -45,29 +45,43 @@ static bool totp_state_init(PluginState* const plugin_state) {
totp_scene_director_init_scenes(plugin_state); totp_scene_director_init_scenes(plugin_state);
if (plugin_state->crypto_verify_data == NULL) { if(plugin_state->crypto_verify_data == NULL) {
DialogMessage* message = dialog_message_alloc(); DialogMessage* message = dialog_message_alloc();
dialog_message_set_buttons(message, "No", NULL, "Yes"); dialog_message_set_buttons(message, "No", NULL, "Yes");
dialog_message_set_text(message, "Would you like to setup PIN?", SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter); dialog_message_set_text(
message,
"Would you like to setup PIN?",
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER,
AlignCenter,
AlignCenter);
DialogMessageButton dialog_result = dialog_message_show(plugin_state->dialogs, message); DialogMessageButton dialog_result = dialog_message_show(plugin_state->dialogs, message);
dialog_message_free(message); dialog_message_free(message);
if (dialog_result == DialogMessageButtonRight) { if(dialog_result == DialogMessageButtonRight) {
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
} else { } else {
totp_crypto_seed_iv(plugin_state, NULL, 0); totp_crypto_seed_iv(plugin_state, NULL, 0);
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
} }
} else if (plugin_state->pin_set) { } else if(plugin_state->pin_set) {
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
} else { } else {
totp_crypto_seed_iv(plugin_state, NULL, 0); totp_crypto_seed_iv(plugin_state, NULL, 0);
if (totp_crypto_verify_key(plugin_state)) { if(totp_crypto_verify_key(plugin_state)) {
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
} else { } else {
FURI_LOG_E(LOGGING_TAG, "Digital signature verification failed. Looks like conf file was created on another flipper and can't be used on any other"); FURI_LOG_E(
LOGGING_TAG,
"Digital signature verification failed. Looks like conf file was created on another flipper and can't be used on any other");
DialogMessage* message = dialog_message_alloc(); DialogMessage* message = dialog_message_alloc();
dialog_message_set_buttons(message, "Exit", NULL, NULL); dialog_message_set_buttons(message, "Exit", NULL, NULL);
dialog_message_set_text(message, "Digital signature verification failed", SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter); dialog_message_set_text(
message,
"Digital signature verification failed",
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER,
AlignCenter,
AlignCenter);
dialog_message_show(plugin_state->dialogs, message); dialog_message_show(plugin_state->dialogs, message);
dialog_message_free(message); dialog_message_free(message);
return false; return false;
@@ -88,7 +102,7 @@ static void dispose_plugin_state(PluginState* plugin_state) {
ListNode* node = plugin_state->tokens_list; ListNode* node = plugin_state->tokens_list;
ListNode* tmp; ListNode* tmp;
while (node != NULL) { while(node != NULL) {
tmp = node->next; tmp = node->next;
TokenInfo* tokenInfo = (TokenInfo*)node->data; TokenInfo* tokenInfo = (TokenInfo*)node->data;
token_info_free(tokenInfo); token_info_free(tokenInfo);
@@ -96,7 +110,7 @@ static void dispose_plugin_state(PluginState* plugin_state) {
node = tmp; node = tmp;
} }
if (plugin_state->crypto_verify_data != NULL) { if(plugin_state->crypto_verify_data != NULL) {
free(plugin_state->crypto_verify_data); free(plugin_state->crypto_verify_data);
} }
free(plugin_state); free(plugin_state);
@@ -106,7 +120,7 @@ int32_t totp_app() {
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
PluginState* plugin_state = malloc(sizeof(PluginState)); PluginState* plugin_state = malloc(sizeof(PluginState));
if (!totp_state_init(plugin_state)) { if(!totp_state_init(plugin_state)) {
FURI_LOG_E(LOGGING_TAG, "App state initialization failed\r\n"); FURI_LOG_E(LOGGING_TAG, "App state initialization failed\r\n");
dispose_plugin_state(plugin_state); dispose_plugin_state(plugin_state);
return 254; return 254;
@@ -131,18 +145,20 @@ int32_t totp_app() {
bool processing = true; bool processing = true;
uint32_t last_user_interaction_time = furi_get_tick(); uint32_t last_user_interaction_time = furi_get_tick();
while(processing) { while(processing) {
if (plugin_state->changing_scene) continue; if(plugin_state->changing_scene) continue;
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
PluginState* plugin_state = (PluginState*)acquire_mutex_block(&state_mutex); PluginState* plugin_state = (PluginState*)acquire_mutex_block(&state_mutex);
if(event_status == FuriStatusOk) { if(event_status == FuriStatusOk) {
if (event.type == EventTypeKey) { if(event.type == EventTypeKey) {
last_user_interaction_time = furi_get_tick(); last_user_interaction_time = furi_get_tick();
} }
processing = totp_scene_director_handle_event(&event, plugin_state); processing = totp_scene_director_handle_event(&event, plugin_state);
} else if (plugin_state->pin_set && plugin_state->current_scene != TotpSceneAuthentication && furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) { } else if(
plugin_state->pin_set && plugin_state->current_scene != TotpSceneAuthentication &&
furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) {
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
} }

View File

@@ -14,26 +14,34 @@ TokenInfo* token_info_alloc() {
} }
void token_info_free(TokenInfo* token_info) { void token_info_free(TokenInfo* token_info) {
if (token_info == NULL) return; if(token_info == NULL) return;
free(token_info->name); free(token_info->name);
free(token_info->token); free(token_info->token);
free(token_info); free(token_info);
} }
void token_info_set_secret(TokenInfo* token_info, const char* base32_token_secret, uint8_t token_secret_length, uint8_t* iv) { void token_info_set_secret(
TokenInfo* token_info,
const char* base32_token_secret,
uint8_t token_secret_length,
uint8_t* iv) {
uint8_t* plain_secret = malloc(token_secret_length); uint8_t* plain_secret = malloc(token_secret_length);
int plain_secret_length = base32_decode((uint8_t *)base32_token_secret, plain_secret, token_secret_length); int plain_secret_length =
base32_decode((uint8_t*)base32_token_secret, plain_secret, token_secret_length);
token_info->token = totp_crypto_encrypt(plain_secret, plain_secret_length, iv, &token_info->token_length); token_info->token =
totp_crypto_encrypt(plain_secret, plain_secret_length, iv, &token_info->token_length);
memset(plain_secret, 0, token_secret_length); memset(plain_secret, 0, token_secret_length);
free(plain_secret); free(plain_secret);
} }
uint8_t token_info_get_digits_count(TokenInfo* token_info) { uint8_t token_info_get_digits_count(TokenInfo* token_info) {
switch (token_info->digits) { switch(token_info->digits) {
case TOTP_6_DIGITS: return 6; case TOTP_6_DIGITS:
case TOTP_8_DIGITS: return 8; return 6;
case TOTP_8_DIGITS:
return 8;
} }
return 6; return 6;

View File

@@ -2,16 +2,9 @@
#include <inttypes.h> #include <inttypes.h>
typedef enum { typedef enum { SHA1, SHA256, SHA512 } TokenHashAlgo;
SHA1,
SHA256,
SHA512
} TokenHashAlgo;
typedef enum { typedef enum { TOTP_6_DIGITS, TOTP_8_DIGITS } TokenDigitsCount;
TOTP_6_DIGITS,
TOTP_8_DIGITS
} TokenDigitsCount;
typedef struct { typedef struct {
uint8_t* token; uint8_t* token;
@@ -23,5 +16,9 @@ typedef struct {
TokenInfo* token_info_alloc(); TokenInfo* token_info_alloc();
void token_info_free(TokenInfo* token_info); void token_info_free(TokenInfo* token_info);
void token_info_set_secret(TokenInfo* token_info, const char* base32_token_secret, uint8_t token_secret_length, uint8_t* iv); void token_info_set_secret(
TokenInfo* token_info,
const char* base32_token_secret,
uint8_t token_secret_length,
uint8_t* iv);
uint8_t token_info_get_digits_count(TokenInfo* token_info); uint8_t token_info_get_digits_count(TokenInfo* token_info);