diff --git a/applications/external/totp/application.fam b/applications/external/totp/application.fam index 4d9fe4634..aba01fe73 100644 --- a/applications/external/totp/application.fam +++ b/applications/external/totp/application.fam @@ -15,7 +15,7 @@ App( ], stack_size=2 * 1024, order=20, - fap_version="2.3", + fap_version="3.20", fap_author="Alexander Kopachov (@akopachov)", fap_description="Software-based TOTP authenticator for Flipper Zero device", fap_weburl="https://github.com/akopachov/flipper-zero_authenticator", diff --git a/applications/external/totp/cli/cli.c b/applications/external/totp/cli/cli.c index c860b5a36..4cb68ce83 100644 --- a/applications/external/totp/cli/cli.c +++ b/applications/external/totp/cli/cli.c @@ -16,6 +16,10 @@ #include "commands/automation/automation.h" #include "commands/details/details.h" +struct TotpCliContext { + PluginState* plugin_state; +}; + static void totp_cli_print_unknown_command(const FuriString* unknown_command) { TOTP_CLI_PRINTF_ERROR( "Command \"%s\" is unknown. Use \"" TOTP_CLI_COMMAND_HELP @@ -63,7 +67,7 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) { } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_AUTOMATION) == 0) { totp_cli_command_automation_handle(plugin_state, args, cli); } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_RESET) == 0) { - totp_cli_command_reset_handle(plugin_state, cli, cli_context->event_queue); + totp_cli_command_reset_handle(plugin_state, cli); } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_UPDATE) == 0) { totp_cli_command_update_handle(plugin_state, args, cli); } else if( @@ -77,13 +81,11 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) { furi_string_free(cmd); } -TotpCliContext* - totp_cli_register_command_handler(PluginState* plugin_state, FuriMessageQueue* event_queue) { +TotpCliContext* totp_cli_register_command_handler(PluginState* plugin_state) { Cli* cli = furi_record_open(RECORD_CLI); TotpCliContext* context = malloc(sizeof(TotpCliContext)); furi_check(context != NULL); context->plugin_state = plugin_state; - context->event_queue = event_queue; cli_add_command( cli, TOTP_CLI_COMMAND_NAME, CliCommandFlagParallelSafe, totp_cli_handler, context); furi_record_close(RECORD_CLI); diff --git a/applications/external/totp/cli/cli.h b/applications/external/totp/cli/cli.h index 2e4b92db8..13afef78f 100644 --- a/applications/external/totp/cli/cli.h +++ b/applications/external/totp/cli/cli.h @@ -3,11 +3,17 @@ #include #include "../types/plugin_state.h" -typedef struct { - PluginState* plugin_state; - FuriMessageQueue* event_queue; -} TotpCliContext; +typedef struct TotpCliContext TotpCliContext; -TotpCliContext* - totp_cli_register_command_handler(PluginState* plugin_state, FuriMessageQueue* event_queue); +/** + * @brief Registers TOTP CLI handler + * @param plugin_state application state + * @return TOTP CLI context + */ +TotpCliContext* totp_cli_register_command_handler(PluginState* plugin_state); + +/** + * @brief Unregisters TOTP CLI handler + * @param context application state + */ void totp_cli_unregister_command_handler(TotpCliContext* context); \ No newline at end of file diff --git a/applications/external/totp/cli/cli_helpers.h b/applications/external/totp/cli/cli_helpers.h index b8f4f236a..9c40bff13 100644 --- a/applications/external/totp/cli/cli_helpers.h +++ b/applications/external/totp/cli/cli_helpers.h @@ -33,12 +33,14 @@ extern const char* TOTP_CLI_COLOR_INFO; #define TOTP_CLI_PRINTF_INFO(format, ...) \ TOTP_CLI_PRINTF_COLORFUL(TOTP_CLI_COLOR_INFO, format, ##__VA_ARGS__) -#define TOTP_CLI_LOCK_UI(plugin_state) \ - Scene __previous_scene = plugin_state->current_scene; \ - totp_scene_director_activate_scene(plugin_state, TotpSceneStandby) +#define TOTP_CLI_LOCK_UI(plugin_state) \ + Scene __previous_scene = plugin_state->current_scene; \ + totp_scene_director_activate_scene(plugin_state, TotpSceneStandby); \ + totp_scene_director_force_redraw(plugin_state) -#define TOTP_CLI_UNLOCK_UI(plugin_state) \ - totp_scene_director_activate_scene(plugin_state, __previous_scene) +#define TOTP_CLI_UNLOCK_UI(plugin_state) \ + totp_scene_director_activate_scene(plugin_state, __previous_scene); \ + totp_scene_director_force_redraw(plugin_state) /** * @brief Checks whether user is authenticated and entered correct PIN. @@ -109,6 +111,6 @@ void totp_cli_print_error_updating_config_file(); void totp_cli_print_error_loading_token_info(); /** - * @brief Prints message to let user knwo that command is processing now + * @brief Prints message to let user know that command is processing now */ void totp_cli_print_processing(); \ No newline at end of file diff --git a/applications/external/totp/cli/commands/add/add.c b/applications/external/totp/cli/commands/add/add.c index fa64bd41c..d2bf8b907 100644 --- a/applications/external/totp/cli/commands/add/add.c +++ b/applications/external/totp/cli/commands/add/add.c @@ -11,7 +11,7 @@ struct TotpAddContext { FuriString* args; Cli* cli; - uint8_t* iv; + const CryptoSettings* crypto_settings; }; enum TotpIteratorUpdateTokenResultsEx { @@ -54,7 +54,7 @@ static TotpIteratorUpdateTokenResult // Reading token secret furi_string_reset(temp_str); - TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]\r\n"); + TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]:\r\n"); if(!totp_cli_read_line(context_t->cli, temp_str, mask_user_input)) { totp_cli_delete_last_line(); furi_string_secure_free(temp_str); @@ -68,7 +68,7 @@ static TotpIteratorUpdateTokenResult furi_string_get_cstr(temp_str), furi_string_size(temp_str), token_secret_encoding, - context_t->iv); + context_t->crypto_settings); furi_string_secure_free(temp_str); @@ -166,7 +166,8 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl TOTP_CLI_LOCK_UI(plugin_state); - struct TotpAddContext add_context = {.args = args, .cli = cli, .iv = &plugin_state->iv[0]}; + struct TotpAddContext add_context = { + .args = args, .cli = cli, .crypto_settings = &plugin_state->crypto_settings}; TotpIteratorUpdateTokenResult add_result = totp_token_info_iterator_add_new_token(iterator_context, &add_token_handler, &add_context); diff --git a/applications/external/totp/cli/commands/automation/automation.c b/applications/external/totp/cli/commands/automation/automation.c index c9f6ac34b..87c121dbe 100644 --- a/applications/external/totp/cli/commands/automation/automation.c +++ b/applications/external/totp/cli/commands/automation/automation.c @@ -7,17 +7,23 @@ #define TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD "automation" #define TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE "none" #define TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB "usb" -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED #define TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT "bt" #endif +#define TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTY "QWERTY" +#define TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_AZERTY "AZERTY" +#define TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT_PREFIX "-k" +#define TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT "layout" void totp_cli_command_automation_docopt_commands() { - TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_AUTOMATION " Get or set automation method\r\n"); + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_AUTOMATION " Get or set automation settings\r\n"); } void totp_cli_command_automation_docopt_usage() { - TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_AUTOMATION " " DOCOPT_OPTIONAL( - DOCOPT_MULTIPLE(DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD))) "\r\n"); + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_AUTOMATION " " DOCOPT_OPTIONAL(DOCOPT_OPTION( + TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT_PREFIX, + DOCOPT_ARGUMENT( + TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT))) " " DOCOPT_OPTIONAL(DOCOPT_MULTIPLE(DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD))) "\r\n"); } void totp_cli_command_automation_docopt_arguments() { @@ -25,24 +31,33 @@ void totp_cli_command_automation_docopt_arguments() { " " TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD " Automation method to be set. Must be one of: " TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE ", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED ", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT #endif "\r\n"); } -static void totp_cli_command_automation_print_method(AutomationMethod method, const char* color) { -#ifdef TOTP_BADBT_TYPE_ENABLED +void totp_cli_command_automation_docopt_options() { + TOTP_CLI_PRINTF(" " DOCOPT_OPTION( + TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT_PREFIX, + DOCOPT_ARGUMENT( + TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT)) " Automation keyboard layout. Must be one of: " TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTY + ", " TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_AZERTY + "\r\n"); +} + +static void print_method(AutomationMethod method, const char* color) { +#ifdef TOTP_BADBT_AUTOMATION_ENABLED bool has_previous_method = false; #endif if(method & AutomationMethodBadUsb) { TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB "\""); -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED has_previous_method = true; #endif } -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED if(method & AutomationMethodBadBt) { if(has_previous_method) { TOTP_CLI_PRINTF_COLORFUL(color, " and "); @@ -57,6 +72,37 @@ static void totp_cli_command_automation_print_method(AutomationMethod method, co } } +static void print_kb_layout(AutomationKeyboardLayout layout, const char* color) { + char* layoutToPrint; + switch(layout) { + case AutomationKeyboardLayoutQWERTY: + layoutToPrint = TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTY; + break; + case AutomationKeyboardLayoutAZERTY: + layoutToPrint = TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_AZERTY; + break; + default: + furi_crash("Unknown automation keyboard layout"); + break; + } + + TOTP_CLI_PRINTF_COLORFUL(color, "%s", layoutToPrint); +} + +static bool + parse_automation_keyboard_layout(const FuriString* str, AutomationKeyboardLayout* out) { + bool result = true; + if(furi_string_cmpi_str(str, TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_QWERTY) == 0) { + *out = AutomationKeyboardLayoutQWERTY; + } else if(furi_string_cmpi_str(str, TOTP_CLI_COMMAND_AUTOMATION_LAYOUT_AZERTY) == 0) { + *out = AutomationKeyboardLayoutAZERTY; + } else { + result = false; + } + + return result; +} + void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* args, Cli* cli) { if(!totp_cli_ensure_authenticated(plugin_state, cli)) { return; @@ -65,6 +111,7 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a FuriString* temp_str = furi_string_alloc(); bool new_method_provided = false; AutomationMethod new_method = AutomationMethodNone; + AutomationKeyboardLayout new_kb_layout = plugin_state->automation_kb_layout; bool args_valid = true; while(args_read_string_and_trim(args, temp_str)) { if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE) == 0) { @@ -74,13 +121,19 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a new_method_provided = true; new_method |= AutomationMethodBadUsb; } -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT) == 0) { new_method_provided = true; new_method |= AutomationMethodBadBt; } #endif - else { + else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_ARG_KB_LAYOUT_PREFIX) == 0) { + if(!args_read_string_and_trim(args, temp_str) || + !parse_automation_keyboard_layout(temp_str, &new_kb_layout)) { + args_valid = false; + break; + } + } else { args_valid = false; break; } @@ -96,15 +149,19 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a TOTP_CLI_LOCK_UI(plugin_state); plugin_state->automation_method = new_method; + plugin_state->automation_kb_layout = new_kb_layout; if(totp_config_file_update_automation_method(plugin_state)) { TOTP_CLI_PRINTF_SUCCESS("Automation method is set to "); - totp_cli_command_automation_print_method(new_method, TOTP_CLI_COLOR_SUCCESS); + print_method(new_method, TOTP_CLI_COLOR_SUCCESS); + TOTP_CLI_PRINTF_SUCCESS(" ("); + print_kb_layout(plugin_state->automation_kb_layout, TOTP_CLI_COLOR_SUCCESS); + TOTP_CLI_PRINTF_SUCCESS(")"); cli_nl(); } else { totp_cli_print_error_updating_config_file(); } -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED if(!(new_method & AutomationMethodBadBt) && plugin_state->bt_type_code_worker_context != NULL) { totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); @@ -115,8 +172,10 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* a TOTP_CLI_UNLOCK_UI(plugin_state); } else { TOTP_CLI_PRINTF_INFO("Current automation method is "); - totp_cli_command_automation_print_method( - plugin_state->automation_method, TOTP_CLI_COLOR_INFO); + print_method(plugin_state->automation_method, TOTP_CLI_COLOR_INFO); + TOTP_CLI_PRINTF_INFO(" ("); + print_kb_layout(plugin_state->automation_kb_layout, TOTP_CLI_COLOR_INFO); + TOTP_CLI_PRINTF_INFO(")"); cli_nl(); } } while(false); diff --git a/applications/external/totp/cli/commands/automation/automation.h b/applications/external/totp/cli/commands/automation/automation.h index fb62e638e..4a713d49b 100644 --- a/applications/external/totp/cli/commands/automation/automation.h +++ b/applications/external/totp/cli/commands/automation/automation.h @@ -8,4 +8,5 @@ void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* args, Cli* cli); void totp_cli_command_automation_docopt_commands(); void totp_cli_command_automation_docopt_usage(); -void totp_cli_command_automation_docopt_arguments(); \ No newline at end of file +void totp_cli_command_automation_docopt_arguments(); +void totp_cli_command_automation_docopt_options(); \ No newline at end of file diff --git a/applications/external/totp/cli/commands/help/help.c b/applications/external/totp/cli/commands/help/help.c index cc47db11f..7093877ea 100644 --- a/applications/external/totp/cli/commands/help/help.c +++ b/applications/external/totp/cli/commands/help/help.c @@ -64,4 +64,6 @@ void totp_cli_command_help_handle() { totp_cli_command_add_docopt_options(); totp_cli_command_update_docopt_options(); totp_cli_command_delete_docopt_options(); + totp_cli_command_pin_docopt_options(); + totp_cli_command_automation_docopt_options(); } \ No newline at end of file diff --git a/applications/external/totp/cli/commands/pin/pin.c b/applications/external/totp/cli/commands/pin/pin.c index 62531b96a..2b989a713 100644 --- a/applications/external/totp/cli/commands/pin/pin.c +++ b/applications/external/totp/cli/commands/pin/pin.c @@ -7,19 +7,35 @@ #include "../../../services/config/config.h" #include "../../cli_helpers.h" #include -#include "../../../services/crypto/crypto.h" +#include "../../../services/crypto/crypto_facade.h" #include "../../../ui/scene_director.h" #define TOTP_CLI_COMMAND_PIN_COMMAND_SET "set" #define TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE "remove" +#define TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT_PREFIX "-c" +#define TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT "slot" void totp_cli_command_pin_docopt_commands() { TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_PIN " Set\\change\\remove PIN\r\n"); } void totp_cli_command_pin_docopt_usage() { - TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_PIN " " DOCOPT_REQUIRED( - TOTP_CLI_COMMAND_PIN_COMMAND_SET " | " TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) "\r\n"); + TOTP_CLI_PRINTF( + " " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_PIN + " " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_PIN_COMMAND_SET " | " TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) " " DOCOPT_OPTIONAL( + DOCOPT_OPTION( + TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT_PREFIX, + DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT))) "\r\n"); +} + +void totp_cli_command_pin_docopt_options() { + TOTP_CLI_PRINTF( + " " DOCOPT_OPTION( + TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT_PREFIX, + DOCOPT_ARGUMENT( + TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT)) " New crypto key slot. Must be between %d and %d\r\n", + ACCEPTABLE_CRYPTO_KEY_SLOT_START, + ACCEPTABLE_CRYPTO_KEY_SLOT_END); } static inline uint8_t totp_cli_key_to_pin_code(uint8_t key) { @@ -89,35 +105,49 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl bool do_change = false; bool do_remove = false; - UNUSED(do_remove); - if(args_read_string_and_trim(args, temp_str)) { + uint8_t crypto_key_slot = plugin_state->crypto_settings.crypto_key_slot; + + bool arguments_parsed = true; + while(args_read_string_and_trim(args, temp_str)) { if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_SET) == 0) { do_change = true; } else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) == 0) { do_remove = true; + } else if( + furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_ARG_NEW_CRYPTO_KEY_SLOT_PREFIX) == + 0) { + if(!args_read_uint8_and_trim(args, &crypto_key_slot) || + !totp_crypto_check_key_slot(crypto_key_slot)) { + TOTP_CLI_PRINTF_ERROR("Slot \"%" PRIu8 "\" can not be used\r\n", crypto_key_slot); + arguments_parsed = false; + break; + } } else { totp_cli_print_invalid_arguments(); + arguments_parsed = false; + break; } - } else { - totp_cli_print_invalid_arguments(); } - if((do_change || do_remove) && totp_cli_ensure_authenticated(plugin_state, cli)) { + if(!(do_change || do_remove) || (do_change && do_remove)) { + totp_cli_print_invalid_arguments(); + arguments_parsed = false; + } + + if(arguments_parsed && totp_cli_ensure_authenticated(plugin_state, cli)) { TOTP_CLI_LOCK_UI(plugin_state); do { - uint8_t old_iv[TOTP_IV_SIZE]; - memcpy(&old_iv[0], &plugin_state->iv[0], TOTP_IV_SIZE); - uint8_t new_pin[TOTP_IV_SIZE]; - memset(&new_pin[0], 0, TOTP_IV_SIZE); + uint8_t new_pin[CRYPTO_IV_LENGTH]; + memset(&new_pin[0], 0, CRYPTO_IV_LENGTH); uint8_t new_pin_length = 0; if(do_change) { if(!totp_cli_read_pin(cli, &new_pin[0], &new_pin_length)) { - memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE); + memset_s(&new_pin[0], CRYPTO_IV_LENGTH, 0, CRYPTO_IV_LENGTH); break; } } else if(do_remove) { new_pin_length = 0; - memset(&new_pin[0], 0, TOTP_IV_SIZE); + memset(&new_pin[0], 0, CRYPTO_IV_LENGTH); } char* backup_path = totp_config_file_backup(plugin_state); @@ -127,7 +157,7 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl "Once you make sure everything is fine and works as expected, please delete this backup file\r\n"); free(backup_path); } else { - memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE); + memset_s(&new_pin[0], CRYPTO_IV_LENGTH, 0, CRYPTO_IV_LENGTH); TOTP_CLI_PRINTF_ERROR( "An error has occurred during taking backup of config file\r\n"); break; @@ -135,10 +165,10 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl TOTP_CLI_PRINTF("Encrypting...\r\n"); - bool update_result = - totp_config_file_update_encryption(plugin_state, new_pin, new_pin_length); + bool update_result = totp_config_file_update_encryption( + plugin_state, crypto_key_slot, new_pin, new_pin_length); - memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE); + memset_s(&new_pin[0], CRYPTO_IV_LENGTH, 0, CRYPTO_IV_LENGTH); totp_cli_delete_last_line(); diff --git a/applications/external/totp/cli/commands/pin/pin.h b/applications/external/totp/cli/commands/pin/pin.h index 1308ae736..2d320a02a 100644 --- a/applications/external/totp/cli/commands/pin/pin.h +++ b/applications/external/totp/cli/commands/pin/pin.h @@ -7,4 +7,5 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cli* cli); void totp_cli_command_pin_docopt_commands(); -void totp_cli_command_pin_docopt_usage(); \ No newline at end of file +void totp_cli_command_pin_docopt_usage(); +void totp_cli_command_pin_docopt_options(); \ No newline at end of file diff --git a/applications/external/totp/cli/commands/reset/reset.c b/applications/external/totp/cli/commands/reset/reset.c index 96b2cc56a..250d594bf 100644 --- a/applications/external/totp/cli/commands/reset/reset.c +++ b/applications/external/totp/cli/commands/reset/reset.c @@ -17,10 +17,7 @@ void totp_cli_command_reset_docopt_usage() { TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_RESET "\r\n"); } -void totp_cli_command_reset_handle( - PluginState* plugin_state, - Cli* cli, - FuriMessageQueue* event_queue) { +void totp_cli_command_reset_handle(PluginState* plugin_state, Cli* cli) { TOTP_CLI_LOCK_UI(plugin_state); TOTP_CLI_PRINTF_WARNING( "As a result of reset all the settings and tokens will be permanently lost.\r\n"); @@ -35,7 +32,7 @@ void totp_cli_command_reset_handle( totp_config_file_reset(plugin_state); TOTP_CLI_PRINTF_SUCCESS("Application has been successfully reset to default.\r\n"); TOTP_CLI_PRINTF_SUCCESS("Now application will be closed to apply all the changes.\r\n"); - totp_cli_force_close_app(event_queue); + totp_cli_force_close_app(plugin_state->event_queue); } else { TOTP_CLI_PRINTF_INFO("Action was not confirmed by user\r\n"); TOTP_CLI_UNLOCK_UI(plugin_state); diff --git a/applications/external/totp/cli/commands/reset/reset.h b/applications/external/totp/cli/commands/reset/reset.h index 3a4675587..221c84304 100644 --- a/applications/external/totp/cli/commands/reset/reset.h +++ b/applications/external/totp/cli/commands/reset/reset.h @@ -5,9 +5,6 @@ #define TOTP_CLI_COMMAND_RESET "reset" -void totp_cli_command_reset_handle( - PluginState* plugin_state, - Cli* cli, - FuriMessageQueue* event_queue); +void totp_cli_command_reset_handle(PluginState* plugin_state, Cli* cli); void totp_cli_command_reset_docopt_commands(); void totp_cli_command_reset_docopt_usage(); \ No newline at end of file diff --git a/applications/external/totp/cli/commands/update/update.c b/applications/external/totp/cli/commands/update/update.c index 49beb7b6d..79ed75670 100644 --- a/applications/external/totp/cli/commands/update/update.c +++ b/applications/external/totp/cli/commands/update/update.c @@ -13,7 +13,7 @@ struct TotpUpdateContext { FuriString* args; Cli* cli; - uint8_t* iv; + const CryptoSettings* crypto_settings; }; enum TotpIteratorUpdateTokenResultsEx { @@ -83,7 +83,7 @@ static TotpIteratorUpdateTokenResult if(update_token_secret) { // Reading token secret furi_string_reset(temp_str); - TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]\r\n"); + TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]:\r\n"); bool token_secret_read = totp_cli_read_line(context_t->cli, temp_str, mask_user_input); totp_cli_delete_last_line(); if(!token_secret_read) { @@ -96,7 +96,7 @@ static TotpIteratorUpdateTokenResult furi_string_get_cstr(temp_str), furi_string_size(temp_str), token_secret_encoding, - context_t->iv)) { + context_t->crypto_settings)) { furi_string_secure_free(temp_str); return TotpIteratorUpdateTokenResultInvalidSecret; } @@ -151,7 +151,7 @@ void totp_cli_command_update_handle(PluginState* plugin_state, FuriString* args, totp_token_info_iterator_go_to(iterator_context, token_number - 1); struct TotpUpdateContext update_context = { - .args = args, .cli = cli, .iv = &plugin_state->iv[0]}; + .args = args, .cli = cli, .crypto_settings = &plugin_state->crypto_settings}; TotpIteratorUpdateTokenResult update_result = totp_token_info_iterator_update_current_token( iterator_context, &update_token_handler, &update_context); diff --git a/applications/external/totp/cli/common_command_arguments.h b/applications/external/totp/cli/common_command_arguments.h index be1c0bdfe..0bf834225 100644 --- a/applications/external/totp/cli/common_command_arguments.h +++ b/applications/external/totp/cli/common_command_arguments.h @@ -18,32 +18,87 @@ #define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING_PREFIX "-e" #define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING "encoding" +/** + * @brief Prints information about unknown argument + * @param arg + */ void totp_cli_printf_unknown_argument(const FuriString* arg); +/** + * @brief Prints information about missed required argument + * @param arg + */ void totp_cli_printf_missed_argument_value(char* arg); +/** + * @brief Tries to read token hashing algo + * @param token_info token info to set parsed algo to if successfully read and parsed + * @param arg argument to parse + * @param args rest of arguments + * @param[out] parsed will be set to \c true if token hashing algo sucecssfully read and parsed; \c false otherwise + * @return \c true if \c arg represents token hashing algo argument; \c false otherwise + */ bool totp_cli_try_read_algo(TokenInfo* token_info, FuriString* arg, FuriString* args, bool* parsed); +/** + * @brief Tries to read token digits count + * @param token_info token info to set parsed digits count to if successfully read and parsed + * @param arg argument to parse + * @param args rest of arguments + * @param[out] parsed will be set to \c true if token digits count sucecssfully read and parsed; \c false otherwise + * @return \c true if \c arg represents token digits count argument; \c false otherwise + */ bool totp_cli_try_read_digits( TokenInfo* token_info, const FuriString* arg, FuriString* args, bool* parsed); +/** + * @brief Tries to read token duration + * @param token_info token info to set parsed duration to if successfully read and parsed + * @param arg argument to parse + * @param args rest of arguments + * @param[out] parsed will be set to \c true if token duration sucecssfully read and parsed; \c false otherwise + * @return \c true if \c arg represents token duration argument; \c false otherwise + */ bool totp_cli_try_read_duration( TokenInfo* token_info, const FuriString* arg, FuriString* args, bool* parsed); +/** + * @brief Tries to read token automation features + * @param token_info token info to set parsed automation features to if successfully read and parsed + * @param arg argument to parse + * @param args rest of arguments + * @param[out] parsed will be set to \c true if token automation features sucecssfully read and parsed; \c false otherwise + * @return \c true if \c arg represents token automation features argument; \c false otherwise + */ bool totp_cli_try_read_automation_features( TokenInfo* token_info, FuriString* arg, FuriString* args, bool* parsed); +/** + * @brief Tries to read unsecure flag + * @param arg argument to parse + * @param[out] parsed will be set to \c true if unsecure flag sucecssfully read and parsed; \c false otherwise + * @param[out] unsecure_flag will be set to parsed unsecure flag state if read and parsed successfully + * @return \c true if \c arg represents unsecure flag argument; \c false otherwise + */ bool totp_cli_try_read_unsecure_flag(const FuriString* arg, bool* parsed, bool* unsecure_flag); +/** + * @brief Tries to read plain token secret encoding + * @param arg argument to parse + * @param args rest of arguments + * @param[out] parsed will be set to \c true if plain token secret encoding sucecssfully read and parsed; \c false otherwise + * @param[out] secret_encoding will be set to parsed plain token secret encoding if read and parsed successfully + * @return \c true if \c arg represents plain token secret encoding argument; \c false otherwise + */ bool totp_cli_try_read_plain_token_secret_encoding( FuriString* arg, FuriString* args, diff --git a/applications/external/totp/features_config.h b/applications/external/totp/features_config.h index 54bbaba94..764f27bea 100644 --- a/applications/external/totp/features_config.h +++ b/applications/external/totp/features_config.h @@ -4,13 +4,8 @@ #endif // Include Bluetooth token input automation -#ifndef TOTP_NO_BADBT_TYPE -#define TOTP_BADBT_TYPE_ENABLED -#endif - -// Include token input automation icons on the main screen -#ifndef TOTP_NO_AUTOMATION_ICONS -#define TOTP_AUTOMATION_ICONS_ENABLED +#ifndef TOTP_NO_BADBT_AUTOMATION +#define TOTP_BADBT_AUTOMATION_ENABLED #endif // List of compatible firmwares @@ -19,6 +14,7 @@ #define TOTP_FIRMWARE_XTREME_UL (3) // End of list +// Target firmware #ifndef TOTP_TARGET_FIRMWARE #define TOTP_TARGET_FIRMWARE TOTP_FIRMWARE_XTREME_UL #endif diff --git a/applications/external/totp/images/totp_arrow_bottom_10x5.png b/applications/external/totp/images/totp_arrow_bottom_10x5.png deleted file mode 100644 index 54e22f5ef..000000000 Binary files a/applications/external/totp/images/totp_arrow_bottom_10x5.png and /dev/null differ diff --git a/applications/external/totp/services/config/config.c b/applications/external/totp/services/config/config.c index 5b7cd936e..19b1cf368 100644 --- a/applications/external/totp/services/config/config.c +++ b/applications/external/totp/services/config/config.c @@ -9,7 +9,8 @@ #include "../../types/common.h" #include "../../types/token_info.h" #include "../../features_config.h" -#include "../crypto/crypto.h" +#include "../crypto/crypto_facade.h" +#include "../crypto/constants.h" #include "migrations/common_migration.h" #define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf" @@ -110,7 +111,16 @@ static char* totp_config_file_backup_i(Storage* storage) { static bool totp_open_config_file(Storage* storage, FlipperFormat** file) { FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - if(storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK) { + bool conf_file_exists = storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK; + if(!conf_file_exists) { + FURI_LOG_I(LOGGING_TAG, "Application catalog needs to be migrated"); + FS_Error migration_result = + storage_common_migrate(storage, EXT_PATH("authenticator"), CONFIG_FILE_DIRECTORY_PATH); + FURI_LOG_I(LOGGING_TAG, "Migrated catalog. Result code: %d", (int)migration_result); + conf_file_exists = storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK; + } + + if(conf_file_exists) { FURI_LOG_D(LOGGING_TAG, "Config file %s found", 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); @@ -119,16 +129,6 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) { } } else { 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) { - FURI_LOG_D( - 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); - return false; - } - } if(!flipper_format_file_open_new(fff_data_file, CONFIG_FILE_PATH)) { totp_close_config_file(fff_data_file); @@ -139,6 +139,13 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) { flipper_format_write_header_cstr( fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION); + uint32_t tmp_uint32 = CRYPTO_LATEST_VERSION; + flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &tmp_uint32, 1); + + tmp_uint32 = DEFAULT_CRYPTO_KEY_SLOT; + flipper_format_write_uint32( + fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &tmp_uint32, 1); + flipper_format_write_comment_cstr( fff_data_file, "Config file format specification can be found here: https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md"); @@ -146,7 +153,7 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) { float tmp_tz = 0; flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1); - uint32_t tmp_uint32 = NotificationMethodSound | NotificationMethodVibro; + tmp_uint32 = NotificationMethodSound | NotificationMethodVibro; flipper_format_write_uint32( fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1); @@ -154,7 +161,11 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) { flipper_format_write_uint32( fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1); - tmp_uint32 = 0; + tmp_uint32 = AutomationKeyboardLayoutQWERTY; + flipper_format_write_uint32( + fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1); + + tmp_uint32 = 0; //-V1048 flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1); if(!flipper_format_rewind(fff_data_file)) { @@ -233,6 +244,12 @@ bool totp_config_file_update_automation_method(const PluginState* plugin_state) break; } + tmp_uint32 = plugin_state->automation_kb_layout; + if(!flipper_format_insert_or_update_uint32( + file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1)) { + break; + } + update_result = true; } while(false); @@ -265,6 +282,12 @@ bool totp_config_file_update_user_settings(const PluginState* plugin_state) { break; } + tmp_uint32 = plugin_state->automation_kb_layout; + if(!flipper_format_insert_or_update_uint32( + file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1)) { + break; + } + update_result = true; } while(false); @@ -344,8 +367,38 @@ bool totp_config_file_load(PluginState* const plugin_state) { } } + uint32_t tmp_uint32; + + if(!flipper_format_read_uint32( + fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &tmp_uint32, 1)) { + FURI_LOG_E(LOGGING_TAG, "Missing required " TOTP_CONFIG_KEY_CRYPTO_VERSION "property"); + break; + } + + plugin_state->crypto_settings.crypto_version = tmp_uint32; + + if(!flipper_format_rewind(fff_data_file)) { + break; + } + + if(!flipper_format_read_uint32( + fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &tmp_uint32, 1)) { + FURI_LOG_E( + LOGGING_TAG, "Missing required " TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT "property"); + break; + } + + plugin_state->crypto_settings.crypto_key_slot = tmp_uint32; + + if(!flipper_format_rewind(fff_data_file)) { + break; + } + if(!flipper_format_read_hex( - fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE)) { + fff_data_file, + TOTP_CONFIG_KEY_BASE_IV, + &plugin_state->crypto_settings.base_iv[0], + CRYPTO_IV_LENGTH)) { FURI_LOG_D(LOGGING_TAG, "Missing base IV"); } @@ -357,22 +410,23 @@ bool totp_config_file_load(PluginState* const plugin_state) { 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); - furi_check(plugin_state->crypto_verify_data != NULL); - plugin_state->crypto_verify_data_length = crypto_size; + plugin_state->crypto_settings.crypto_verify_data = + malloc(sizeof(uint8_t) * crypto_size); + furi_check(plugin_state->crypto_settings.crypto_verify_data != NULL); + plugin_state->crypto_settings.crypto_verify_data_length = crypto_size; if(!flipper_format_read_hex( fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, - plugin_state->crypto_verify_data, + plugin_state->crypto_settings.crypto_verify_data, crypto_size)) { FURI_LOG_D(LOGGING_TAG, "Missing crypto verify token"); - free(plugin_state->crypto_verify_data); - plugin_state->crypto_verify_data = NULL; - plugin_state->crypto_verify_data_length = 0; + free(plugin_state->crypto_settings.crypto_verify_data); + plugin_state->crypto_settings.crypto_verify_data = NULL; + plugin_state->crypto_settings.crypto_verify_data_length = 0; } } else { - plugin_state->crypto_verify_data = NULL; - plugin_state->crypto_verify_data_length = 0; + plugin_state->crypto_settings.crypto_verify_data = NULL; + plugin_state->crypto_settings.crypto_verify_data_length = 0; } if(!flipper_format_rewind(fff_data_file)) { @@ -390,13 +444,17 @@ bool totp_config_file_load(PluginState* const plugin_state) { } if(!flipper_format_read_bool( - fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) { - plugin_state->pin_set = true; + fff_data_file, + TOTP_CONFIG_KEY_PINSET, + &plugin_state->crypto_settings.pin_required, + 1)) { + plugin_state->crypto_settings.pin_required = true; } - flipper_format_rewind(fff_data_file); + if(!flipper_format_rewind(fff_data_file)) { + break; + } - uint32_t tmp_uint32; if(!flipper_format_read_uint32( fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) { tmp_uint32 = NotificationMethodSound | NotificationMethodVibro; @@ -404,7 +462,9 @@ bool totp_config_file_load(PluginState* const plugin_state) { plugin_state->notification_method = tmp_uint32; - flipper_format_rewind(fff_data_file); + if(!flipper_format_rewind(fff_data_file)) { + break; + } if(!flipper_format_read_uint32( fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) { @@ -413,6 +473,21 @@ bool totp_config_file_load(PluginState* const plugin_state) { plugin_state->automation_method = tmp_uint32; + if(!flipper_format_rewind(fff_data_file)) { + break; + } + + if(!flipper_format_read_uint32( + fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1)) { + tmp_uint32 = AutomationKeyboardLayoutQWERTY; + } + + plugin_state->automation_kb_layout = tmp_uint32; + + if(!flipper_format_rewind(fff_data_file)) { + break; + } + if(!flipper_format_read_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1)) { tmp_uint32 = 0; } @@ -425,7 +500,9 @@ bool totp_config_file_load(PluginState* const plugin_state) { plugin_state->config_file_context->config_file = fff_data_file; plugin_state->config_file_context->token_info_iterator_context = totp_token_info_iterator_alloc( - storage, plugin_state->config_file_context->config_file, plugin_state->iv); + storage, + plugin_state->config_file_context->config_file, + &plugin_state->crypto_settings); result = true; } while(false); @@ -438,21 +515,39 @@ bool totp_config_file_update_crypto_signatures(const PluginState* plugin_state) flipper_format_rewind(config_file); bool update_result = false; do { + uint32_t tmp_uint32 = plugin_state->crypto_settings.crypto_version; + if(!flipper_format_insert_or_update_uint32( + config_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &tmp_uint32, 1)) { + break; + } + + tmp_uint32 = plugin_state->crypto_settings.crypto_key_slot; + if(!flipper_format_insert_or_update_uint32( + config_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &tmp_uint32, 1)) { + break; + } + if(!flipper_format_insert_or_update_hex( - config_file, TOTP_CONFIG_KEY_BASE_IV, plugin_state->base_iv, TOTP_IV_SIZE)) { + config_file, + TOTP_CONFIG_KEY_BASE_IV, + plugin_state->crypto_settings.base_iv, + CRYPTO_IV_LENGTH)) { break; } if(!flipper_format_insert_or_update_hex( config_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, - plugin_state->crypto_verify_data, - plugin_state->crypto_verify_data_length)) { + plugin_state->crypto_settings.crypto_verify_data, + plugin_state->crypto_settings.crypto_verify_data_length)) { break; } if(!flipper_format_insert_or_update_bool( - config_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) { + config_file, + TOTP_CONFIG_KEY_PINSET, + &plugin_state->crypto_settings.pin_required, + 1)) { break; } @@ -480,6 +575,7 @@ void totp_config_file_reset(PluginState* const plugin_state) { bool totp_config_file_update_encryption( PluginState* plugin_state, + uint8_t new_crypto_key_slot, const uint8_t* new_pin, uint8_t new_pin_length) { FlipperFormat* config_file = plugin_state->config_file_context->config_file; @@ -489,23 +585,28 @@ bool totp_config_file_update_encryption( return false; } - uint8_t old_iv[TOTP_IV_SIZE]; - memcpy(&old_iv[0], &plugin_state->iv[0], TOTP_IV_SIZE); - - memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE); - memset(&plugin_state->base_iv[0], 0, TOTP_IV_SIZE); - if(plugin_state->crypto_verify_data != NULL) { - free(plugin_state->crypto_verify_data); - plugin_state->crypto_verify_data = NULL; + if(!totp_crypto_check_key_slot(new_crypto_key_slot)) { + return false; } - CryptoSeedIVResult seed_result = - totp_crypto_seed_iv(plugin_state, new_pin_length > 0 ? new_pin : NULL, new_pin_length); + CryptoSettings old_crypto_settings = plugin_state->crypto_settings; + + memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH); + memset(&plugin_state->crypto_settings.base_iv[0], 0, CRYPTO_IV_LENGTH); + if(plugin_state->crypto_settings.crypto_verify_data != NULL) { + free(plugin_state->crypto_settings.crypto_verify_data); + plugin_state->crypto_settings.crypto_verify_data = NULL; + } + + plugin_state->crypto_settings.crypto_key_slot = new_crypto_key_slot; + plugin_state->crypto_settings.crypto_version = CRYPTO_LATEST_VERSION; + + CryptoSeedIVResult seed_result = totp_crypto_seed_iv( + &plugin_state->crypto_settings, new_pin_length > 0 ? new_pin : NULL, new_pin_length); if(seed_result & CryptoSeedIVResultFlagSuccess && - seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) { - if(!totp_config_file_update_crypto_signatures(plugin_state)) { - return false; - } + seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData && + !totp_config_file_update_crypto_signatures(plugin_state)) { + return false; } else if(seed_result == CryptoSeedIVResultFailed) { return false; } @@ -552,12 +653,15 @@ bool totp_config_file_update_encryption( size_t plain_token_length; uint8_t* plain_token = totp_crypto_decrypt( - encrypted_token, secret_bytes_count, &old_iv[0], &plain_token_length); + encrypted_token, secret_bytes_count, &old_crypto_settings, &plain_token_length); free(encrypted_token); size_t encrypted_token_length; encrypted_token = totp_crypto_encrypt( - plain_token, plain_token_length, &plugin_state->iv[0], &encrypted_token_length); + plain_token, + plain_token_length, + &plugin_state->crypto_settings, + &encrypted_token_length); memset_s(plain_token, plain_token_length, 0, plain_token_length); free(plain_token); @@ -588,6 +692,36 @@ bool totp_config_file_update_encryption( return result; } +bool totp_config_file_ensure_latest_encryption( + PluginState* plugin_state, + const uint8_t* pin, + uint8_t pin_length) { + bool result = true; + if(plugin_state->crypto_settings.crypto_version < CRYPTO_LATEST_VERSION) { + FURI_LOG_I(LOGGING_TAG, "Migration to crypto v%d is needed", CRYPTO_LATEST_VERSION); + char* backup_path = totp_config_file_backup(plugin_state); + if(backup_path != NULL) { + free(backup_path); + uint8_t crypto_key_slot = plugin_state->crypto_settings.crypto_key_slot; + if(!totp_crypto_check_key_slot(crypto_key_slot)) { + crypto_key_slot = DEFAULT_CRYPTO_KEY_SLOT; + } + + result = + totp_config_file_update_encryption(plugin_state, crypto_key_slot, pin, pin_length); + FURI_LOG_I( + LOGGING_TAG, + "Migration to crypto v%d is done. Result: %d", + CRYPTO_LATEST_VERSION, + result); + } else { + result = false; + } + } + + return result; +} + TokenInfoIteratorContext* totp_config_get_token_iterator_context(const PluginState* plugin_state) { return plugin_state->config_file_context->token_info_iterator_context; } \ No newline at end of file diff --git a/applications/external/totp/services/config/config.h b/applications/external/totp/services/config/config.h index d2fe957c6..38bc06ba2 100644 --- a/applications/external/totp/services/config/config.h +++ b/applications/external/totp/services/config/config.h @@ -73,15 +73,29 @@ void totp_config_file_close(PluginState* const plugin_state); /** * @brief Updates config file encryption by re-encrypting it using new user's PIN and new randomly generated IV * @param plugin_state application state + * @param new_crypto_key_slot new crypto key slot to be used * @param new_pin new user's PIN * @param new_pin_length new user's PIN length * @return \c true if config file encryption successfully updated; \c false otherwise */ bool totp_config_file_update_encryption( PluginState* plugin_state, + uint8_t new_crypto_key_slot, const uint8_t* new_pin, uint8_t new_pin_length); +/** + * @brief Ensures application config file uses latest encryption and upgrades encryption if needed + * @param plugin_state application state + * @param pin user's PIN + * @param pin_length user's PIN length + * @return \c true if operation succeeded; \c false otherwise + */ +bool totp_config_file_ensure_latest_encryption( + PluginState* plugin_state, + const uint8_t* pin, + uint8_t pin_length); + /** * @brief Gets token info iterator context * @param plugin_state application state diff --git a/applications/external/totp/services/config/constants.h b/applications/external/totp/services/config/constants.h index ba6658fb5..1205bae07 100644 --- a/applications/external/totp/services/config/constants.h +++ b/applications/external/totp/services/config/constants.h @@ -2,9 +2,9 @@ #include -#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator") +#define CONFIG_FILE_DIRECTORY_PATH STORAGE_APP_DATA_PATH_PREFIX #define CONFIG_FILE_HEADER "Flipper TOTP plugin config file" -#define CONFIG_FILE_ACTUAL_VERSION (6) +#define CONFIG_FILE_ACTUAL_VERSION (8) #define TOTP_CONFIG_KEY_TIMEZONE "Timezone" #define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName" @@ -18,4 +18,7 @@ #define TOTP_CONFIG_KEY_PINSET "PinIsSet" #define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod" #define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod" +#define TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT "AutomationKbLayout" #define TOTP_CONFIG_KEY_FONT "Font" +#define TOTP_CONFIG_KEY_CRYPTO_VERSION "CryptoVersion" +#define TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT "CryptoKeySlot" diff --git a/applications/external/totp/services/config/migrations/common_migration.c b/applications/external/totp/services/config/migrations/common_migration.c index e8537da0b..4a12cbd3a 100644 --- a/applications/external/totp/services/config/migrations/common_migration.c +++ b/applications/external/totp/services/config/migrations/common_migration.c @@ -1,6 +1,7 @@ #include "common_migration.h" #include "../constants.h" #include "../../../types/token_info.h" +#include "../../../types/automation_kb_layout.h" #include bool totp_config_migrate_to_latest( @@ -17,6 +18,28 @@ bool totp_config_migrate_to_latest( break; } + if(flipper_format_read_string( + fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, temp_str)) { + flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, temp_str); + } else { + uint32_t old_crypto_version = 1; + flipper_format_write_uint32( + fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &old_crypto_version, 1); + } + + flipper_format_rewind(fff_backup_data_file); + + if(flipper_format_read_string( + fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, temp_str)) { + flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, temp_str); + } else { + uint32_t default_old_key_slot = 2; + flipper_format_write_uint32( + fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &default_old_key_slot, 1); + } + + flipper_format_rewind(fff_backup_data_file); + 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); } @@ -68,6 +91,21 @@ bool totp_config_migrate_to_latest( flipper_format_rewind(fff_backup_data_file); + if(flipper_format_read_string( + fff_backup_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, temp_str)) { + flipper_format_write_string( + fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, temp_str); + } else { + uint32_t default_automation_kb_layout = AutomationKeyboardLayoutQWERTY; + flipper_format_write_uint32( + fff_data_file, + TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, + &default_automation_kb_layout, + 1); + } + + flipper_format_rewind(fff_backup_data_file); + while(true) { if(!flipper_format_read_string( fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) { diff --git a/applications/external/totp/services/config/token_info_iterator.c b/applications/external/totp/services/config/token_info_iterator.c index 1f4a75776..75424ef43 100644 --- a/applications/external/totp/services/config/token_info_iterator.c +++ b/applications/external/totp/services/config/token_info_iterator.c @@ -4,6 +4,7 @@ #include #include #include "../../types/common.h" +#include "../../types/crypto_settings.h" #define CONFIG_FILE_PART_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf.part" #define STREAM_COPY_BUFFER_SIZE 128 @@ -15,7 +16,7 @@ struct TokenInfoIteratorContext { size_t last_seek_index; TokenInfo* current_token; FlipperFormat* config_file; - uint8_t* iv; + CryptoSettings* crypto_settings; Storage* storage; }; @@ -237,8 +238,10 @@ static bool return result; } -TokenInfoIteratorContext* - totp_token_info_iterator_alloc(Storage* storage, FlipperFormat* config_file, uint8_t* iv) { +TokenInfoIteratorContext* totp_token_info_iterator_alloc( + Storage* storage, + FlipperFormat* config_file, + CryptoSettings* crypto_settings) { Stream* stream = flipper_format_get_raw_stream(config_file); stream_rewind(stream); size_t tokens_count = 0; @@ -256,7 +259,7 @@ TokenInfoIteratorContext* context->total_count = tokens_count; context->current_token = token_info_alloc(); context->config_file = config_file; - context->iv = iv; + context->crypto_settings = crypto_settings; context->storage = storage; return context; } @@ -453,7 +456,7 @@ bool totp_token_info_iterator_go_to(TokenInfoIteratorContext* context, size_t to furi_string_get_cstr(temp_str), furi_string_size(temp_str), PlainTokenSecretEncodingBase32, - context->iv)) { + context->crypto_settings)) { FURI_LOG_W( LOGGING_TAG, "Token \"%s\" has plain secret", diff --git a/applications/external/totp/services/config/token_info_iterator.h b/applications/external/totp/services/config/token_info_iterator.h index 7e9a65853..ce4d8c72b 100644 --- a/applications/external/totp/services/config/token_info_iterator.h +++ b/applications/external/totp/services/config/token_info_iterator.h @@ -28,11 +28,13 @@ enum TotpIteratorUpdateTokenResults { * @brief Initializes a new token info iterator * @param storage storage reference * @param config_file config file to use - * @param iv initialization vector (IV) to be used for encryption\decryption + * @param crypto_settings crypto settings * @return Token info iterator context */ -TokenInfoIteratorContext* - totp_token_info_iterator_alloc(Storage* storage, FlipperFormat* config_file, uint8_t* iv); +TokenInfoIteratorContext* totp_token_info_iterator_alloc( + Storage* storage, + FlipperFormat* config_file, + CryptoSettings* crypto_settings); /** * @brief Navigates iterator to the token with given index diff --git a/applications/external/totp/services/crypto/common_types.h b/applications/external/totp/services/crypto/common_types.h new file mode 100644 index 000000000..fb8e4c83c --- /dev/null +++ b/applications/external/totp/services/crypto/common_types.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +typedef uint8_t CryptoSeedIVResult; + +enum CryptoSeedIVResults { + + /** + * @brief IV seeding operation failed + */ + CryptoSeedIVResultFailed = 0b00, + + /** + * @brief IV seeding operation succeeded + */ + CryptoSeedIVResultFlagSuccess = 0b01, + + /** + * @brief As a part of IV seeding operation new crypto verify data has been generated + */ + CryptoSeedIVResultFlagNewCryptoVerifyData = 0b10 +}; \ No newline at end of file diff --git a/applications/external/totp/services/crypto/constants.h b/applications/external/totp/services/crypto/constants.h new file mode 100644 index 000000000..294ae4361 --- /dev/null +++ b/applications/external/totp/services/crypto/constants.h @@ -0,0 +1,11 @@ +#pragma once + +#define CRYPTO_IV_LENGTH (16) + +// According to this explanation: https://github.com/flipperdevices/flipperzero-firmware/issues/2885#issuecomment-1646664666 +// disabling usage of any key which is "the same across all devices" +#define ACCEPTABLE_CRYPTO_KEY_SLOT_START (12) +#define ACCEPTABLE_CRYPTO_KEY_SLOT_END (100) + +#define DEFAULT_CRYPTO_KEY_SLOT ACCEPTABLE_CRYPTO_KEY_SLOT_START +#define CRYPTO_LATEST_VERSION (2) \ No newline at end of file diff --git a/applications/external/totp/services/crypto/crypto_facade.c b/applications/external/totp/services/crypto/crypto_facade.c new file mode 100644 index 000000000..acbc09a4e --- /dev/null +++ b/applications/external/totp/services/crypto/crypto_facade.c @@ -0,0 +1,78 @@ +#include "crypto_facade.h" +#include +#include +#include "crypto_v1.h" +#include "crypto_v2.h" +#include "constants.h" + +bool totp_crypto_check_key_slot(uint8_t key_slot) { + uint8_t empty_iv[CRYPTO_IV_LENGTH] = {0}; + if(key_slot < ACCEPTABLE_CRYPTO_KEY_SLOT_START || key_slot > ACCEPTABLE_CRYPTO_KEY_SLOT_END) { + return false; + } + + return furi_hal_crypto_verify_key(key_slot) && + furi_hal_crypto_store_load_key(key_slot, empty_iv) && + furi_hal_crypto_store_unload_key(key_slot); +} + +uint8_t* totp_crypto_encrypt( + const uint8_t* plain_data, + const size_t plain_data_length, + const CryptoSettings* crypto_settings, + size_t* encrypted_data_length) { + if(crypto_settings->crypto_version == 1) { + return totp_crypto_encrypt_v1( + plain_data, plain_data_length, crypto_settings, encrypted_data_length); + } + + if(crypto_settings->crypto_version == 2) { + return totp_crypto_encrypt_v2( + plain_data, plain_data_length, crypto_settings, encrypted_data_length); + } + + furi_crash("Unsupported crypto version"); +} + +uint8_t* totp_crypto_decrypt( + const uint8_t* encrypted_data, + const size_t encrypted_data_length, + const CryptoSettings* crypto_settings, + size_t* decrypted_data_length) { + if(crypto_settings->crypto_version == 1) { + return totp_crypto_decrypt_v1( + encrypted_data, encrypted_data_length, crypto_settings, decrypted_data_length); + } + + if(crypto_settings->crypto_version == 2) { + return totp_crypto_decrypt_v2( + encrypted_data, encrypted_data_length, crypto_settings, decrypted_data_length); + } + + furi_crash("Unsupported crypto version"); +} + +CryptoSeedIVResult + totp_crypto_seed_iv(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length) { + if(crypto_settings->crypto_version == 1) { + return totp_crypto_seed_iv_v1(crypto_settings, pin, pin_length); + } + + if(crypto_settings->crypto_version == 2) { + return totp_crypto_seed_iv_v2(crypto_settings, pin, pin_length); + } + + furi_crash("Unsupported crypto version"); +} + +bool totp_crypto_verify_key(const CryptoSettings* crypto_settings) { + if(crypto_settings->crypto_version == 1) { + return totp_crypto_verify_key_v1(crypto_settings); + } + + if(crypto_settings->crypto_version == 2) { + return totp_crypto_verify_key_v2(crypto_settings); + } + + furi_crash("Unsupported crypto version"); +} \ No newline at end of file diff --git a/applications/external/totp/services/crypto/crypto.h b/applications/external/totp/services/crypto/crypto_facade.h similarity index 58% rename from applications/external/totp/services/crypto/crypto.h rename to applications/external/totp/services/crypto/crypto_facade.h index ab27191a8..bbcbf7c00 100644 --- a/applications/external/totp/services/crypto/crypto.h +++ b/applications/external/totp/services/crypto/crypto_facade.h @@ -1,68 +1,59 @@ #pragma once -#include "../../types/plugin_state.h" +#include +#include +#include +#include "../../types/crypto_settings.h" +#include "common_types.h" -typedef uint8_t CryptoSeedIVResult; - -enum CryptoSeedIVResults { - - /** - * @brief IV seeding operation failed - */ - CryptoSeedIVResultFailed = 0b00, - - /** - * @brief IV seeding operation succeeded - */ - CryptoSeedIVResultFlagSuccess = 0b01, - - /** - * @brief As a part of IV seeding operation new crypto verify data has been generated - */ - CryptoSeedIVResultFlagNewCryptoVerifyData = 0b10 -}; +/** + * @brief Checks whether key slot can be used for encryption purposes + * @param key_slot key slot index + * @return \c true if key slot can be used for encryption; \c false otherwise + */ +bool totp_crypto_check_key_slot(uint8_t key_slot); /** * @brief Encrypts plain data using built-in certificate and given initialization vector (IV) * @param plain_data plain data to be encrypted * @param plain_data_length plain data length - * @param iv initialization vector (IV) to be used to encrypt plain data + * @param crypto_settings crypto settings * @param[out] encrypted_data_length encrypted data length * @return Encrypted data */ uint8_t* totp_crypto_encrypt( const uint8_t* plain_data, const size_t plain_data_length, - const uint8_t* iv, + const CryptoSettings* crypto_settings, size_t* encrypted_data_length); /** * @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV) * @param encrypted_data encrypted data to be decrypted * @param encrypted_data_length encrypted data length - * @param iv initialization vector (IV) to be used to encrypt plain data + * @param crypto_settings crypto settings * @param[out] decrypted_data_length decrypted data length * @return Decrypted data */ uint8_t* totp_crypto_decrypt( const uint8_t* encrypted_data, const size_t encrypted_data_length, - const uint8_t* iv, + const CryptoSettings* crypto_settings, size_t* decrypted_data_length); /** * @brief Seed initialization vector (IV) using user's PIN - * @param plugin_state application state + * @param crypto_settings crypto settings * @param pin user's PIN * @param pin_length user's PIN length * @return Results of seeding IV */ CryptoSeedIVResult - totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length); + totp_crypto_seed_iv(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length); /** * @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption - * @param plugin_state application state + * @param crypto_settings crypto settings * @return \c true if cryptographic information is valid; \c false otherwise */ -bool totp_crypto_verify_key(const PluginState* plugin_state); \ No newline at end of file +bool totp_crypto_verify_key(const CryptoSettings* crypto_settings); diff --git a/applications/external/totp/services/crypto/crypto.c b/applications/external/totp/services/crypto/crypto_v1.c similarity index 66% rename from applications/external/totp/services/crypto/crypto.c rename to applications/external/totp/services/crypto/crypto_v1.c index 95ddc3210..d637599f5 100644 --- a/applications/external/totp/services/crypto/crypto.c +++ b/applications/external/totp/services/crypto/crypto_v1.c @@ -1,4 +1,6 @@ -#include "crypto.h" +#include "crypto_v1.h" +#include +#include #include #include #include @@ -8,13 +10,14 @@ #define CRYPTO_KEY_SLOT (2) #define CRYPTO_VERIFY_KEY_LENGTH (16) #define CRYPTO_ALIGNMENT_FACTOR (16) +#define TOTP_IV_SIZE (16) static const char* CRYPTO_VERIFY_KEY = "FFF_Crypto_pass"; -uint8_t* totp_crypto_encrypt( +uint8_t* totp_crypto_encrypt_v1( const uint8_t* plain_data, const size_t plain_data_length, - const uint8_t* iv, + const CryptoSettings* crypto_settings, size_t* encrypted_data_length) { uint8_t* encrypted_data; size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR; @@ -29,7 +32,7 @@ uint8_t* totp_crypto_encrypt( furi_check(encrypted_data != NULL); *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, crypto_settings->iv); furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length); furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT); @@ -40,7 +43,7 @@ uint8_t* totp_crypto_encrypt( furi_check(encrypted_data != NULL); *encrypted_data_length = plain_data_length; - furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv); + furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, crypto_settings->iv); furi_hal_crypto_encrypt(plain_data, encrypted_data, plain_data_length); furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT); } @@ -48,29 +51,31 @@ uint8_t* totp_crypto_encrypt( return encrypted_data; } -uint8_t* totp_crypto_decrypt( +uint8_t* totp_crypto_decrypt_v1( const uint8_t* encrypted_data, const size_t encrypted_data_length, - const uint8_t* iv, + const CryptoSettings* crypto_settings, size_t* decrypted_data_length) { *decrypted_data_length = encrypted_data_length; uint8_t* decrypted_data = malloc(*decrypted_data_length); furi_check(decrypted_data != NULL); - furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv); + furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, crypto_settings->iv); furi_hal_crypto_decrypt(encrypted_data, decrypted_data, encrypted_data_length); furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT); return decrypted_data; } -CryptoSeedIVResult - totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) { +CryptoSeedIVResult totp_crypto_seed_iv_v1( + CryptoSettings* crypto_settings, + const uint8_t* pin, + uint8_t pin_length) { CryptoSeedIVResult result; - if(plugin_state->crypto_verify_data == NULL) { + if(crypto_settings->crypto_verify_data == NULL) { FURI_LOG_I(LOGGING_TAG, "Generating new IV"); - furi_hal_random_fill_buf(&plugin_state->base_iv[0], TOTP_IV_SIZE); + furi_hal_random_fill_buf(&crypto_settings->base_iv[0], TOTP_IV_SIZE); } - memcpy(&plugin_state->iv[0], &plugin_state->base_iv[0], TOTP_IV_SIZE); + memcpy(&crypto_settings->iv[0], &crypto_settings->base_iv[0], TOTP_IV_SIZE); if(pin != NULL && pin_length > 0) { uint8_t max_i; if(pin_length > TOTP_IV_SIZE) { @@ -80,7 +85,7 @@ CryptoSeedIVResult } for(uint8_t i = 0; i < max_i; i++) { - plugin_state->iv[i] = plugin_state->iv[i] ^ (uint8_t)(pin[i] * (i + 1)); + crypto_settings->iv[i] = crypto_settings->iv[i] ^ (uint8_t)(pin[i] * (i + 1)); } } else { uint8_t max_i; @@ -93,24 +98,24 @@ CryptoSeedIVResult const uint8_t* uid = (const uint8_t*)UID64_BASE; //-V566 for(uint8_t i = 0; i < max_i; i++) { - plugin_state->iv[i] = plugin_state->iv[i] ^ uid[i]; + crypto_settings->iv[i] = crypto_settings->iv[i] ^ uid[i]; } } result = CryptoSeedIVResultFlagSuccess; - if(plugin_state->crypto_verify_data == NULL) { + if(crypto_settings->crypto_verify_data == NULL) { FURI_LOG_I(LOGGING_TAG, "Generating crypto verify data"); - plugin_state->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH); - furi_check(plugin_state->crypto_verify_data != NULL); - plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH; + crypto_settings->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH); + furi_check(crypto_settings->crypto_verify_data != NULL); + crypto_settings->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH; - plugin_state->crypto_verify_data = totp_crypto_encrypt( + crypto_settings->crypto_verify_data = totp_crypto_encrypt_v1( (const uint8_t*)CRYPTO_VERIFY_KEY, CRYPTO_VERIFY_KEY_LENGTH, - &plugin_state->iv[0], - &plugin_state->crypto_verify_data_length); + crypto_settings, + &crypto_settings->crypto_verify_data_length); - plugin_state->pin_set = pin != NULL && pin_length > 0; + crypto_settings->pin_required = pin != NULL && pin_length > 0; result |= CryptoSeedIVResultFlagNewCryptoVerifyData; } @@ -118,12 +123,12 @@ CryptoSeedIVResult return result; } -bool totp_crypto_verify_key(const PluginState* plugin_state) { +bool totp_crypto_verify_key_v1(const CryptoSettings* crypto_settings) { size_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], + uint8_t* decrypted_key = totp_crypto_decrypt_v1( + crypto_settings->crypto_verify_data, + crypto_settings->crypto_verify_data_length, + crypto_settings, &decrypted_key_length); bool key_valid = true; diff --git a/applications/external/totp/services/crypto/crypto_v1.h b/applications/external/totp/services/crypto/crypto_v1.h new file mode 100644 index 000000000..80e850196 --- /dev/null +++ b/applications/external/totp/services/crypto/crypto_v1.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include +#include "../../types/crypto_settings.h" +#include "common_types.h" + +/** + * @brief Encrypts plain data using built-in certificate and given initialization vector (IV) + * @param plain_data plain data to be encrypted + * @param plain_data_length plain data length + * @param crypto_settings crypto settings + * @param[out] encrypted_data_length encrypted data length + * @return Encrypted data + */ +uint8_t* totp_crypto_encrypt_v1( + const uint8_t* plain_data, + const size_t plain_data_length, + const CryptoSettings* crypto_settings, + size_t* encrypted_data_length); + +/** + * @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV) + * @param encrypted_data encrypted data to be decrypted + * @param encrypted_data_length encrypted data length + * @param crypto_settings crypto settings + * @param[out] decrypted_data_length decrypted data length + * @return Decrypted data + */ +uint8_t* totp_crypto_decrypt_v1( + const uint8_t* encrypted_data, + const size_t encrypted_data_length, + const CryptoSettings* crypto_settings, + size_t* decrypted_data_length); + +/** + * @brief Seed initialization vector (IV) using user's PIN + * @param crypto_settings crypto settings + * @param pin user's PIN + * @param pin_length user's PIN length + * @return Results of seeding IV + */ +CryptoSeedIVResult + totp_crypto_seed_iv_v1(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length); + +/** + * @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption + * @param crypto_settings crypto settings + * @return \c true if cryptographic information is valid; \c false otherwise + */ +bool totp_crypto_verify_key_v1(const CryptoSettings* crypto_settings); \ No newline at end of file diff --git a/applications/external/totp/services/crypto/crypto_v2.c b/applications/external/totp/services/crypto/crypto_v2.c new file mode 100644 index 000000000..897a7fd32 --- /dev/null +++ b/applications/external/totp/services/crypto/crypto_v2.c @@ -0,0 +1,184 @@ +#include "crypto_v2.h" +#include +#include +#include +#include +#include +#include "../../types/common.h" +#include "../hmac/hmac_sha512.h" +#include "memset_s.h" +#include "constants.h" + +#define CRYPTO_ALIGNMENT_FACTOR (16) + +static const uint8_t* get_device_uid() { + return (const uint8_t*)UID64_BASE; //-V566 +} + +static uint8_t get_device_uid_length() { + return furi_hal_version_uid_size(); +} + +static const uint8_t* get_crypto_verify_key() { + return get_device_uid(); +} + +static uint8_t get_crypto_verify_key_length() { + return get_device_uid_length(); +} + +uint8_t* totp_crypto_encrypt_v2( + const uint8_t* plain_data, + const size_t plain_data_length, + const CryptoSettings* crypto_settings, + size_t* encrypted_data_length) { + uint8_t* encrypted_data; + size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR; + if(remain) { + size_t plain_data_aligned_length = plain_data_length - remain + CRYPTO_ALIGNMENT_FACTOR; + uint8_t* plain_data_aligned = malloc(plain_data_aligned_length); + furi_check(plain_data_aligned != NULL); + memset(plain_data_aligned, 0, plain_data_aligned_length); + memcpy(plain_data_aligned, plain_data, plain_data_length); + + encrypted_data = malloc(plain_data_aligned_length); + furi_check(encrypted_data != NULL); + *encrypted_data_length = plain_data_aligned_length; + + furi_check( + furi_hal_crypto_store_load_key(crypto_settings->crypto_key_slot, crypto_settings->iv), + "Encryption failed: store_load_key"); + furi_check( + furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length), + "Encryption failed: encrypt"); + furi_check( + furi_hal_crypto_store_unload_key(crypto_settings->crypto_key_slot), + "Encryption failed: store_unload_key"); + + memset_s(plain_data_aligned, plain_data_aligned_length, 0, plain_data_aligned_length); + free(plain_data_aligned); + } else { + encrypted_data = malloc(plain_data_length); + furi_check(encrypted_data != NULL); + *encrypted_data_length = plain_data_length; + + furi_check( + furi_hal_crypto_store_load_key(crypto_settings->crypto_key_slot, crypto_settings->iv), + "Encryption failed: store_load_key"); + furi_check( + furi_hal_crypto_encrypt(plain_data, encrypted_data, plain_data_length), + "Encryption failed: encrypt"); + furi_check( + furi_hal_crypto_store_unload_key(crypto_settings->crypto_key_slot), + "Encryption failed: store_unload_key"); + } + + return encrypted_data; +} + +uint8_t* totp_crypto_decrypt_v2( + const uint8_t* encrypted_data, + const size_t encrypted_data_length, + const CryptoSettings* crypto_settings, + size_t* decrypted_data_length) { + *decrypted_data_length = encrypted_data_length; + uint8_t* decrypted_data = malloc(*decrypted_data_length); + furi_check(decrypted_data != NULL); + furi_check( + furi_hal_crypto_store_load_key(crypto_settings->crypto_key_slot, crypto_settings->iv), + "Decryption failed: store_load_key"); + furi_check( + furi_hal_crypto_decrypt(encrypted_data, decrypted_data, encrypted_data_length), + "Decryption failed: decrypt"); + furi_check( + furi_hal_crypto_store_unload_key(crypto_settings->crypto_key_slot), + "Decryption failed: store_unload_key"); + return decrypted_data; +} + +CryptoSeedIVResult totp_crypto_seed_iv_v2( + CryptoSettings* crypto_settings, + const uint8_t* pin, + uint8_t pin_length) { + CryptoSeedIVResult result; + if(crypto_settings->crypto_verify_data == NULL) { + FURI_LOG_I(LOGGING_TAG, "Generating new IV"); + furi_hal_random_fill_buf(&crypto_settings->base_iv[0], CRYPTO_IV_LENGTH); + } + + memcpy(&crypto_settings->iv[0], &crypto_settings->base_iv[0], CRYPTO_IV_LENGTH); + + const uint8_t* device_uid = get_device_uid(); + uint8_t device_uid_length = get_device_uid_length(); + + uint8_t hmac_key_length = device_uid_length; + if(pin != NULL && pin_length > 0) { + hmac_key_length += pin_length; + } + + uint8_t* hmac_key = malloc(hmac_key_length); + furi_check(hmac_key != NULL); + + memcpy(hmac_key, device_uid, device_uid_length); + + if(pin != NULL && pin_length > 0) { + memcpy(hmac_key + device_uid_length, pin, pin_length); + } + + uint8_t hmac[HMAC_SHA512_RESULT_SIZE] = {0}; + int hmac_result_code = hmac_sha512( + hmac_key, hmac_key_length, &crypto_settings->base_iv[0], CRYPTO_IV_LENGTH, &hmac[0]); + + memset_s(hmac_key, hmac_key_length, 0, hmac_key_length); + free(hmac_key); + + if(hmac_result_code == 0) { + uint8_t offset = + hmac[HMAC_SHA512_RESULT_SIZE - 1] % (HMAC_SHA512_RESULT_SIZE - CRYPTO_IV_LENGTH - 1); + memcpy(&crypto_settings->iv[0], &hmac[offset], CRYPTO_IV_LENGTH); + + result = CryptoSeedIVResultFlagSuccess; + if(crypto_settings->crypto_verify_data == NULL) { + const uint8_t* crypto_vkey = get_crypto_verify_key(); + uint8_t crypto_vkey_length = get_crypto_verify_key_length(); + FURI_LOG_I(LOGGING_TAG, "Generating crypto verify data"); + crypto_settings->crypto_verify_data = malloc(crypto_vkey_length); + furi_check(crypto_settings->crypto_verify_data != NULL); + crypto_settings->crypto_verify_data_length = crypto_vkey_length; + + crypto_settings->crypto_verify_data = totp_crypto_encrypt_v2( + crypto_vkey, + crypto_vkey_length, + crypto_settings, + &crypto_settings->crypto_verify_data_length); + + crypto_settings->pin_required = pin != NULL && pin_length > 0; + + result |= CryptoSeedIVResultFlagNewCryptoVerifyData; + } + } else { + result = CryptoSeedIVResultFailed; + } + + return result; +} + +bool totp_crypto_verify_key_v2(const CryptoSettings* crypto_settings) { + size_t decrypted_key_length; + uint8_t* decrypted_key = totp_crypto_decrypt_v2( + crypto_settings->crypto_verify_data, + crypto_settings->crypto_verify_data_length, + crypto_settings, + &decrypted_key_length); + + const uint8_t* crypto_vkey = get_crypto_verify_key(); + uint8_t crypto_vkey_length = get_crypto_verify_key_length(); + bool key_valid = true; + for(uint8_t i = 0; i < crypto_vkey_length && key_valid; i++) { + if(decrypted_key[i] != crypto_vkey[i]) key_valid = false; + } + + free(decrypted_key); + + return key_valid; +} \ No newline at end of file diff --git a/applications/external/totp/services/crypto/crypto_v2.h b/applications/external/totp/services/crypto/crypto_v2.h new file mode 100644 index 000000000..1395e7046 --- /dev/null +++ b/applications/external/totp/services/crypto/crypto_v2.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include +#include "../../types/crypto_settings.h" +#include "common_types.h" + +/** + * @brief Encrypts plain data using built-in certificate and given initialization vector (IV) + * @param plain_data plain data to be encrypted + * @param plain_data_length plain data length + * @param crypto_settings crypto settings + * @param[out] encrypted_data_length encrypted data length + * @return Encrypted data + */ +uint8_t* totp_crypto_encrypt_v2( + const uint8_t* plain_data, + const size_t plain_data_length, + const CryptoSettings* crypto_settings, + size_t* encrypted_data_length); + +/** + * @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV) + * @param encrypted_data encrypted data to be decrypted + * @param encrypted_data_length encrypted data length + * @param crypto_settings crypto settings + * @param[out] decrypted_data_length decrypted data length + * @return Decrypted data + */ +uint8_t* totp_crypto_decrypt_v2( + const uint8_t* encrypted_data, + const size_t encrypted_data_length, + const CryptoSettings* crypto_settings, + size_t* decrypted_data_length); + +/** + * @brief Seed initialization vector (IV) using user's PIN + * @param crypto_settings crypto settings + * @param pin user's PIN + * @param pin_length user's PIN length + * @return Results of seeding IV + */ +CryptoSeedIVResult + totp_crypto_seed_iv_v2(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length); + +/** + * @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption + * @param crypto_settings crypto settings + * @return \c true if cryptographic information is valid; \c false otherwise + */ +bool totp_crypto_verify_key_v2(const CryptoSettings* crypto_settings); \ No newline at end of file diff --git a/applications/external/totp/totp_app.c b/applications/external/totp/totp_app.c index 301100b58..251d7bb5b 100644 --- a/applications/external/totp/totp_app.c +++ b/applications/external/totp/totp_app.c @@ -15,60 +15,53 @@ #include "ui/scene_director.h" #include "ui/constants.h" #include "ui/common_dialogs.h" -#include "services/crypto/crypto.h" +#include "services/crypto/crypto_facade.h" #include "cli/cli.h" +#include "version.h" -static void render_callback(Canvas* const canvas, void* ctx) { +struct TotpRenderCallbackContext { + FuriMutex* mutex; + PluginState* plugin_state; +}; + +static void render_callback(Canvas* const canvas, void* const ctx) { furi_assert(ctx); - PluginState* plugin_state = ctx; - if(furi_mutex_acquire(plugin_state->mutex, 25) == FuriStatusOk) { - totp_scene_director_render(canvas, plugin_state); - furi_mutex_release(plugin_state->mutex); + const struct TotpRenderCallbackContext* context = ctx; + if(furi_mutex_acquire(context->mutex, 25) == FuriStatusOk) { + totp_scene_director_render(canvas, context->plugin_state); + furi_mutex_release(context->mutex); } } -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - +static void input_callback(InputEvent* const input_event, void* const ctx) { + furi_assert(ctx); + FuriMessageQueue* event_queue = ctx; PluginEvent event = {.type = EventTypeKey, .input = *input_event}; furi_message_queue_put(event_queue, &event, FuriWaitForever); } -static bool totp_activate_initial_scene(PluginState* const plugin_state) { - if(plugin_state->crypto_verify_data == NULL) { - DialogMessage* message = dialog_message_alloc(); - 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); - DialogMessageButton dialog_result = - dialog_message_show(plugin_state->dialogs_app, message); - dialog_message_free(message); - if(dialog_result == DialogMessageButtonRight) { - totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication); - } else { - CryptoSeedIVResult seed_result = totp_crypto_seed_iv(plugin_state, NULL, 0); - if(seed_result & CryptoSeedIVResultFlagSuccess && - seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) { - if(!totp_config_file_update_crypto_signatures(plugin_state)) { - totp_dialogs_config_loading_error(plugin_state); - return false; - } - } else if(seed_result == CryptoSeedIVResultFailed) { - totp_dialogs_config_loading_error(plugin_state); - return false; - } +static bool first_run_init(PluginState* const plugin_state) { + DialogMessage* message = dialog_message_alloc(); + 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); + DialogMessageButton dialog_result = dialog_message_show(plugin_state->dialogs_app, message); + dialog_message_free(message); + if(!totp_crypto_check_key_slot(plugin_state->crypto_settings.crypto_key_slot)) { + totp_dialogs_config_loading_error(plugin_state); + return false; + } - totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); - } - } else if(plugin_state->pin_set) { + if(dialog_result == DialogMessageButtonRight) { totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication); } else { - CryptoSeedIVResult seed_result = totp_crypto_seed_iv(plugin_state, NULL, 0); + CryptoSeedIVResult seed_result = + totp_crypto_seed_iv(&plugin_state->crypto_settings, NULL, 0); if(seed_result & CryptoSeedIVResultFlagSuccess && seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) { if(!totp_config_file_update_crypto_signatures(plugin_state)) { @@ -80,23 +73,65 @@ static bool totp_activate_initial_scene(PluginState* const plugin_state) { return false; } - if(totp_crypto_verify_key(plugin_state)) { - totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); - } 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"); - DialogMessage* message = dialog_message_alloc(); - 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_show(plugin_state->dialogs_app, message); - dialog_message_free(message); + totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); + } + + return true; +} + +static bool pinless_activation(PluginState* const plugin_state) { + CryptoSeedIVResult seed_result = totp_crypto_seed_iv(&plugin_state->crypto_settings, NULL, 0); + if(seed_result & CryptoSeedIVResultFlagSuccess && + seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) { + if(!totp_config_file_update_crypto_signatures(plugin_state)) { + totp_dialogs_config_loading_error(plugin_state); + return false; + } + } else if(seed_result == CryptoSeedIVResultFailed) { + totp_dialogs_config_loading_error(plugin_state); + return false; + } + + if(totp_crypto_verify_key(&plugin_state->crypto_settings)) { + totp_config_file_ensure_latest_encryption(plugin_state, NULL, 0); + totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); + } else { + FURI_LOG_E( + LOGGING_TAG, + "Digital signature verification failed. Looks like conf file was created on another device and can't be used on any other"); + DialogMessage* message = dialog_message_alloc(); + 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_show(plugin_state->dialogs_app, message); + dialog_message_free(message); + return false; + } + + return true; +} + +static bool pin_activation(PluginState* const plugin_state) { + totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication); + return true; +} + +static bool totp_activate_initial_scene(PluginState* const plugin_state) { + if(plugin_state->crypto_settings.crypto_verify_data == NULL) { + if(!first_run_init(plugin_state)) { + return false; + } + } else if(plugin_state->crypto_settings.pin_required) { + if(!pin_activation(plugin_state)) { + return false; + } + } else { + if(!pinless_activation(plugin_state)) { return false; } } @@ -109,6 +144,7 @@ static bool on_user_idle(void* context) { if(plugin_state->current_scene != TotpSceneAuthentication && plugin_state->current_scene != TotpSceneStandby) { totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication); + totp_scene_director_force_redraw(plugin_state); return true; } @@ -117,18 +153,17 @@ static bool on_user_idle(void* context) { static bool totp_plugin_state_init(PluginState* const plugin_state) { plugin_state->gui = furi_record_open(RECORD_GUI); - plugin_state->notification_app = furi_record_open(RECORD_NOTIFICATION); plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS); - memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE); + memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH); if(!totp_config_file_load(plugin_state)) { totp_dialogs_config_loading_error(plugin_state); return false; } - plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + plugin_state->event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED if(plugin_state->automation_method & AutomationMethodBadBt) { plugin_state->bt_type_code_worker_context = totp_bt_type_code_worker_init(); } else { @@ -136,7 +171,7 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) { } #endif - if(plugin_state->pin_set) { + if(plugin_state->crypto_settings.pin_required) { plugin_state->idle_timeout_context = idle_timeout_alloc(TOTP_AUTO_LOCK_IDLE_TIMEOUT_SEC, &on_user_idle, plugin_state); idle_timeout_start(plugin_state->idle_timeout_context); @@ -154,28 +189,35 @@ static void totp_plugin_state_free(PluginState* plugin_state) { } furi_record_close(RECORD_GUI); - furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_DIALOGS); totp_config_file_close(plugin_state); - if(plugin_state->crypto_verify_data != NULL) { - free(plugin_state->crypto_verify_data); + if(plugin_state->crypto_settings.crypto_verify_data != NULL) { + free(plugin_state->crypto_settings.crypto_verify_data); } -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED if(plugin_state->bt_type_code_worker_context != NULL) { totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); plugin_state->bt_type_code_worker_context = NULL; } #endif - furi_mutex_free(plugin_state->mutex); + if(plugin_state->event_queue != NULL) { + furi_message_queue_free(plugin_state->event_queue); + } + free(plugin_state); } int32_t totp_app() { - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); + FURI_LOG_I( + LOGGING_TAG, + "App version: %" PRIu8 ".%" PRIu8 ".%" PRIu8, + TOTP_APP_VERSION_MAJOR, + TOTP_APP_VERSION_MINOR, + TOTP_APP_VERSION_PATCH); PluginState* plugin_state = malloc(sizeof(PluginState)); furi_check(plugin_state != NULL); @@ -185,7 +227,7 @@ int32_t totp_app() { return 254; } - TotpCliContext* cli_context = totp_cli_register_command_handler(plugin_state, event_queue); + TotpCliContext* cli_context = totp_cli_register_command_handler(plugin_state); if(!totp_activate_initial_scene(plugin_state)) { FURI_LOG_E(LOGGING_TAG, "An error ocurred during activating initial scene\r\n"); @@ -196,10 +238,14 @@ int32_t totp_app() { // Affecting dolphin level dolphin_deed(DolphinDeedPluginStart); + FuriMutex* main_loop_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + struct TotpRenderCallbackContext render_context = { + .plugin_state = plugin_state, .mutex = main_loop_mutex}; + // Set system callbacks ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, plugin_state); - view_port_input_callback_set(view_port, input_callback, event_queue); + view_port_draw_callback_set(view_port, render_callback, &render_context); + view_port_input_callback_set(view_port, input_callback, plugin_state->event_queue); // Open GUI and register view_port gui_add_view_port(plugin_state->gui, view_port, GuiLayerFullscreen); @@ -207,24 +253,24 @@ int32_t totp_app() { PluginEvent event; bool processing = true; while(processing) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - - if(furi_mutex_acquire(plugin_state->mutex, FuriWaitForever) == FuriStatusOk) { - if(event_status == FuriStatusOk) { + if(furi_message_queue_get(plugin_state->event_queue, &event, FuriWaitForever) == + FuriStatusOk) { + if(event.type == EventForceCloseApp) { + processing = false; + } else if(event.type == EventForceRedraw) { + processing = true; //-V1048 + } else if(furi_mutex_acquire(main_loop_mutex, FuriWaitForever) == FuriStatusOk) { if(event.type == EventTypeKey && plugin_state->idle_timeout_context != NULL) { idle_timeout_report_activity(plugin_state->idle_timeout_context); } - if(event.type == EventForceCloseApp) { - processing = false; - } else { - processing = totp_scene_director_handle_event(&event, plugin_state); - } - } + processing = totp_scene_director_handle_event(&event, plugin_state); - view_port_update(view_port); - furi_mutex_release(plugin_state->mutex); + furi_mutex_release(main_loop_mutex); + } } + + view_port_update(view_port); } totp_cli_unregister_command_handler(cli_context); @@ -233,7 +279,7 @@ int32_t totp_app() { view_port_enabled_set(view_port, false); gui_remove_view_port(plugin_state->gui, view_port); view_port_free(view_port); - furi_message_queue_free(event_queue); + furi_mutex_free(main_loop_mutex); totp_plugin_state_free(plugin_state); return 0; } diff --git a/applications/external/totp/types/automation_kb_layout.h b/applications/external/totp/types/automation_kb_layout.h new file mode 100644 index 000000000..9c23e91ab --- /dev/null +++ b/applications/external/totp/types/automation_kb_layout.h @@ -0,0 +1,8 @@ +#pragma once + +typedef uint8_t AutomationKeyboardLayout; + +enum AutomationKeyboardLayouts { + AutomationKeyboardLayoutQWERTY = 0, + AutomationKeyboardLayoutAZERTY = 1 +}; \ No newline at end of file diff --git a/applications/external/totp/types/automation_method.h b/applications/external/totp/types/automation_method.h index b51e59e03..89e39e18e 100644 --- a/applications/external/totp/types/automation_method.h +++ b/applications/external/totp/types/automation_method.h @@ -7,7 +7,7 @@ typedef uint8_t AutomationMethod; enum AutomationMethods { AutomationMethodNone = 0b00, AutomationMethodBadUsb = 0b01, -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED AutomationMethodBadBt = 0b10, #endif }; diff --git a/applications/external/totp/types/crypto_settings.h b/applications/external/totp/types/crypto_settings.h new file mode 100644 index 000000000..8b970fd6d --- /dev/null +++ b/applications/external/totp/types/crypto_settings.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include "../services/crypto/constants.h" + +typedef struct { + /** + * @brief Crypto key slot to be used + */ + uint8_t crypto_key_slot; + + /** + * @brief Crypto algorithms version to be used + */ + uint8_t crypto_version; + + /** + * @brief Initialization vector (IV) to be used for encryption\decryption + */ + uint8_t iv[CRYPTO_IV_LENGTH]; + + /** + * @brief Basic randomly-generated initialization vector (IV) + */ + uint8_t base_iv[CRYPTO_IV_LENGTH]; + + /** + * @brief Encrypted well-known data + */ + uint8_t* crypto_verify_data; + + /** + * @brief Encrypted well-known data length + */ + size_t crypto_verify_data_length; + + /** + * @brief Whether user's PIN is required or not + */ + bool pin_required; +} CryptoSettings; \ No newline at end of file diff --git a/applications/external/totp/types/event_type.h b/applications/external/totp/types/event_type.h index 7bdf6981f..138f528d8 100644 --- a/applications/external/totp/types/event_type.h +++ b/applications/external/totp/types/event_type.h @@ -3,4 +3,4 @@ typedef uint8_t EventType; -enum EventTypes { EventTypeTick, EventTypeKey, EventForceCloseApp }; +enum EventTypes { EventTypeTick, EventTypeKey, EventForceCloseApp, EventForceRedraw }; diff --git a/applications/external/totp/types/plugin_state.h b/applications/external/totp/types/plugin_state.h index 87ed51abd..a3b2f5c8f 100644 --- a/applications/external/totp/types/plugin_state.h +++ b/applications/external/totp/types/plugin_state.h @@ -9,11 +9,11 @@ #include "../services/idle_timeout/idle_timeout.h" #include "notification_method.h" #include "automation_method.h" -#ifdef TOTP_BADBT_TYPE_ENABLED +#include "automation_kb_layout.h" +#ifdef TOTP_BADBT_AUTOMATION_ENABLED #include "../workers/bt_type_code/bt_type_code.h" #endif - -#define TOTP_IV_SIZE (16) +#include "crypto_settings.h" /** * @brief Application state structure @@ -29,11 +29,6 @@ typedef struct { */ void* current_scene_state; - /** - * @brief Reference to the firmware notification subsystem - */ - NotificationApp* notification_app; - /** * @brief Reference to the firmware dialogs subsystem */ @@ -54,47 +49,22 @@ typedef struct { */ ConfigFileContext* config_file_context; - /** - * @brief Encrypted well-known string data - */ - uint8_t* crypto_verify_data; - - /** - * @brief Encrypted well-known string data length - */ - size_t crypto_verify_data_length; - - /** - * @brief Whether PIN is set by user or not - */ - bool pin_set; - - /** - * @brief Initialization vector (IV) to be used for encryption\decryption - */ - uint8_t iv[TOTP_IV_SIZE]; - - /** - * @brief Basic randomly-generated initialization vector (IV) - */ - uint8_t base_iv[TOTP_IV_SIZE]; - /** * @brief Notification method */ NotificationMethod notification_method; - /** - * @brief Main rendering loop mutex - */ - FuriMutex* mutex; - /** * @brief Automation method */ AutomationMethod automation_method; -#ifdef TOTP_BADBT_TYPE_ENABLED + /** + * @brief Automation keyboard layout to be used + */ + AutomationKeyboardLayout automation_kb_layout; + +#ifdef TOTP_BADBT_AUTOMATION_ENABLED /** * @brief Bad-Bluetooth worker context */ @@ -110,4 +80,14 @@ typedef struct { * @brief Font index to be used to draw TOTP token */ uint8_t active_font_index; + + /** + * @brief Application even queue + */ + FuriMessageQueue* event_queue; + + /** + * @brief Crypto settings + */ + CryptoSettings crypto_settings; } PluginState; diff --git a/applications/external/totp/types/token_info.c b/applications/external/totp/types/token_info.c index ab47f4e3e..1d1e73160 100644 --- a/applications/external/totp/types/token_info.c +++ b/applications/external/totp/types/token_info.c @@ -1,9 +1,10 @@ #include "token_info.h" +#include #include #include #include #include "common.h" -#include "../services/crypto/crypto.h" +#include "../services/crypto/crypto_facade.h" TokenInfo* token_info_alloc() { TokenInfo* tokenInfo = malloc(sizeof(TokenInfo)); @@ -25,7 +26,7 @@ bool token_info_set_secret( const char* plain_token_secret, size_t token_secret_length, PlainTokenSecretEncoding plain_token_secret_encoding, - const uint8_t* iv) { + const CryptoSettings* crypto_settings) { if(token_secret_length == 0) return false; uint8_t* plain_secret; size_t plain_secret_length; @@ -54,8 +55,8 @@ bool token_info_set_secret( free(token_info->token); } - 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, crypto_settings, &token_info->token_length); result = true; } else { result = false; diff --git a/applications/external/totp/types/token_info.h b/applications/external/totp/types/token_info.h index 163a0492e..969445dff 100644 --- a/applications/external/totp/types/token_info.h +++ b/applications/external/totp/types/token_info.h @@ -1,8 +1,9 @@ #pragma once -#include +#include #include #include +#include "crypto_settings.h" #define TOKEN_HASH_ALGO_SHA1_NAME "sha1" #define TOKEN_HASH_ALGO_STEAM_NAME "steam" @@ -200,7 +201,7 @@ void token_info_free(TokenInfo* token_info); * @param plain_token_secret plain token secret * @param token_secret_length plain token secret length * @param plain_token_secret_encoding plain token secret encoding - * @param iv initialization vecor (IV) to be used for encryption + * @param crypto_settings crypto settings * @return \c true if token successfully set; \c false otherwise */ bool token_info_set_secret( @@ -208,7 +209,7 @@ bool token_info_set_secret( const char* plain_token_secret, size_t token_secret_length, PlainTokenSecretEncoding plain_token_secret_encoding, - const uint8_t* iv); + const CryptoSettings* crypto_settings); /** * @brief Sets token digits count from \c uint8_t value diff --git a/applications/external/totp/ui/canvas_extensions.h b/applications/external/totp/ui/canvas_extensions.h index ab5519140..2e053b488 100644 --- a/applications/external/totp/ui/canvas_extensions.h +++ b/applications/external/totp/ui/canvas_extensions.h @@ -4,6 +4,15 @@ #include #include +/** + * @brief Draw string using given font + * @param canvas canvas to draw string at + * @param x horizontal position + * @param y vertical position + * @param text string to draw + * @param text_length string length + * @param font font to be used to draw string + */ void canvas_draw_str_ex( Canvas* canvas, uint8_t x, diff --git a/applications/external/totp/ui/common_dialogs.h b/applications/external/totp/ui/common_dialogs.h index 187d0e95c..1ddd80a75 100644 --- a/applications/external/totp/ui/common_dialogs.h +++ b/applications/external/totp/ui/common_dialogs.h @@ -3,5 +3,16 @@ #include #include "../types/plugin_state.h" +/** + * @brief Shows standard dialog about the fact that error occurred when loading config file + * @param plugin_state application state + * @return dialog button which user pressed to close the dialog + */ DialogMessageButton totp_dialogs_config_loading_error(PluginState* plugin_state); + +/** + * @brief Shows standard dialog about the fact that error occurred when updating config file + * @param plugin_state application state + * @return dialog button which user pressed to close the dialog + */ DialogMessageButton totp_dialogs_config_updating_error(PluginState* plugin_state); \ No newline at end of file diff --git a/applications/external/totp/ui/scene_director.c b/applications/external/totp/ui/scene_director.c index 657762a94..fd7cf1dca 100644 --- a/applications/external/totp/ui/scene_director.c +++ b/applications/external/totp/ui/scene_director.c @@ -116,3 +116,8 @@ bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* con return processing; } + +void totp_scene_director_force_redraw(PluginState* const plugin_state) { + PluginEvent event = {.type = EventForceRedraw}; + furi_message_queue_put(plugin_state->event_queue, &event, FuriWaitForever); +} \ No newline at end of file diff --git a/applications/external/totp/ui/scene_director.h b/applications/external/totp/ui/scene_director.h index e45223997..1f09f9ea9 100644 --- a/applications/external/totp/ui/scene_director.h +++ b/applications/external/totp/ui/scene_director.h @@ -33,3 +33,9 @@ void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_ * @return \c true if event handled and applilcation should continue; \c false if application should be closed */ bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* const plugin_state); + +/** + * @brief Forces screen to be redraw\updated + * @param plugin_state application state + */ +void totp_scene_director_force_redraw(PluginState* const plugin_state); \ No newline at end of file diff --git a/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.c b/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.c index 6856d1e30..6ae288d4c 100644 --- a/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.c +++ b/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.c @@ -42,7 +42,7 @@ typedef struct { struct TotpAddContext { SceneState* scene_state; - uint8_t* iv; + const CryptoSettings* crypto_settings; }; enum TotpIteratorUpdateTokenResultsEx { TotpIteratorUpdateTokenResultInvalidSecret = 1 }; @@ -58,7 +58,7 @@ static TotpIteratorUpdateTokenResult add_token_handler(TokenInfo* tokenInfo, con context_t->scene_state->token_secret, context_t->scene_state->token_secret_length, PlainTokenSecretEncodingBase32, - context_t->iv)) { + context_t->crypto_settings)) { return TotpIteratorUpdateTokenResultInvalidSecret; } @@ -271,7 +271,7 @@ bool totp_scene_add_new_token_handle_event( break; case ConfirmButton: { struct TotpAddContext add_context = { - .iv = plugin_state->iv, .scene_state = scene_state}; + .scene_state = scene_state, .crypto_settings = &plugin_state->crypto_settings}; TokenInfoIteratorContext* iterator_context = totp_config_get_token_iterator_context(plugin_state); TotpIteratorUpdateTokenResult add_result = totp_token_info_iterator_add_new_token( diff --git a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c index 7575d0f2d..33dcd5b43 100644 --- a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c +++ b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c @@ -12,14 +12,30 @@ #include "../../../services/convert/convert.h" #include #include "../../../features_config.h" -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED #include "../../../workers/bt_type_code/bt_type_code.h" #endif +#ifdef TOTP_BADBT_AUTOMATION_ENABLED +#define AUTOMATION_LIST_MAX_INDEX (3) +#else +#define AUTOMATION_LIST_MAX_INDEX (1) +#endif +#define BAD_KB_LAYOUT_LIST_MAX_INDEX (1) +#define FONT_TEST_STR_LENGTH (7) + static const char* YES_NO_LIST[] = {"NO", "YES"}; -static const char* ON_OFF_LIST[] = {"OFF", "ON"}; +static const char* AUTOMATION_LIST[] = { + "None", + "USB" +#ifdef TOTP_BADBT_AUTOMATION_ENABLED + , + "Bluetooth", + "BT and USB" +#endif +}; +static const char* BAD_KB_LAYOUT_LIST[] = {"QWERTY", "AZERTY"}; static const char* FONT_TEST_STR = "0123BCD"; -static const uint8_t FONT_TEST_STR_LENGTH = 7; typedef enum { HoursInput, @@ -27,10 +43,8 @@ typedef enum { FontSelect, SoundSwitch, VibroSwitch, - BadUsbSwitch, -#ifdef TOTP_BADBT_TYPE_ENABLED - BadBtSwitch, -#endif + AutomationSwitch, + BadKeyboardLayoutSelect, ConfirmButton } Control; @@ -39,11 +53,9 @@ typedef struct { uint8_t tz_offset_minutes; bool notification_sound; bool notification_vibro; - bool badusb_enabled; -#ifdef TOTP_BADBT_TYPE_ENABLED - bool badbt_enabled; -#endif - uint8_t y_offset; + AutomationMethod automation_method; + uint16_t y_offset; + AutomationKeyboardLayout automation_kb_layout; Control selected_control; uint8_t active_font; } SceneState; @@ -59,10 +71,11 @@ void totp_scene_app_settings_activate(PluginState* plugin_state) { scene_state->tz_offset_minutes = 60.0f * off_dec; scene_state->notification_sound = plugin_state->notification_method & NotificationMethodSound; scene_state->notification_vibro = plugin_state->notification_method & NotificationMethodVibro; - scene_state->badusb_enabled = plugin_state->automation_method & AutomationMethodBadUsb; -#ifdef TOTP_BADBT_TYPE_ENABLED - scene_state->badbt_enabled = plugin_state->automation_method & AutomationMethodBadBt; -#endif + scene_state->automation_method = + MIN(plugin_state->automation_method, AUTOMATION_LIST_MAX_INDEX); + scene_state->automation_kb_layout = + MIN(plugin_state->automation_kb_layout, BAD_KB_LAYOUT_LIST_MAX_INDEX); + scene_state->active_font = plugin_state->active_font_index; } @@ -82,127 +95,121 @@ static void two_digit_to_str(int8_t num, char* str) { void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state) { const SceneState* scene_state = plugin_state->current_scene_state; + if(scene_state->selected_control < FontSelect) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 0, 0 - scene_state->y_offset, AlignLeft, AlignTop, "Timezone offset"); + canvas_set_font(canvas, FontSecondary); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, 0, 0 - scene_state->y_offset, AlignLeft, AlignTop, "Timezone offset"); - canvas_set_font(canvas, FontSecondary); + char tmp_str[4]; + two_digit_to_str(scene_state->tz_offset_hours, &tmp_str[0]); + canvas_draw_str_aligned( + canvas, 0, 17 - scene_state->y_offset, AlignLeft, AlignTop, "Hours:"); + ui_control_select_render( + canvas, + 36, + 10 - scene_state->y_offset, + SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH, + &tmp_str[0], + scene_state->selected_control == HoursInput); - char tmp_str[4]; - two_digit_to_str(scene_state->tz_offset_hours, &tmp_str[0]); - canvas_draw_str_aligned(canvas, 0, 17 - scene_state->y_offset, AlignLeft, AlignTop, "Hours:"); - ui_control_select_render( - canvas, - 36, - 10 - scene_state->y_offset, - SCREEN_WIDTH - 36, - &tmp_str[0], - scene_state->selected_control == HoursInput); + two_digit_to_str(scene_state->tz_offset_minutes, &tmp_str[0]); + canvas_draw_str_aligned( + canvas, 0, 35 - scene_state->y_offset, AlignLeft, AlignTop, "Minutes:"); + ui_control_select_render( + canvas, + 36, + 28 - scene_state->y_offset, + SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH, + &tmp_str[0], + scene_state->selected_control == MinutesInput); - two_digit_to_str(scene_state->tz_offset_minutes, &tmp_str[0]); - canvas_draw_str_aligned( - canvas, 0, 35 - scene_state->y_offset, AlignLeft, AlignTop, "Minutes:"); - ui_control_select_render( - canvas, - 36, - 28 - scene_state->y_offset, - SCREEN_WIDTH - 36, - &tmp_str[0], - scene_state->selected_control == MinutesInput); + } else if(scene_state->selected_control < SoundSwitch) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 0, 64 - scene_state->y_offset, AlignLeft, AlignTop, "Font"); + canvas_set_font(canvas, FontSecondary); - canvas_draw_icon( - canvas, - SCREEN_WIDTH_CENTER - 5, - SCREEN_HEIGHT - 5 - scene_state->y_offset, - &I_totp_arrow_bottom_10x5); + const FONT_INFO* const font = available_fonts[scene_state->active_font]; + ui_control_select_render( + canvas, + 0, + 74 - scene_state->y_offset, + SCREEN_WIDTH - UI_CONTROL_VSCROLL_WIDTH, + font->name, + scene_state->selected_control == FontSelect); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 0, 64 - scene_state->y_offset, AlignLeft, AlignTop, "Font"); - canvas_set_font(canvas, FontSecondary); + uint8_t font_x_offset = + SCREEN_WIDTH_CENTER - + (((font->charInfo[0].width + font->spacePixels) * FONT_TEST_STR_LENGTH) >> 1); + uint8_t font_y_offset = 108 - scene_state->y_offset - (font->height >> 1); + canvas_draw_str_ex( + canvas, font_x_offset, font_y_offset, FONT_TEST_STR, FONT_TEST_STR_LENGTH, font); - const FONT_INFO* const font = available_fonts[scene_state->active_font]; - ui_control_select_render( - canvas, - 0, - 74 - scene_state->y_offset, - SCREEN_WIDTH, - font->name, - scene_state->selected_control == FontSelect); + } else if(scene_state->selected_control < AutomationSwitch) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 0, 128 - scene_state->y_offset, AlignLeft, AlignTop, "Notifications"); + canvas_set_font(canvas, FontSecondary); - uint8_t font_x_offset = - SCREEN_WIDTH_CENTER - - (((font->charInfo[0].width + font->spacePixels) * FONT_TEST_STR_LENGTH) >> 1); - uint8_t font_y_offset = 108 - scene_state->y_offset - (font->height >> 1); - canvas_draw_str_ex( - canvas, font_x_offset, font_y_offset, FONT_TEST_STR, FONT_TEST_STR_LENGTH, font); + canvas_draw_str_aligned( + canvas, 0, 145 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:"); + ui_control_select_render( + canvas, + 36, + 138 - scene_state->y_offset, + SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH, + YES_NO_LIST[scene_state->notification_sound], + scene_state->selected_control == SoundSwitch); - canvas_draw_icon( - canvas, SCREEN_WIDTH_CENTER - 5, 123 - scene_state->y_offset, &I_totp_arrow_bottom_10x5); + canvas_draw_str_aligned( + canvas, 0, 163 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:"); + ui_control_select_render( + canvas, + 36, + 156 - scene_state->y_offset, + SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH, + YES_NO_LIST[scene_state->notification_vibro], + scene_state->selected_control == VibroSwitch); + } else { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 0, 192 - scene_state->y_offset, AlignLeft, AlignTop, "Automation"); + canvas_set_font(canvas, FontSecondary); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, 0, 128 - scene_state->y_offset, AlignLeft, AlignTop, "Notifications"); - canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, 0, 209 - scene_state->y_offset, AlignLeft, AlignTop, "Method:"); + ui_control_select_render( + canvas, + 36, + 202 - scene_state->y_offset, + SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH, + AUTOMATION_LIST[scene_state->automation_method], + scene_state->selected_control == AutomationSwitch); - canvas_draw_str_aligned(canvas, 0, 145 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:"); - ui_control_select_render( - canvas, - 36, - 138 - scene_state->y_offset, - SCREEN_WIDTH - 36, - YES_NO_LIST[scene_state->notification_sound], - scene_state->selected_control == SoundSwitch); + canvas_draw_str_aligned( + canvas, 0, 227 - scene_state->y_offset, AlignLeft, AlignTop, "Layout:"); - canvas_draw_str_aligned(canvas, 0, 163 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:"); - ui_control_select_render( - canvas, - 36, - 156 - scene_state->y_offset, - SCREEN_WIDTH - 36, - YES_NO_LIST[scene_state->notification_vibro], - scene_state->selected_control == VibroSwitch); + ui_control_select_render( + canvas, + 36, + 220 - scene_state->y_offset, + SCREEN_WIDTH - 36 - UI_CONTROL_VSCROLL_WIDTH, + BAD_KB_LAYOUT_LIST[scene_state->automation_kb_layout], + scene_state->selected_control == BadKeyboardLayoutSelect); - canvas_draw_icon( - canvas, SCREEN_WIDTH_CENTER - 5, 187 - scene_state->y_offset, &I_totp_arrow_bottom_10x5); + ui_control_button_render( + canvas, + SCREEN_WIDTH_CENTER - 24, + 242 - scene_state->y_offset, + 48, + 13, + "Confirm", + scene_state->selected_control == ConfirmButton); + } - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, 0, 192 - scene_state->y_offset, AlignLeft, AlignTop, "Automation"); - canvas_set_font(canvas, FontSecondary); - - canvas_draw_str_aligned( - canvas, 0, 209 - scene_state->y_offset, AlignLeft, AlignTop, "BadUSB:"); - ui_control_select_render( - canvas, - 36, - 202 - scene_state->y_offset, - SCREEN_WIDTH - 36, - ON_OFF_LIST[scene_state->badusb_enabled], - scene_state->selected_control == BadUsbSwitch); - -#ifdef TOTP_BADBT_TYPE_ENABLED - canvas_draw_str_aligned(canvas, 0, 227 - scene_state->y_offset, AlignLeft, AlignTop, "BadBT:"); - ui_control_select_render( - canvas, - 36, - 220 - scene_state->y_offset, - SCREEN_WIDTH - 36, - ON_OFF_LIST[scene_state->badbt_enabled], - scene_state->selected_control == BadBtSwitch); -#endif - - ui_control_button_render( - canvas, - SCREEN_WIDTH_CENTER - 24, -#ifdef TOTP_BADBT_TYPE_ENABLED - 242 - scene_state->y_offset, -#else - 229 - scene_state->y_offset, -#endif - 48, - 13, - "Confirm", - scene_state->selected_control == ConfirmButton); + ui_control_vscroll_render( + canvas, SCREEN_WIDTH - 3, 0, SCREEN_HEIGHT, scene_state->selected_control, ConfirmButton); } bool totp_scene_app_settings_handle_event( @@ -267,14 +274,21 @@ bool totp_scene_app_settings_handle_event( scene_state->notification_sound = !scene_state->notification_sound; } else if(scene_state->selected_control == VibroSwitch) { scene_state->notification_vibro = !scene_state->notification_vibro; - } else if(scene_state->selected_control == BadUsbSwitch) { - scene_state->badusb_enabled = !scene_state->badusb_enabled; + } else if(scene_state->selected_control == AutomationSwitch) { + totp_roll_value_uint8_t( + &scene_state->automation_method, + 1, + 0, + AUTOMATION_LIST_MAX_INDEX, + RollOverflowBehaviorRoll); + } else if(scene_state->selected_control == BadKeyboardLayoutSelect) { + totp_roll_value_uint8_t( + &scene_state->automation_kb_layout, + 1, + 0, + BAD_KB_LAYOUT_LIST_MAX_INDEX, + RollOverflowBehaviorRoll); } -#ifdef TOTP_BADBT_TYPE_ENABLED - else if(scene_state->selected_control == BadBtSwitch) { - scene_state->badbt_enabled = !scene_state->badbt_enabled; - } -#endif break; case InputKeyLeft: if(scene_state->selected_control == HoursInput) { @@ -294,14 +308,21 @@ bool totp_scene_app_settings_handle_event( scene_state->notification_sound = !scene_state->notification_sound; } else if(scene_state->selected_control == VibroSwitch) { scene_state->notification_vibro = !scene_state->notification_vibro; - } else if(scene_state->selected_control == BadUsbSwitch) { - scene_state->badusb_enabled = !scene_state->badusb_enabled; + } else if(scene_state->selected_control == AutomationSwitch) { + totp_roll_value_uint8_t( + &scene_state->automation_method, + -1, + 0, + AUTOMATION_LIST_MAX_INDEX, + RollOverflowBehaviorRoll); + } else if(scene_state->selected_control == BadKeyboardLayoutSelect) { + totp_roll_value_uint8_t( + &scene_state->automation_kb_layout, + -1, + 0, + BAD_KB_LAYOUT_LIST_MAX_INDEX, + RollOverflowBehaviorRoll); } -#ifdef TOTP_BADBT_TYPE_ENABLED - else if(scene_state->selected_control == BadBtSwitch) { - scene_state->badbt_enabled = !scene_state->badbt_enabled; - } -#endif break; case InputKeyOk: break; @@ -322,22 +343,18 @@ bool totp_scene_app_settings_handle_event( (scene_state->notification_sound ? NotificationMethodSound : NotificationMethodNone) | (scene_state->notification_vibro ? NotificationMethodVibro : NotificationMethodNone); - plugin_state->automation_method = scene_state->badusb_enabled ? AutomationMethodBadUsb : - AutomationMethodNone; -#ifdef TOTP_BADBT_TYPE_ENABLED - plugin_state->automation_method |= scene_state->badbt_enabled ? AutomationMethodBadBt : - AutomationMethodNone; -#endif - + plugin_state->automation_method = scene_state->automation_method; plugin_state->active_font_index = scene_state->active_font; + plugin_state->automation_kb_layout = scene_state->automation_kb_layout; if(!totp_config_file_update_user_settings(plugin_state)) { totp_dialogs_config_updating_error(plugin_state); return false; } -#ifdef TOTP_BADBT_TYPE_ENABLED - if(!scene_state->badbt_enabled && plugin_state->bt_type_code_worker_context != NULL) { +#ifdef TOTP_BADBT_AUTOMATION_ENABLED + if((scene_state->automation_method & AutomationMethodBadBt) == 0 && + plugin_state->bt_type_code_worker_context != NULL) { totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); plugin_state->bt_type_code_worker_context = NULL; } diff --git a/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c b/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c index 218e5e397..ea407395a 100644 --- a/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c +++ b/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c @@ -6,10 +6,10 @@ #include "../../../services/config/config.h" #include "../../scene_director.h" #include "../../totp_scenes_enum.h" -#include "../../../services/crypto/crypto.h" +#include "../../../services/crypto/crypto_facade.h" #include "../../../types/user_pin_codes.h" -#define MAX_CODE_LENGTH TOTP_IV_SIZE +#define MAX_CODE_LENGTH CRYPTO_IV_LENGTH static const uint8_t PIN_ASTERISK_RADIUS = 3; static const uint8_t PIN_ASTERISK_STEP = (PIN_ASTERISK_RADIUS << 1) + 2; @@ -24,7 +24,7 @@ void totp_scene_authenticate_activate(PluginState* plugin_state) { scene_state->code_length = 0; memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH); plugin_state->current_scene_state = scene_state; - memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE); + memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH); } void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) { @@ -35,7 +35,7 @@ void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_st v_shift = -10; } - if(plugin_state->crypto_verify_data == NULL) { + if(plugin_state->crypto_settings.crypto_verify_data == NULL) { canvas_draw_str_aligned( canvas, SCREEN_WIDTH_CENTER, @@ -123,20 +123,22 @@ bool totp_scene_authenticate_handle_event( } } else if(event->input.type == InputTypeRelease && event->input.key == InputKeyOk) { CryptoSeedIVResult seed_result = totp_crypto_seed_iv( - plugin_state, &scene_state->code_input[0], scene_state->code_length); + &plugin_state->crypto_settings, &scene_state->code_input[0], scene_state->code_length); if(seed_result & CryptoSeedIVResultFlagSuccess && seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) { totp_config_file_update_crypto_signatures(plugin_state); } - if(totp_crypto_verify_key(plugin_state)) { + if(totp_crypto_verify_key(&plugin_state->crypto_settings)) { FURI_LOG_D(LOGGING_TAG, "PIN is valid"); + totp_config_file_ensure_latest_encryption( + plugin_state, &scene_state->code_input[0], scene_state->code_length); totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); } else { FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid"); memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH); - memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE); + memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH); scene_state->code_length = 0; DialogMessage* message = dialog_message_alloc(); diff --git a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c index 0a0c8373a..de1c0685f 100644 --- a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -15,7 +15,7 @@ #include "../../../features_config.h" #include "../../../workers/generate_totp_code/generate_totp_code.h" #include "../../../workers/usb_type_code/usb_type_code.h" -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED #include "../../../workers/bt_type_code/bt_type_code.h" #endif @@ -33,50 +33,40 @@ typedef struct { typedef struct { char last_code[TokenDigitsCountMax + 1]; TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context; - NotificationMessage const** notification_sequence_new_token; - NotificationMessage const** notification_sequence_automation; + NotificationMessage const* notification_sequence_new_token[8]; + NotificationMessage const* notification_sequence_automation[11]; FuriMutex* last_code_update_sync; TotpGenerateCodeWorkerContext* generate_code_worker_context; UiPrecalculatedDimensions ui_precalculated_dimensions; const FONT_INFO* active_font; + NotificationApp* notification_app; } SceneState; static const NotificationSequence* get_notification_sequence_new_token(const PluginState* plugin_state, SceneState* scene_state) { - if(scene_state->notification_sequence_new_token == NULL) { - uint8_t i = 0; - uint8_t length = 4; + if(scene_state->notification_sequence_new_token[0] == NULL) { + NotificationMessage const** sequence = &scene_state->notification_sequence_new_token[0]; + *(sequence++) = &message_display_backlight_on; + *(sequence++) = &message_green_255; if(plugin_state->notification_method & NotificationMethodVibro) { - length += 2; + *(sequence++) = &message_vibro_on; } if(plugin_state->notification_method & NotificationMethodSound) { - length += 2; + *(sequence++) = &message_note_c5; } - scene_state->notification_sequence_new_token = malloc(sizeof(void*) * length); - furi_check(scene_state->notification_sequence_new_token != NULL); - scene_state->notification_sequence_new_token[i++] = &message_display_backlight_on; - scene_state->notification_sequence_new_token[i++] = &message_green_255; + *(sequence++) = &message_delay_50; + if(plugin_state->notification_method & NotificationMethodVibro) { - scene_state->notification_sequence_new_token[i++] = &message_vibro_on; + *(sequence++) = &message_vibro_off; } if(plugin_state->notification_method & NotificationMethodSound) { - scene_state->notification_sequence_new_token[i++] = &message_note_c5; + *(sequence++) = &message_sound_off; } - scene_state->notification_sequence_new_token[i++] = &message_delay_50; - - if(plugin_state->notification_method & NotificationMethodVibro) { - scene_state->notification_sequence_new_token[i++] = &message_vibro_off; - } - - if(plugin_state->notification_method & NotificationMethodSound) { - scene_state->notification_sequence_new_token[i++] = &message_sound_off; - } - - scene_state->notification_sequence_new_token[i++] = NULL; + *(sequence++) = NULL; } return (NotificationSequence*)scene_state->notification_sequence_new_token; @@ -84,44 +74,33 @@ static const NotificationSequence* static const NotificationSequence* get_notification_sequence_automation(const PluginState* plugin_state, SceneState* scene_state) { - if(scene_state->notification_sequence_automation == NULL) { - uint8_t i = 0; - uint8_t length = 3; + if(scene_state->notification_sequence_automation[0] == NULL) { + NotificationMessage const** sequence = &scene_state->notification_sequence_automation[0]; + + *(sequence++) = &message_blue_255; if(plugin_state->notification_method & NotificationMethodVibro) { - length += 2; + *(sequence++) = &message_vibro_on; } if(plugin_state->notification_method & NotificationMethodSound) { - length += 6; + *(sequence++) = &message_note_d5; //-V525 + *(sequence++) = &message_delay_50; + *(sequence++) = &message_note_e4; + *(sequence++) = &message_delay_50; + *(sequence++) = &message_note_f3; } - scene_state->notification_sequence_automation = malloc(sizeof(void*) * length); - furi_check(scene_state->notification_sequence_automation != NULL); + *(sequence++) = &message_delay_50; - scene_state->notification_sequence_automation[i++] = &message_blue_255; if(plugin_state->notification_method & NotificationMethodVibro) { - scene_state->notification_sequence_automation[i++] = &message_vibro_on; + *(sequence++) = &message_vibro_off; } if(plugin_state->notification_method & NotificationMethodSound) { - scene_state->notification_sequence_automation[i++] = &message_note_d5; //-V525 - scene_state->notification_sequence_automation[i++] = &message_delay_50; - scene_state->notification_sequence_automation[i++] = &message_note_e4; - scene_state->notification_sequence_automation[i++] = &message_delay_50; - scene_state->notification_sequence_automation[i++] = &message_note_f3; + *(sequence++) = &message_sound_off; } - scene_state->notification_sequence_automation[i++] = &message_delay_50; - - if(plugin_state->notification_method & NotificationMethodVibro) { - scene_state->notification_sequence_automation[i++] = &message_vibro_off; - } - - if(plugin_state->notification_method & NotificationMethodSound) { - scene_state->notification_sequence_automation[i++] = &message_sound_off; - } - - scene_state->notification_sequence_automation[i++] = NULL; + *(sequence++) = NULL; } return (NotificationSequence*)scene_state->notification_sequence_automation; @@ -153,7 +132,7 @@ static void draw_totp_code(Canvas* const canvas, const PluginState* const plugin } static void on_new_token_code_generated(bool time_left, void* context) { - const PluginState* plugin_state = context; + PluginState* const plugin_state = context; const TokenInfoIteratorContext* iterator_context = totp_config_get_token_iterator_context(plugin_state); if(totp_token_info_iterator_get_total_count(iterator_context) == 0) { @@ -174,13 +153,16 @@ static void on_new_token_code_generated(bool time_left, void* context) { if(time_left) { notification_message( - plugin_state->notification_app, - get_notification_sequence_new_token(plugin_state, plugin_state->current_scene_state)); + scene_state->notification_app, + get_notification_sequence_new_token(plugin_state, scene_state)); } + + totp_scene_director_force_redraw(plugin_state); } static void on_code_lifetime_updated_generated(float code_lifetime_percent, void* context) { - SceneState* scene_state = context; + PluginState* const plugin_state = context; + SceneState* scene_state = plugin_state->current_scene_state; scene_state->ui_precalculated_dimensions.progress_bar_width = (uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * code_lifetime_percent); scene_state->ui_precalculated_dimensions.progress_bar_x = @@ -188,6 +170,7 @@ static void on_code_lifetime_updated_generated(float code_lifetime_percent, void scene_state->ui_precalculated_dimensions.progress_bar_width) >> 1) + PROGRESS_BAR_MARGIN; + totp_scene_director_force_redraw(plugin_state); } void totp_scene_generate_token_activate(PluginState* plugin_state) { @@ -200,12 +183,18 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) { scene_state->last_code_update_sync = furi_mutex_alloc(FuriMutexTypeNormal); if(plugin_state->automation_method & AutomationMethodBadUsb) { scene_state->usb_type_code_worker_context = totp_usb_type_code_worker_start( - scene_state->last_code, TokenDigitsCountMax + 1, scene_state->last_code_update_sync); + scene_state->last_code, + TokenDigitsCountMax + 1, + scene_state->last_code_update_sync, + plugin_state->automation_kb_layout); } scene_state->active_font = available_fonts[plugin_state->active_font_index]; + scene_state->notification_app = furi_record_open(RECORD_NOTIFICATION); + scene_state->notification_sequence_automation[0] = NULL; + scene_state->notification_sequence_new_token[0] = NULL; -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED if(plugin_state->automation_method & AutomationMethodBadBt) { if(plugin_state->bt_type_code_worker_context == NULL) { @@ -215,7 +204,8 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) { plugin_state->bt_type_code_worker_context, scene_state->last_code, TokenDigitsCountMax + 1, - scene_state->last_code_update_sync); + scene_state->last_code_update_sync, + plugin_state->automation_kb_layout); } #endif const TokenInfoIteratorContext* iterator_context = @@ -225,7 +215,7 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) { totp_token_info_iterator_get_current_token(iterator_context), scene_state->last_code_update_sync, plugin_state->timezone_offset, - plugin_state->iv); + &plugin_state->crypto_settings); totp_generate_code_worker_set_code_generated_handler( scene_state->generate_code_worker_context, &on_new_token_code_generated, plugin_state); @@ -233,7 +223,7 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) { totp_generate_code_worker_set_lifetime_changed_handler( scene_state->generate_code_worker_context, &on_code_lifetime_updated_generated, - scene_state); + plugin_state); update_totp_params( plugin_state, totp_token_info_iterator_get_current_token_index(iterator_context)); @@ -297,11 +287,10 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ canvas, SCREEN_WIDTH - 8, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_right_8x9); } -#ifdef TOTP_AUTOMATION_ICONS_ENABLED if(plugin_state->automation_method & AutomationMethodBadUsb) { canvas_draw_icon( canvas, -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED SCREEN_WIDTH_CENTER - (plugin_state->automation_method & AutomationMethodBadBt ? 33 : 15), #else @@ -312,7 +301,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ &I_hid_usb_31x9); } -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED if(plugin_state->automation_method & AutomationMethodBadBt && plugin_state->bt_type_code_worker_context != NULL && totp_bt_type_code_worker_is_advertising(plugin_state->bt_type_code_worker_context)) { @@ -324,7 +313,6 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ &I_hid_ble_31x9); } #endif -#endif } bool totp_scene_generate_token_handle_event( @@ -350,11 +338,11 @@ bool totp_scene_generate_token_handle_event( TotpUsbTypeCodeWorkerEventType, totp_token_info_iterator_get_current_token(iterator_context)->automation_features); notification_message( - plugin_state->notification_app, + scene_state->notification_app, get_notification_sequence_automation(plugin_state, scene_state)); return true; } -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED else if( event->input.key == InputKeyUp && plugin_state->automation_method & AutomationMethodBadBt) { @@ -366,7 +354,7 @@ bool totp_scene_generate_token_handle_event( TotpBtTypeCodeWorkerEventType, totp_token_info_iterator_get_current_token(iterator_context)->automation_features); notification_message( - plugin_state->notification_app, + scene_state->notification_app, get_notification_sequence_automation(plugin_state, scene_state)); return true; } @@ -427,23 +415,17 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) { totp_generate_code_worker_stop(scene_state->generate_code_worker_context); + furi_record_close(RECORD_NOTIFICATION); + if(plugin_state->automation_method & AutomationMethodBadUsb) { totp_usb_type_code_worker_stop(scene_state->usb_type_code_worker_context); } -#ifdef TOTP_BADBT_TYPE_ENABLED +#ifdef TOTP_BADBT_AUTOMATION_ENABLED if(plugin_state->automation_method & AutomationMethodBadBt) { totp_bt_type_code_worker_stop(plugin_state->bt_type_code_worker_context); } #endif - if(scene_state->notification_sequence_new_token != NULL) { - free(scene_state->notification_sequence_new_token); - } - - if(scene_state->notification_sequence_automation != NULL) { - free(scene_state->notification_sequence_automation); - } - furi_mutex_free(scene_state->last_code_update_sync); free(scene_state); diff --git a/applications/external/totp/ui/ui_controls.c b/applications/external/totp/ui/ui_controls.c index d5e86aa58..28a7d57da 100644 --- a/applications/external/totp/ui/ui_controls.c +++ b/applications/external/totp/ui/ui_controls.c @@ -112,3 +112,27 @@ void ui_control_button_render( canvas_set_color(canvas, ColorBlack); } } + +void ui_control_vscroll_render( + Canvas* const canvas, + uint8_t x, + uint8_t y, + uint8_t height, + uint8_t position, + uint8_t max_position) { + canvas_draw_line(canvas, x, y, x, y + height); + uint8_t block_height = height / MIN(10, max_position); + uint8_t block_position_y = + height * ((float)position / (float)max_position) - (block_height >> 1); + uint8_t block_position_y_abs = y + block_position_y; + if(block_position_y_abs + block_height > height) { + block_position_y_abs = height - block_height; + } + + canvas_draw_box( + canvas, + x - (UI_CONTROL_VSCROLL_WIDTH >> 1), + block_position_y_abs, + UI_CONTROL_VSCROLL_WIDTH, + block_height); +} diff --git a/applications/external/totp/ui/ui_controls.h b/applications/external/totp/ui/ui_controls.h index b97006a03..ccee4edfc 100644 --- a/applications/external/totp/ui/ui_controls.h +++ b/applications/external/totp/ui/ui_controls.h @@ -3,6 +3,8 @@ #include #include +#define UI_CONTROL_VSCROLL_WIDTH (3) + /** * @brief Renders TextBox control * @param canvas canvas to render control at @@ -51,3 +53,20 @@ void ui_control_select_render( uint8_t width, const char* text, bool is_selected); + +/** + * @brief Renders vertical scroll bar + * @param canvas canvas to render control at + * @param x horizontal position of a control to be rendered at + * @param y vertical position of a control to be rendered at + * @param height control height + * @param position current position + * @param max_position maximal position + */ +void ui_control_vscroll_render( + Canvas* const canvas, + uint8_t x, + uint8_t y, + uint8_t height, + uint8_t position, + uint8_t max_position); diff --git a/applications/external/totp/version.h b/applications/external/totp/version.h new file mode 100644 index 000000000..e6925b600 --- /dev/null +++ b/applications/external/totp/version.h @@ -0,0 +1,5 @@ +#pragma once + +#define TOTP_APP_VERSION_MAJOR (3) +#define TOTP_APP_VERSION_MINOR (2) +#define TOTP_APP_VERSION_PATCH (0) \ No newline at end of file diff --git a/applications/external/totp/workers/bt_type_code/bt_type_code.c b/applications/external/totp/workers/bt_type_code/bt_type_code.c index a27467ed6..16dfcc0e8 100644 --- a/applications/external/totp/workers/bt_type_code/bt_type_code.c +++ b/applications/external/totp/workers/bt_type_code/bt_type_code.c @@ -12,13 +12,14 @@ #include "../../types/token_info.h" #include "../type_code_common.h" #include "../../features_config.h" +#include "../../services/config/constants.h" #if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME_UL #define TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN FURI_HAL_BT_ADV_NAME_LENGTH #define TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN GAP_MAC_ADDR_SIZE #endif -#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys") +#define HID_BT_KEYS_STORAGE_PATH CONFIG_FILE_DIRECTORY_PATH "/.bt_hid.keys" struct TotpBtTypeCodeWorkerContext { char* code_buffer; @@ -33,6 +34,7 @@ struct TotpBtTypeCodeWorkerContext { char previous_bt_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN]; uint8_t previous_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN]; #endif + AutomationKeyboardLayout keyboard_layout; }; static inline bool totp_type_code_worker_stop_requested() { @@ -73,7 +75,8 @@ static void totp_type_code_worker_type_code(TotpBtTypeCodeWorkerContext* context &furi_hal_bt_hid_kb_release, context->code_buffer, context->code_buffer_size, - context->flags); + context->flags, + context->keyboard_layout); furi_mutex_release(context->code_buffer_sync); } } @@ -119,11 +122,13 @@ void totp_bt_type_code_worker_start( TotpBtTypeCodeWorkerContext* context, char* code_buffer, uint8_t code_buffer_size, - FuriMutex* code_buffer_sync) { + FuriMutex* code_buffer_sync, + AutomationKeyboardLayout keyboard_layout) { furi_check(context != NULL); context->code_buffer = code_buffer; context->code_buffer_size = code_buffer_size; context->code_buffer_sync = code_buffer_sync; + context->keyboard_layout = keyboard_layout; context->thread = furi_thread_alloc(); furi_thread_set_name(context->thread, "TOTPBtHidWorker"); furi_thread_set_stack_size(context->thread, 1024); diff --git a/applications/external/totp/workers/bt_type_code/bt_type_code.h b/applications/external/totp/workers/bt_type_code/bt_type_code.h index 85016592e..1b9db9bee 100644 --- a/applications/external/totp/workers/bt_type_code/bt_type_code.h +++ b/applications/external/totp/workers/bt_type_code/bt_type_code.h @@ -3,6 +3,7 @@ #include #include #include +#include "../../types/automation_kb_layout.h" typedef uint8_t TotpBtTypeCodeWorkerEvent; @@ -47,12 +48,14 @@ void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context); * @param code_buffer code buffer to be used to automate * @param code_buffer_size code buffer size * @param code_buffer_sync code buffer synchronization primitive + * @param keyboard_layout keyboard layout to be used */ void totp_bt_type_code_worker_start( TotpBtTypeCodeWorkerContext* context, char* code_buffer, uint8_t code_buffer_size, - FuriMutex* code_buffer_sync); + FuriMutex* code_buffer_sync, + AutomationKeyboardLayout keyboard_layout); /** * @brief Stops bluetooth token input automation worker diff --git a/applications/external/totp/workers/generate_totp_code/generate_totp_code.c b/applications/external/totp/workers/generate_totp_code/generate_totp_code.c index 74482517f..20a7bb54c 100644 --- a/applications/external/totp/workers/generate_totp_code/generate_totp_code.c +++ b/applications/external/totp/workers/generate_totp_code/generate_totp_code.c @@ -1,6 +1,7 @@ #include "generate_totp_code.h" #include -#include "../../services/crypto/crypto.h" +#include +#include "../../services/crypto/crypto_facade.h" #include "../../services/totp/totp.h" #include "../../services/convert/convert.h" #include @@ -14,7 +15,7 @@ struct TotpGenerateCodeWorkerContext { FuriMutex* code_buffer_sync; const TokenInfo* token_info; float timezone_offset; - uint8_t* iv; + const CryptoSettings* crypto_settings; TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler; void* on_new_code_generated_handler_context; TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler; @@ -69,7 +70,7 @@ static void generate_totp_code( if(token_info->token != NULL && token_info->token_length > 0) { size_t key_length; uint8_t* key = totp_crypto_decrypt( - token_info->token, token_info->token_length, context->iv, &key_length); + token_info->token, token_info->token_length, context->crypto_settings, &key_length); int_token_to_str( totp_at( @@ -147,14 +148,14 @@ TotpGenerateCodeWorkerContext* totp_generate_code_worker_start( const TokenInfo* token_info, FuriMutex* code_buffer_sync, float timezone_offset, - uint8_t* iv) { + const CryptoSettings* crypto_settings) { TotpGenerateCodeWorkerContext* context = malloc(sizeof(TotpGenerateCodeWorkerContext)); furi_check(context != NULL); context->code_buffer = code_buffer; context->token_info = token_info; context->code_buffer_sync = code_buffer_sync; context->timezone_offset = timezone_offset; - context->iv = iv; + context->crypto_settings = crypto_settings; context->thread = furi_thread_alloc(); furi_thread_set_name(context->thread, "TOTPGenerateWorker"); furi_thread_set_stack_size(context->thread, 2048); diff --git a/applications/external/totp/workers/generate_totp_code/generate_totp_code.h b/applications/external/totp/workers/generate_totp_code/generate_totp_code.h index f351ffa68..eb234313e 100644 --- a/applications/external/totp/workers/generate_totp_code/generate_totp_code.h +++ b/applications/external/totp/workers/generate_totp_code/generate_totp_code.h @@ -38,7 +38,7 @@ enum TotGenerateCodeWorkerEvents { * @param token_info token info to be used to generate code * @param code_buffer_sync code buffer synchronization primitive * @param timezone_offset timezone offset to be used to generate code - * @param iv initialization vector (IV) to be used to decrypt token secret + * @param crypto_settings crypto settings * @return worker context */ TotpGenerateCodeWorkerContext* totp_generate_code_worker_start( @@ -46,7 +46,7 @@ TotpGenerateCodeWorkerContext* totp_generate_code_worker_start( const TokenInfo* token_info, FuriMutex* code_buffer_sync, float timezone_offset, - uint8_t* iv); + const CryptoSettings* crypto_settings); /** * @brief Stops generate code worker diff --git a/applications/external/totp/workers/type_code_common.c b/applications/external/totp/workers/type_code_common.c index 82a5a028e..122c0b2a5 100644 --- a/applications/external/totp/workers/type_code_common.c +++ b/applications/external/totp/workers/type_code_common.c @@ -3,7 +3,9 @@ #include #include "../../services/convert/convert.h" -static const uint8_t hid_number_keys[] = { +#define HID_KEYS_MAP_LENGTH (36) + +static const uint8_t hid_qwerty_keys_map[HID_KEYS_MAP_LENGTH] = { HID_KEYBOARD_0, HID_KEYBOARD_1, HID_KEYBOARD_2, HID_KEYBOARD_3, HID_KEYBOARD_4, HID_KEYBOARD_5, HID_KEYBOARD_6, HID_KEYBOARD_7, HID_KEYBOARD_8, HID_KEYBOARD_9, HID_KEYBOARD_A, HID_KEYBOARD_B, HID_KEYBOARD_C, HID_KEYBOARD_D, HID_KEYBOARD_E, @@ -13,6 +15,16 @@ static const uint8_t hid_number_keys[] = { HID_KEYBOARD_U, HID_KEYBOARD_V, HID_KEYBOARD_W, HID_KEYBOARD_X, HID_KEYBOARD_Y, HID_KEYBOARD_Z}; +static const uint8_t hid_azerty_keys_map[HID_KEYS_MAP_LENGTH] = { + HID_KEYBOARD_0, HID_KEYBOARD_1, HID_KEYBOARD_2, HID_KEYBOARD_3, HID_KEYBOARD_4, + HID_KEYBOARD_5, HID_KEYBOARD_6, HID_KEYBOARD_7, HID_KEYBOARD_8, HID_KEYBOARD_9, + HID_KEYBOARD_Q, HID_KEYBOARD_B, HID_KEYBOARD_C, HID_KEYBOARD_D, HID_KEYBOARD_E, + HID_KEYBOARD_F, HID_KEYBOARD_G, HID_KEYBOARD_H, HID_KEYBOARD_I, HID_KEYBOARD_J, + HID_KEYBOARD_K, HID_KEYBOARD_L, HID_KEYBOARD_SEMICOLON, HID_KEYBOARD_N, HID_KEYBOARD_O, + HID_KEYBOARD_P, HID_KEYBOARD_A, HID_KEYBOARD_R, HID_KEYBOARD_S, HID_KEYBOARD_T, + HID_KEYBOARD_U, HID_KEYBOARD_V, HID_KEYBOARD_Z, HID_KEYBOARD_X, HID_KEYBOARD_Y, + HID_KEYBOARD_W}; + static uint32_t get_keystroke_delay(TokenAutomationFeature features) { if(features & TokenAutomationFeatureTypeSlower) { return 100; @@ -44,21 +56,38 @@ void totp_type_code_worker_execute_automation( TOTP_AUTOMATION_KEY_HANDLER key_release_fn, const char* code_buffer, uint8_t code_buffer_size, - TokenAutomationFeature features) { + TokenAutomationFeature features, + AutomationKeyboardLayout keyboard_layout) { furi_delay_ms(500); uint8_t i = 0; char cb_char; + const uint8_t* keyboard_layout_dict; + switch(keyboard_layout) { + case AutomationKeyboardLayoutQWERTY: + keyboard_layout_dict = &hid_qwerty_keys_map[0]; + break; + case AutomationKeyboardLayoutAZERTY: + keyboard_layout_dict = &hid_azerty_keys_map[0]; + break; + + default: + return; + } + while(i < code_buffer_size && (cb_char = code_buffer[i]) != 0) { uint8_t char_index = CONVERT_CHAR_TO_DIGIT(cb_char); if(char_index > 9) { char_index = cb_char - 'A' + 10; } - if(char_index >= sizeof(hid_number_keys)) break; + if(char_index >= HID_KEYS_MAP_LENGTH) break; - uint16_t hid_kb_key = hid_number_keys[char_index]; - if(char_index > 9) { + uint16_t hid_kb_key = keyboard_layout_dict[char_index]; + + // For non-AZERTY press shift for all non-digit chars + // For AZERTY press shift for all characters + if(char_index > 9 || keyboard_layout == AutomationKeyboardLayoutAZERTY) { hid_kb_key |= KEY_MOD_LEFT_SHIFT; } diff --git a/applications/external/totp/workers/type_code_common.h b/applications/external/totp/workers/type_code_common.h index db357329a..81b273c36 100644 --- a/applications/external/totp/workers/type_code_common.h +++ b/applications/external/totp/workers/type_code_common.h @@ -1,6 +1,7 @@ #pragma once #include #include "../types/token_info.h" +#include "../types/automation_kb_layout.h" typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key); @@ -11,10 +12,12 @@ typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key); * @param code_buffer code buffer to be typed * @param code_buffer_size code buffer size * @param features automation features + * @param keyboard_layout keyboard layout to be used */ void totp_type_code_worker_execute_automation( TOTP_AUTOMATION_KEY_HANDLER key_press_fn, TOTP_AUTOMATION_KEY_HANDLER key_release_fn, const char* code_buffer, uint8_t code_buffer_size, - TokenAutomationFeature features); \ No newline at end of file + TokenAutomationFeature features, + AutomationKeyboardLayout keyboard_layout); \ No newline at end of file diff --git a/applications/external/totp/workers/usb_type_code/usb_type_code.c b/applications/external/totp/workers/usb_type_code/usb_type_code.c index a391bdf82..4e3259424 100644 --- a/applications/external/totp/workers/usb_type_code/usb_type_code.c +++ b/applications/external/totp/workers/usb_type_code/usb_type_code.c @@ -15,6 +15,7 @@ struct TotpUsbTypeCodeWorkerContext { FuriThread* thread; FuriMutex* code_buffer_sync; FuriHalUsbInterface* usb_mode_prev; + AutomationKeyboardLayout keyboard_layout; }; static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) { @@ -45,7 +46,8 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex &furi_hal_hid_kb_release, context->code_buffer, context->code_buffer_size, - context->flags); + context->flags, + context->keyboard_layout); furi_mutex_release(context->code_buffer_sync); furi_delay_ms(100); @@ -83,7 +85,8 @@ static int32_t totp_type_code_worker_callback(void* context) { TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start( char* code_buffer, uint8_t code_buffer_size, - FuriMutex* code_buffer_sync) { + FuriMutex* code_buffer_sync, + AutomationKeyboardLayout keyboard_layout) { TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext)); furi_check(context != NULL); context->code_buffer = code_buffer; @@ -91,6 +94,7 @@ TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start( context->code_buffer_sync = code_buffer_sync; context->thread = furi_thread_alloc(); context->usb_mode_prev = NULL; + context->keyboard_layout = keyboard_layout; furi_thread_set_name(context->thread, "TOTPUsbHidWorker"); furi_thread_set_stack_size(context->thread, 1024); furi_thread_set_context(context->thread, context); diff --git a/applications/external/totp/workers/usb_type_code/usb_type_code.h b/applications/external/totp/workers/usb_type_code/usb_type_code.h index 0a700e7fe..d2d1bdf82 100644 --- a/applications/external/totp/workers/usb_type_code/usb_type_code.h +++ b/applications/external/totp/workers/usb_type_code/usb_type_code.h @@ -3,6 +3,7 @@ #include #include #include +#include "../../types/automation_kb_layout.h" typedef uint8_t TotpUsbTypeCodeWorkerEvent; @@ -34,12 +35,14 @@ enum TotpUsbTypeCodeWorkerEvents { * @param code_buffer code buffer to be used to automate * @param code_buffer_size code buffer size * @param code_buffer_sync code buffer synchronization primitive + * @param keyboard_layout keyboard layout to be used * @return worker context */ TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start( char* code_buffer, uint8_t code_buffer_size, - FuriMutex* code_buffer_sync); + FuriMutex* code_buffer_sync, + AutomationKeyboardLayout keyboard_layout); /** * @brief Stops USB token input automation worker