Alexander Kopachov 2 лет назад
Родитель
Сommit
3790f1893a

+ 4 - 0
.ofwcatalog/CHANGELOG.md

@@ -1,5 +1,9 @@
 # Changelog
 # Changelog
 
 
+## v3.0.0 - 26 Jul 2023
+
+* Implemented better encryption [#167](https://github.com/akopachov/flipper-zero_authenticator/issues/167)
+
 ## v2.3.0 - 18 Jul 2023
 ## v2.3.0 - 18 Jul 2023
 
 
 * Implemented [#165](https://github.com/akopachov/flipper-zero_authenticator/issues/165)
 * Implemented [#165](https://github.com/akopachov/flipper-zero_authenticator/issues/165)

+ 1 - 1
application.fam

@@ -15,7 +15,7 @@ App(
     ],
     ],
     stack_size=2 * 1024,
     stack_size=2 * 1024,
     order=20,
     order=20,
-    fap_version="2.3",
+    fap_version="3.0",
     fap_author="Alexander Kopachov (@akopachov)",
     fap_author="Alexander Kopachov (@akopachov)",
     fap_description="Software-based TOTP authenticator for Flipper Zero device",
     fap_description="Software-based TOTP authenticator for Flipper Zero device",
     fap_weburl="https://github.com/akopachov/flipper-zero_authenticator",
     fap_weburl="https://github.com/akopachov/flipper-zero_authenticator",

+ 2 - 4
cli/cli.c

@@ -63,7 +63,7 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
     } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_AUTOMATION) == 0) {
     } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_AUTOMATION) == 0) {
         totp_cli_command_automation_handle(plugin_state, args, cli);
         totp_cli_command_automation_handle(plugin_state, args, cli);
     } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_RESET) == 0) {
     } 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) {
     } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_UPDATE) == 0) {
         totp_cli_command_update_handle(plugin_state, args, cli);
         totp_cli_command_update_handle(plugin_state, args, cli);
     } else if(
     } else if(
@@ -77,13 +77,11 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
     furi_string_free(cmd);
     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);
     Cli* cli = furi_record_open(RECORD_CLI);
     TotpCliContext* context = malloc(sizeof(TotpCliContext));
     TotpCliContext* context = malloc(sizeof(TotpCliContext));
     furi_check(context != NULL);
     furi_check(context != NULL);
     context->plugin_state = plugin_state;
     context->plugin_state = plugin_state;
-    context->event_queue = event_queue;
     cli_add_command(
     cli_add_command(
         cli, TOTP_CLI_COMMAND_NAME, CliCommandFlagParallelSafe, totp_cli_handler, context);
         cli, TOTP_CLI_COMMAND_NAME, CliCommandFlagParallelSafe, totp_cli_handler, context);
     furi_record_close(RECORD_CLI);
     furi_record_close(RECORD_CLI);

+ 1 - 3
cli/cli.h

@@ -5,9 +5,7 @@
 
 
 typedef struct {
 typedef struct {
     PluginState* plugin_state;
     PluginState* plugin_state;
-    FuriMessageQueue* event_queue;
 } TotpCliContext;
 } TotpCliContext;
 
 
-TotpCliContext*
-    totp_cli_register_command_handler(PluginState* plugin_state, FuriMessageQueue* event_queue);
+TotpCliContext* totp_cli_register_command_handler(PluginState* plugin_state);
 void totp_cli_unregister_command_handler(TotpCliContext* context);
 void totp_cli_unregister_command_handler(TotpCliContext* context);

+ 11 - 2
cli/commands/add/add.c

@@ -12,6 +12,8 @@ struct TotpAddContext {
     FuriString* args;
     FuriString* args;
     Cli* cli;
     Cli* cli;
     uint8_t* iv;
     uint8_t* iv;
+    uint8_t crypto_version;
+    uint8_t crypto_key_slot;
 };
 };
 
 
 enum TotpIteratorUpdateTokenResultsEx {
 enum TotpIteratorUpdateTokenResultsEx {
@@ -68,7 +70,9 @@ static TotpIteratorUpdateTokenResult
         furi_string_get_cstr(temp_str),
         furi_string_get_cstr(temp_str),
         furi_string_size(temp_str),
         furi_string_size(temp_str),
         token_secret_encoding,
         token_secret_encoding,
-        context_t->iv);
+        context_t->iv,
+        context_t->crypto_version,
+        context_t->crypto_key_slot);
 
 
     furi_string_secure_free(temp_str);
     furi_string_secure_free(temp_str);
 
 
@@ -166,7 +170,12 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl
 
 
     TOTP_CLI_LOCK_UI(plugin_state);
     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,
+        .iv = &plugin_state->iv[0],
+        .crypto_version = plugin_state->crypto_version,
+        .crypto_key_slot = plugin_state->crypto_key_slot};
     TotpIteratorUpdateTokenResult add_result =
     TotpIteratorUpdateTokenResult add_result =
         totp_token_info_iterator_add_new_token(iterator_context, &add_token_handler, &add_context);
         totp_token_info_iterator_add_new_token(iterator_context, &add_token_handler, &add_context);
 
 

+ 1 - 0
cli/commands/help/help.c

@@ -64,4 +64,5 @@ void totp_cli_command_help_handle() {
     totp_cli_command_add_docopt_options();
     totp_cli_command_add_docopt_options();
     totp_cli_command_update_docopt_options();
     totp_cli_command_update_docopt_options();
     totp_cli_command_delete_docopt_options();
     totp_cli_command_delete_docopt_options();
+    totp_cli_command_pin_docopt_options();
 }
 }

+ 47 - 17
cli/commands/pin/pin.c

@@ -7,19 +7,35 @@
 #include "../../../services/config/config.h"
 #include "../../../services/config/config.h"
 #include "../../cli_helpers.h"
 #include "../../cli_helpers.h"
 #include <memset_s.h>
 #include <memset_s.h>
-#include "../../../services/crypto/crypto.h"
+#include "../../../services/crypto/crypto_facade.h"
 #include "../../../ui/scene_director.h"
 #include "../../../ui/scene_director.h"
 
 
 #define TOTP_CLI_COMMAND_PIN_COMMAND_SET "set"
 #define TOTP_CLI_COMMAND_PIN_COMMAND_SET "set"
 #define TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE "remove"
 #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() {
 void totp_cli_command_pin_docopt_commands() {
     TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_PIN "              Set\\change\\remove PIN\r\n");
     TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_PIN "              Set\\change\\remove PIN\r\n");
 }
 }
 
 
 void totp_cli_command_pin_docopt_usage() {
 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) {
 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_change = false;
     bool do_remove = 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_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) {
         if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_SET) == 0) {
             do_change = true;
             do_change = true;
         } else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) == 0) {
         } else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_PIN_COMMAND_REMOVE) == 0) {
             do_remove = true;
             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 {
         } else {
             totp_cli_print_invalid_arguments();
             totp_cli_print_invalid_arguments();
+            arguments_parsed = false;
+            break;
         }
         }
-    } else {
+    }
+
+    if(!(do_change || do_remove) || (do_change && do_remove)) {
         totp_cli_print_invalid_arguments();
         totp_cli_print_invalid_arguments();
+        arguments_parsed = false;
     }
     }
 
 
-    if((do_change || do_remove) && totp_cli_ensure_authenticated(plugin_state, cli)) {
+    if(arguments_parsed && totp_cli_ensure_authenticated(plugin_state, cli)) {
         TOTP_CLI_LOCK_UI(plugin_state);
         TOTP_CLI_LOCK_UI(plugin_state);
         do {
         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;
             uint8_t new_pin_length = 0;
             if(do_change) {
             if(do_change) {
                 if(!totp_cli_read_pin(cli, &new_pin[0], &new_pin_length)) {
                 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;
                     break;
                 }
                 }
             } else if(do_remove) {
             } else if(do_remove) {
                 new_pin_length = 0;
                 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);
             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");
                     "Once you make sure everything is fine and works as expected, please delete this backup file\r\n");
                 free(backup_path);
                 free(backup_path);
             } else {
             } 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(
                 TOTP_CLI_PRINTF_ERROR(
                     "An error has occurred during taking backup of config file\r\n");
                     "An error has occurred during taking backup of config file\r\n");
                 break;
                 break;
@@ -135,10 +165,10 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
 
 
             TOTP_CLI_PRINTF("Encrypting...\r\n");
             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();
             totp_cli_delete_last_line();
 
 

+ 2 - 1
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_handle(PluginState* plugin_state, FuriString* args, Cli* cli);
 void totp_cli_command_pin_docopt_commands();
 void totp_cli_command_pin_docopt_commands();
-void totp_cli_command_pin_docopt_usage();
+void totp_cli_command_pin_docopt_usage();
+void totp_cli_command_pin_docopt_options();

+ 2 - 5
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");
     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_LOCK_UI(plugin_state);
     TOTP_CLI_PRINTF_WARNING(
     TOTP_CLI_PRINTF_WARNING(
         "As a result of reset all the settings and tokens will be permanently lost.\r\n");
         "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_config_file_reset(plugin_state);
         TOTP_CLI_PRINTF_SUCCESS("Application has been successfully reset to default.\r\n");
         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_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 {
     } else {
         TOTP_CLI_PRINTF_INFO("Action was not confirmed by user\r\n");
         TOTP_CLI_PRINTF_INFO("Action was not confirmed by user\r\n");
         TOTP_CLI_UNLOCK_UI(plugin_state);
         TOTP_CLI_UNLOCK_UI(plugin_state);

+ 1 - 4
cli/commands/reset/reset.h

@@ -5,9 +5,6 @@
 
 
 #define TOTP_CLI_COMMAND_RESET "reset"
 #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_commands();
 void totp_cli_command_reset_docopt_usage();
 void totp_cli_command_reset_docopt_usage();

+ 10 - 2
cli/commands/update/update.c

@@ -14,6 +14,8 @@ struct TotpUpdateContext {
     FuriString* args;
     FuriString* args;
     Cli* cli;
     Cli* cli;
     uint8_t* iv;
     uint8_t* iv;
+    uint8_t crypto_version;
+    uint8_t crypto_key_slot;
 };
 };
 
 
 enum TotpIteratorUpdateTokenResultsEx {
 enum TotpIteratorUpdateTokenResultsEx {
@@ -96,7 +98,9 @@ static TotpIteratorUpdateTokenResult
                furi_string_get_cstr(temp_str),
                furi_string_get_cstr(temp_str),
                furi_string_size(temp_str),
                furi_string_size(temp_str),
                token_secret_encoding,
                token_secret_encoding,
-               context_t->iv)) {
+               context_t->iv,
+               context_t->crypto_version,
+               context_t->crypto_key_slot)) {
             furi_string_secure_free(temp_str);
             furi_string_secure_free(temp_str);
             return TotpIteratorUpdateTokenResultInvalidSecret;
             return TotpIteratorUpdateTokenResultInvalidSecret;
         }
         }
@@ -151,7 +155,11 @@ void totp_cli_command_update_handle(PluginState* plugin_state, FuriString* args,
     totp_token_info_iterator_go_to(iterator_context, token_number - 1);
     totp_token_info_iterator_go_to(iterator_context, token_number - 1);
 
 
     struct TotpUpdateContext update_context = {
     struct TotpUpdateContext update_context = {
-        .args = args, .cli = cli, .iv = &plugin_state->iv[0]};
+        .args = args,
+        .cli = cli,
+        .iv = &plugin_state->iv[0],
+        .crypto_version = plugin_state->crypto_version,
+        .crypto_key_slot = plugin_state->crypto_key_slot};
     TotpIteratorUpdateTokenResult update_result = totp_token_info_iterator_update_current_token(
     TotpIteratorUpdateTokenResult update_result = totp_token_info_iterator_update_current_token(
         iterator_context, &update_token_handler, &update_context);
         iterator_context, &update_token_handler, &update_context);
 
 

+ 125 - 18
services/config/config.c

@@ -9,7 +9,8 @@
 #include "../../types/common.h"
 #include "../../types/common.h"
 #include "../../types/token_info.h"
 #include "../../types/token_info.h"
 #include "../../features_config.h"
 #include "../../features_config.h"
-#include "../crypto/crypto.h"
+#include "../crypto/crypto_facade.h"
+#include "../crypto/constants.h"
 #include "migrations/common_migration.h"
 #include "migrations/common_migration.h"
 
 
 #define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
 #define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
@@ -139,6 +140,13 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
         flipper_format_write_header_cstr(
         flipper_format_write_header_cstr(
             fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION);
             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(
         flipper_format_write_comment_cstr(
             fff_data_file,
             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");
             "Config file format specification can be found here: https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md");
@@ -146,7 +154,7 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
         float tmp_tz = 0;
         float tmp_tz = 0;
         flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1);
         flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1);
 
 
-        uint32_t tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
+        tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
         flipper_format_write_uint32(
         flipper_format_write_uint32(
             fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
             fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
 
 
@@ -344,8 +352,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_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_key_slot = tmp_uint32;
+
+        if(!flipper_format_rewind(fff_data_file)) {
+            break;
+        }
+
         if(!flipper_format_read_hex(
         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->base_iv[0],
+               CRYPTO_IV_LENGTH)) {
             FURI_LOG_D(LOGGING_TAG, "Missing base IV");
             FURI_LOG_D(LOGGING_TAG, "Missing base IV");
         }
         }
 
 
@@ -394,9 +432,10 @@ bool totp_config_file_load(PluginState* const plugin_state) {
             plugin_state->pin_set = true;
             plugin_state->pin_set = true;
         }
         }
 
 
-        flipper_format_rewind(fff_data_file);
+        if(!flipper_format_rewind(fff_data_file)) {
+            break;
+        }
 
 
-        uint32_t tmp_uint32;
         if(!flipper_format_read_uint32(
         if(!flipper_format_read_uint32(
                fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
                fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
             tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
             tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
@@ -404,7 +443,9 @@ bool totp_config_file_load(PluginState* const plugin_state) {
 
 
         plugin_state->notification_method = tmp_uint32;
         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(
         if(!flipper_format_read_uint32(
                fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) {
                fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) {
@@ -413,6 +454,10 @@ bool totp_config_file_load(PluginState* const plugin_state) {
 
 
         plugin_state->automation_method = tmp_uint32;
         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_FONT, &tmp_uint32, 1)) {
         if(!flipper_format_read_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1)) {
             tmp_uint32 = 0;
             tmp_uint32 = 0;
         }
         }
@@ -425,7 +470,11 @@ bool totp_config_file_load(PluginState* const plugin_state) {
         plugin_state->config_file_context->config_file = fff_data_file;
         plugin_state->config_file_context->config_file = fff_data_file;
         plugin_state->config_file_context->token_info_iterator_context =
         plugin_state->config_file_context->token_info_iterator_context =
             totp_token_info_iterator_alloc(
             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->iv,
+                plugin_state->crypto_version,
+                plugin_state->crypto_key_slot);
         result = true;
         result = true;
     } while(false);
     } while(false);
 
 
@@ -438,8 +487,20 @@ bool totp_config_file_update_crypto_signatures(const PluginState* plugin_state)
     flipper_format_rewind(config_file);
     flipper_format_rewind(config_file);
     bool update_result = false;
     bool update_result = false;
     do {
     do {
+        uint32_t tmp_uint32 = plugin_state->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_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(
         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->base_iv, CRYPTO_IV_LENGTH)) {
             break;
             break;
         }
         }
 
 
@@ -480,6 +541,7 @@ void totp_config_file_reset(PluginState* const plugin_state) {
 
 
 bool totp_config_file_update_encryption(
 bool totp_config_file_update_encryption(
     PluginState* plugin_state,
     PluginState* plugin_state,
+    uint8_t new_crypto_key_slot,
     const uint8_t* new_pin,
     const uint8_t* new_pin,
     uint8_t new_pin_length) {
     uint8_t new_pin_length) {
     FlipperFormat* config_file = plugin_state->config_file_context->config_file;
     FlipperFormat* config_file = plugin_state->config_file_context->config_file;
@@ -489,23 +551,28 @@ bool totp_config_file_update_encryption(
         return false;
         return false;
     }
     }
 
 
-    uint8_t old_iv[TOTP_IV_SIZE];
-    memcpy(&old_iv[0], &plugin_state->iv[0], TOTP_IV_SIZE);
+    uint8_t old_iv[CRYPTO_IV_LENGTH];
+    memcpy(&old_iv[0], &plugin_state->iv[0], CRYPTO_IV_LENGTH);
+
+    uint8_t old_crypto_key_slot = plugin_state->crypto_key_slot;
+    uint8_t old_crypto_version = plugin_state->crypto_version;
 
 
-    memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
-    memset(&plugin_state->base_iv[0], 0, TOTP_IV_SIZE);
+    memset(&plugin_state->iv[0], 0, CRYPTO_IV_LENGTH);
+    memset(&plugin_state->base_iv[0], 0, CRYPTO_IV_LENGTH);
     if(plugin_state->crypto_verify_data != NULL) {
     if(plugin_state->crypto_verify_data != NULL) {
         free(plugin_state->crypto_verify_data);
         free(plugin_state->crypto_verify_data);
         plugin_state->crypto_verify_data = NULL;
         plugin_state->crypto_verify_data = NULL;
     }
     }
 
 
+    plugin_state->crypto_key_slot = new_crypto_key_slot;
+    plugin_state->crypto_version = CRYPTO_LATEST_VERSION;
+
     CryptoSeedIVResult seed_result =
     CryptoSeedIVResult seed_result =
         totp_crypto_seed_iv(plugin_state, new_pin_length > 0 ? new_pin : NULL, new_pin_length);
         totp_crypto_seed_iv(plugin_state, new_pin_length > 0 ? new_pin : NULL, new_pin_length);
     if(seed_result & CryptoSeedIVResultFlagSuccess &&
     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) {
     } else if(seed_result == CryptoSeedIVResultFailed) {
         return false;
         return false;
     }
     }
@@ -552,12 +619,22 @@ bool totp_config_file_update_encryption(
 
 
                 size_t plain_token_length;
                 size_t plain_token_length;
                 uint8_t* plain_token = totp_crypto_decrypt(
                 uint8_t* plain_token = totp_crypto_decrypt(
-                    encrypted_token, secret_bytes_count, &old_iv[0], &plain_token_length);
+                    encrypted_token,
+                    secret_bytes_count,
+                    &old_iv[0],
+                    old_crypto_version,
+                    old_crypto_key_slot,
+                    &plain_token_length);
 
 
                 free(encrypted_token);
                 free(encrypted_token);
                 size_t encrypted_token_length;
                 size_t encrypted_token_length;
                 encrypted_token = totp_crypto_encrypt(
                 encrypted_token = totp_crypto_encrypt(
-                    plain_token, plain_token_length, &plugin_state->iv[0], &encrypted_token_length);
+                    plain_token,
+                    plain_token_length,
+                    &plugin_state->iv[0],
+                    plugin_state->crypto_version,
+                    plugin_state->crypto_key_slot,
+                    &encrypted_token_length);
 
 
                 memset_s(plain_token, plain_token_length, 0, plain_token_length);
                 memset_s(plain_token, plain_token_length, 0, plain_token_length);
                 free(plain_token);
                 free(plain_token);
@@ -588,6 +665,36 @@ bool totp_config_file_update_encryption(
     return result;
     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_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_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) {
 TokenInfoIteratorContext* totp_config_get_token_iterator_context(const PluginState* plugin_state) {
     return plugin_state->config_file_context->token_info_iterator_context;
     return plugin_state->config_file_context->token_info_iterator_context;
 }
 }

+ 14 - 0
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
  * @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 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 new user's PIN
  * @param new_pin_length new user's PIN length
  * @param new_pin_length new user's PIN length
  * @return \c true if config file encryption successfully updated; \c false otherwise
  * @return \c true if config file encryption successfully updated; \c false otherwise
  */
  */
 bool totp_config_file_update_encryption(
 bool totp_config_file_update_encryption(
     PluginState* plugin_state,
     PluginState* plugin_state,
+    uint8_t new_crypto_key_slot,
     const uint8_t* new_pin,
     const uint8_t* new_pin,
     uint8_t new_pin_length);
     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
  * @brief Gets token info iterator context
  * @param plugin_state application state
  * @param plugin_state application state

+ 3 - 1
services/config/constants.h

@@ -4,7 +4,7 @@
 
 
 #define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator")
 #define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator")
 #define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
 #define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
-#define CONFIG_FILE_ACTUAL_VERSION (6)
+#define CONFIG_FILE_ACTUAL_VERSION (7)
 
 
 #define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
 #define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
 #define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
 #define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
@@ -19,3 +19,5 @@
 #define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod"
 #define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod"
 #define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod"
 #define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod"
 #define TOTP_CONFIG_KEY_FONT "Font"
 #define TOTP_CONFIG_KEY_FONT "Font"
+#define TOTP_CONFIG_KEY_CRYPTO_VERSION "CryptoVersion"
+#define TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT "CryptoKeySlot"

+ 22 - 0
services/config/migrations/common_migration.c

@@ -17,6 +17,28 @@ bool totp_config_migrate_to_latest(
             break;
             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)) {
         if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) {
             flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
             flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
         }
         }

+ 13 - 3
services/config/token_info_iterator.c

@@ -16,6 +16,8 @@ struct TokenInfoIteratorContext {
     TokenInfo* current_token;
     TokenInfo* current_token;
     FlipperFormat* config_file;
     FlipperFormat* config_file;
     uint8_t* iv;
     uint8_t* iv;
+    uint8_t crypto_version;
+    uint8_t crypto_key_slot;
     Storage* storage;
     Storage* storage;
 };
 };
 
 
@@ -237,8 +239,12 @@ static bool
     return result;
     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,
+    uint8_t* iv,
+    uint8_t crypto_version,
+    uint8_t crypto_key_slot) {
     Stream* stream = flipper_format_get_raw_stream(config_file);
     Stream* stream = flipper_format_get_raw_stream(config_file);
     stream_rewind(stream);
     stream_rewind(stream);
     size_t tokens_count = 0;
     size_t tokens_count = 0;
@@ -257,6 +263,8 @@ TokenInfoIteratorContext*
     context->current_token = token_info_alloc();
     context->current_token = token_info_alloc();
     context->config_file = config_file;
     context->config_file = config_file;
     context->iv = iv;
     context->iv = iv;
+    context->crypto_version = crypto_version;
+    context->crypto_key_slot = crypto_key_slot;
     context->storage = storage;
     context->storage = storage;
     return context;
     return context;
 }
 }
@@ -453,7 +461,9 @@ bool totp_token_info_iterator_go_to(TokenInfoIteratorContext* context, size_t to
                    furi_string_get_cstr(temp_str),
                    furi_string_get_cstr(temp_str),
                    furi_string_size(temp_str),
                    furi_string_size(temp_str),
                    PlainTokenSecretEncodingBase32,
                    PlainTokenSecretEncodingBase32,
-                   context->iv)) {
+                   context->iv,
+                   context->crypto_version,
+                   context->crypto_key_slot)) {
                 FURI_LOG_W(
                 FURI_LOG_W(
                     LOGGING_TAG,
                     LOGGING_TAG,
                     "Token \"%s\" has plain secret",
                     "Token \"%s\" has plain secret",

+ 8 - 2
services/config/token_info_iterator.h

@@ -29,10 +29,16 @@ enum TotpIteratorUpdateTokenResults {
  * @param storage storage reference
  * @param storage storage reference
  * @param config_file config file to use
  * @param config_file config file to use
  * @param iv initialization vector (IV) to be used for encryption\decryption
  * @param iv initialization vector (IV) to be used for encryption\decryption
+ * @param crypto_version crypto algorithm version to be used
+ * @param crypto_key_slot crypto key slot to be used
  * @return Token info iterator context
  * @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,
+    uint8_t* iv,
+    uint8_t crypto_version,
+    uint8_t crypto_key_slot);
 
 
 /**
 /**
  * @brief Navigates iterator to the token with given index
  * @brief Navigates iterator to the token with given index

+ 23 - 0
services/crypto/common_types.h

@@ -0,0 +1,23 @@
+#pragma once
+
+#include <stdint.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
+};

+ 11 - 0
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 (6)
+#define ACCEPTABLE_CRYPTO_KEY_SLOT_END (100)
+
+#define DEFAULT_CRYPTO_KEY_SLOT ACCEPTABLE_CRYPTO_KEY_SLOT_START
+#define CRYPTO_LATEST_VERSION (2)

+ 80 - 0
services/crypto/crypto_facade.c

@@ -0,0 +1,80 @@
+#include "crypto_facade.h"
+#include <furi_hal_crypto.h>
+#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 uint8_t* iv,
+    uint8_t crypto_version,
+    uint8_t key_slot,
+    size_t* encrypted_data_length) {
+    if(crypto_version == 1) {
+        return totp_crypto_encrypt_v1(plain_data, plain_data_length, iv, encrypted_data_length);
+    }
+
+    if(crypto_version == 2) {
+        return totp_crypto_encrypt_v2(
+            plain_data, plain_data_length, iv, key_slot, 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 uint8_t* iv,
+    uint8_t crypto_version,
+    uint8_t key_slot,
+    size_t* decrypted_data_length) {
+    if(crypto_version == 1) {
+        return totp_crypto_decrypt_v1(
+            encrypted_data, encrypted_data_length, iv, decrypted_data_length);
+    }
+
+    if(crypto_version == 2) {
+        return totp_crypto_decrypt_v2(
+            encrypted_data, encrypted_data_length, iv, key_slot, decrypted_data_length);
+    }
+
+    furi_crash("Unsupported crypto version");
+}
+
+CryptoSeedIVResult
+    totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) {
+    if(plugin_state->crypto_version == 1) {
+        return totp_crypto_seed_iv_v1(plugin_state, pin, pin_length);
+    }
+
+    if(plugin_state->crypto_version == 2) {
+        return totp_crypto_seed_iv_v2(plugin_state, pin, pin_length);
+    }
+
+    furi_crash("Unsupported crypto version");
+}
+
+bool totp_crypto_verify_key(const PluginState* plugin_state) {
+    if(plugin_state->crypto_version == 1) {
+        return totp_crypto_verify_key_v1(plugin_state);
+    }
+
+    if(plugin_state->crypto_version == 2) {
+        return totp_crypto_verify_key_v2(plugin_state);
+    }
+
+    furi_crash("Unsupported crypto version");
+}

+ 16 - 19
services/crypto/crypto.h → services/crypto/crypto_facade.h

@@ -1,32 +1,22 @@
 #pragma once
 #pragma once
 
 
 #include "../../types/plugin_state.h"
 #include "../../types/plugin_state.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)
  * @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
  * @param plain_data plain data to be encrypted
  * @param plain_data plain data to be encrypted
  * @param plain_data_length plain data length
  * @param plain_data_length plain data length
  * @param iv initialization vector (IV) to be used to encrypt plain data
  * @param iv initialization vector (IV) to be used to encrypt plain data
+ * @param crypto_version version of crypto algorithms to use
+ * @param key_slot key slot to be used
  * @param[out] encrypted_data_length encrypted data length
  * @param[out] encrypted_data_length encrypted data length
  * @return Encrypted data
  * @return Encrypted data
  */
  */
@@ -34,6 +24,8 @@ uint8_t* totp_crypto_encrypt(
     const uint8_t* plain_data,
     const uint8_t* plain_data,
     const size_t plain_data_length,
     const size_t plain_data_length,
     const uint8_t* iv,
     const uint8_t* iv,
+    uint8_t crypto_version,
+    uint8_t key_slot,
     size_t* encrypted_data_length);
     size_t* encrypted_data_length);
 
 
 /**
 /**
@@ -41,6 +33,8 @@ uint8_t* totp_crypto_encrypt(
  * @param encrypted_data encrypted data to be decrypted
  * @param encrypted_data encrypted data to be decrypted
  * @param encrypted_data_length encrypted data length
  * @param encrypted_data_length encrypted data length
  * @param iv initialization vector (IV) to be used to encrypt plain data
  * @param iv initialization vector (IV) to be used to encrypt plain data
+ * @param crypto_version version of crypto algorithms to use
+ * @param key_slot key slot to be used
  * @param[out] decrypted_data_length decrypted data length
  * @param[out] decrypted_data_length decrypted data length
  * @return Decrypted data
  * @return Decrypted data
  */
  */
@@ -48,11 +42,14 @@ uint8_t* totp_crypto_decrypt(
     const uint8_t* encrypted_data,
     const uint8_t* encrypted_data,
     const size_t encrypted_data_length,
     const size_t encrypted_data_length,
     const uint8_t* iv,
     const uint8_t* iv,
+    uint8_t crypto_version,
+    uint8_t key_slot,
     size_t* decrypted_data_length);
     size_t* decrypted_data_length);
 
 
 /**
 /**
  * @brief Seed initialization vector (IV) using user's PIN
  * @brief Seed initialization vector (IV) using user's PIN
  * @param plugin_state application state
  * @param plugin_state application state
+ * @param key_slot key slot to be used
  * @param pin user's PIN
  * @param pin user's PIN
  * @param pin_length user's PIN length
  * @param pin_length user's PIN length
  * @return Results of seeding IV
  * @return Results of seeding IV

+ 8 - 7
services/crypto/crypto.c → services/crypto/crypto_v1.c

@@ -1,4 +1,4 @@
-#include "crypto.h"
+#include "crypto_v1.h"
 #include <furi_hal_crypto.h>
 #include <furi_hal_crypto.h>
 #include <furi_hal_random.h>
 #include <furi_hal_random.h>
 #include <furi_hal_version.h>
 #include <furi_hal_version.h>
@@ -8,10 +8,11 @@
 #define CRYPTO_KEY_SLOT (2)
 #define CRYPTO_KEY_SLOT (2)
 #define CRYPTO_VERIFY_KEY_LENGTH (16)
 #define CRYPTO_VERIFY_KEY_LENGTH (16)
 #define CRYPTO_ALIGNMENT_FACTOR (16)
 #define CRYPTO_ALIGNMENT_FACTOR (16)
+#define TOTP_IV_SIZE (16)
 
 
 static const char* CRYPTO_VERIFY_KEY = "FFF_Crypto_pass";
 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 uint8_t* plain_data,
     const size_t plain_data_length,
     const size_t plain_data_length,
     const uint8_t* iv,
     const uint8_t* iv,
@@ -48,7 +49,7 @@ uint8_t* totp_crypto_encrypt(
     return encrypted_data;
     return encrypted_data;
 }
 }
 
 
-uint8_t* totp_crypto_decrypt(
+uint8_t* totp_crypto_decrypt_v1(
     const uint8_t* encrypted_data,
     const uint8_t* encrypted_data,
     const size_t encrypted_data_length,
     const size_t encrypted_data_length,
     const uint8_t* iv,
     const uint8_t* iv,
@@ -63,7 +64,7 @@ uint8_t* totp_crypto_decrypt(
 }
 }
 
 
 CryptoSeedIVResult
 CryptoSeedIVResult
-    totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) {
+    totp_crypto_seed_iv_v1(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) {
     CryptoSeedIVResult result;
     CryptoSeedIVResult result;
     if(plugin_state->crypto_verify_data == NULL) {
     if(plugin_state->crypto_verify_data == NULL) {
         FURI_LOG_I(LOGGING_TAG, "Generating new IV");
         FURI_LOG_I(LOGGING_TAG, "Generating new IV");
@@ -104,7 +105,7 @@ CryptoSeedIVResult
         furi_check(plugin_state->crypto_verify_data != NULL);
         furi_check(plugin_state->crypto_verify_data != NULL);
         plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
         plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
 
 
-        plugin_state->crypto_verify_data = totp_crypto_encrypt(
+        plugin_state->crypto_verify_data = totp_crypto_encrypt_v1(
             (const uint8_t*)CRYPTO_VERIFY_KEY,
             (const uint8_t*)CRYPTO_VERIFY_KEY,
             CRYPTO_VERIFY_KEY_LENGTH,
             CRYPTO_VERIFY_KEY_LENGTH,
             &plugin_state->iv[0],
             &plugin_state->iv[0],
@@ -118,9 +119,9 @@ CryptoSeedIVResult
     return result;
     return result;
 }
 }
 
 
-bool totp_crypto_verify_key(const PluginState* plugin_state) {
+bool totp_crypto_verify_key_v1(const PluginState* plugin_state) {
     size_t decrypted_key_length;
     size_t decrypted_key_length;
-    uint8_t* decrypted_key = totp_crypto_decrypt(
+    uint8_t* decrypted_key = totp_crypto_decrypt_v1(
         plugin_state->crypto_verify_data,
         plugin_state->crypto_verify_data,
         plugin_state->crypto_verify_data_length,
         plugin_state->crypto_verify_data_length,
         &plugin_state->iv[0],
         &plugin_state->iv[0],

+ 49 - 0
services/crypto/crypto_v1.h

@@ -0,0 +1,49 @@
+#pragma once
+
+#include "../../types/plugin_state.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 iv initialization vector (IV) to be used to encrypt plain data
+ * @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 uint8_t* iv,
+    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[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 uint8_t* iv,
+    size_t* decrypted_data_length);
+
+/**
+ * @brief Seed initialization vector (IV) using user's PIN
+ * @param plugin_state application state
+ * @param pin user's PIN
+ * @param pin_length user's PIN length
+ * @return Results of seeding IV
+ */
+CryptoSeedIVResult
+    totp_crypto_seed_iv_v1(PluginState* plugin_state, 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
+ * @return \c true if cryptographic information is valid; \c false otherwise
+ */
+bool totp_crypto_verify_key_v1(const PluginState* plugin_state);

+ 173 - 0
services/crypto/crypto_v2.c

@@ -0,0 +1,173 @@
+#include "crypto_v2.h"
+#include <furi_hal_crypto.h>
+#include <furi_hal_random.h>
+#include <furi_hal_version.h>
+#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 uint8_t* iv,
+    uint8_t key_slot,
+    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(key_slot, iv) &&
+                furi_hal_crypto_encrypt(
+                    plain_data_aligned, encrypted_data, plain_data_aligned_length) &&
+                furi_hal_crypto_store_unload_key(key_slot),
+            "Encryption failed");
+
+        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(key_slot, iv) &&
+                furi_hal_crypto_encrypt(plain_data, encrypted_data, plain_data_length) &&
+                furi_hal_crypto_store_unload_key(key_slot),
+            "Encryption failed");
+    }
+
+    return encrypted_data;
+}
+
+uint8_t* totp_crypto_decrypt_v2(
+    const uint8_t* encrypted_data,
+    const size_t encrypted_data_length,
+    const uint8_t* iv,
+    uint8_t key_slot,
+    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(key_slot, iv) &&
+            furi_hal_crypto_decrypt(encrypted_data, decrypted_data, encrypted_data_length) &&
+            furi_hal_crypto_store_unload_key(key_slot),
+        "Decryption failed");
+    return decrypted_data;
+}
+
+CryptoSeedIVResult
+    totp_crypto_seed_iv_v2(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) {
+    CryptoSeedIVResult result;
+    if(plugin_state->crypto_verify_data == NULL) {
+        FURI_LOG_I(LOGGING_TAG, "Generating new IV");
+        furi_hal_random_fill_buf(&plugin_state->base_iv[0], CRYPTO_IV_LENGTH);
+    }
+
+    memcpy(&plugin_state->iv[0], &plugin_state->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, &plugin_state->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(&plugin_state->iv[0], &hmac[offset], CRYPTO_IV_LENGTH);
+
+        result = CryptoSeedIVResultFlagSuccess;
+        if(plugin_state->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");
+            plugin_state->crypto_verify_data = malloc(crypto_vkey_length);
+            furi_check(plugin_state->crypto_verify_data != NULL);
+            plugin_state->crypto_verify_data_length = crypto_vkey_length;
+
+            plugin_state->crypto_verify_data = totp_crypto_encrypt_v2(
+                crypto_vkey,
+                crypto_vkey_length,
+                &plugin_state->iv[0],
+                plugin_state->crypto_key_slot,
+                &plugin_state->crypto_verify_data_length);
+
+            plugin_state->pin_set = pin != NULL && pin_length > 0;
+
+            result |= CryptoSeedIVResultFlagNewCryptoVerifyData;
+        }
+    } else {
+        result = CryptoSeedIVResultFailed;
+    }
+
+    return result;
+}
+
+bool totp_crypto_verify_key_v2(const PluginState* plugin_state) {
+    size_t decrypted_key_length;
+    uint8_t* decrypted_key = totp_crypto_decrypt_v2(
+        plugin_state->crypto_verify_data,
+        plugin_state->crypto_verify_data_length,
+        &plugin_state->iv[0],
+        plugin_state->crypto_key_slot,
+        &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;
+}

+ 54 - 0
services/crypto/crypto_v2.h

@@ -0,0 +1,54 @@
+#pragma once
+
+#include "../../types/plugin_state.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 iv initialization vector (IV) to be used to encrypt plain data
+ * @param key_slot key slot to be used
+ * @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 uint8_t* iv,
+    uint8_t key_slot,
+    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 key_slot key slot to be used
+ * @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 uint8_t* iv,
+    uint8_t key_slot,
+    size_t* decrypted_data_length);
+
+/**
+ * @brief Seed initialization vector (IV) using user's PIN
+ * @param plugin_state application state
+ * @param key_slot key slot to be used
+ * @param pin user's PIN
+ * @param pin_length user's PIN length
+ * @return Results of seeding IV
+ */
+CryptoSeedIVResult
+    totp_crypto_seed_iv_v2(PluginState* plugin_state, 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
+ * @return \c true if cryptographic information is valid; \c false otherwise
+ */
+bool totp_crypto_verify_key_v2(const PluginState* plugin_state);

+ 38 - 31
totp_app.c

@@ -15,21 +15,26 @@
 #include "ui/scene_director.h"
 #include "ui/scene_director.h"
 #include "ui/constants.h"
 #include "ui/constants.h"
 #include "ui/common_dialogs.h"
 #include "ui/common_dialogs.h"
-#include "services/crypto/crypto.h"
+#include "services/crypto/crypto_facade.h"
 #include "cli/cli.h"
 #include "cli/cli.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);
     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};
     PluginEvent event = {.type = EventTypeKey, .input = *input_event};
     furi_message_queue_put(event_queue, &event, FuriWaitForever);
     furi_message_queue_put(event_queue, &event, FuriWaitForever);
 }
 }
@@ -81,6 +86,7 @@ static bool totp_activate_initial_scene(PluginState* const plugin_state) {
         }
         }
 
 
         if(totp_crypto_verify_key(plugin_state)) {
         if(totp_crypto_verify_key(plugin_state)) {
+            totp_config_file_ensure_latest_encryption(plugin_state, NULL, 0);
             totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
             totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
         } else {
         } else {
             FURI_LOG_E(
             FURI_LOG_E(
@@ -117,16 +123,15 @@ static bool on_user_idle(void* context) {
 
 
 static bool totp_plugin_state_init(PluginState* const plugin_state) {
 static bool totp_plugin_state_init(PluginState* const plugin_state) {
     plugin_state->gui = furi_record_open(RECORD_GUI);
     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);
     plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS);
-    memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
+    memset(&plugin_state->iv[0], 0, CRYPTO_IV_LENGTH);
 
 
     if(!totp_config_file_load(plugin_state)) {
     if(!totp_config_file_load(plugin_state)) {
         totp_dialogs_config_loading_error(plugin_state);
         totp_dialogs_config_loading_error(plugin_state);
         return false;
         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_TYPE_ENABLED
     if(plugin_state->automation_method & AutomationMethodBadBt) {
     if(plugin_state->automation_method & AutomationMethodBadBt) {
@@ -154,7 +159,6 @@ static void totp_plugin_state_free(PluginState* plugin_state) {
     }
     }
 
 
     furi_record_close(RECORD_GUI);
     furi_record_close(RECORD_GUI);
-    furi_record_close(RECORD_NOTIFICATION);
     furi_record_close(RECORD_DIALOGS);
     furi_record_close(RECORD_DIALOGS);
 
 
     totp_config_file_close(plugin_state);
     totp_config_file_close(plugin_state);
@@ -170,12 +174,11 @@ static void totp_plugin_state_free(PluginState* plugin_state) {
     }
     }
 #endif
 #endif
 
 
-    furi_mutex_free(plugin_state->mutex);
+    furi_message_queue_free(plugin_state->event_queue);
     free(plugin_state);
     free(plugin_state);
 }
 }
 
 
 int32_t totp_app() {
 int32_t totp_app() {
-    FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
     PluginState* plugin_state = malloc(sizeof(PluginState));
     PluginState* plugin_state = malloc(sizeof(PluginState));
     furi_check(plugin_state != NULL);
     furi_check(plugin_state != NULL);
 
 
@@ -185,7 +188,7 @@ int32_t totp_app() {
         return 254;
         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)) {
     if(!totp_activate_initial_scene(plugin_state)) {
         FURI_LOG_E(LOGGING_TAG, "An error ocurred during activating initial scene\r\n");
         FURI_LOG_E(LOGGING_TAG, "An error ocurred during activating initial scene\r\n");
@@ -196,10 +199,14 @@ int32_t totp_app() {
     // Affecting dolphin level
     // Affecting dolphin level
     dolphin_deed(DolphinDeedPluginStart);
     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
     // Set system callbacks
     ViewPort* view_port = view_port_alloc();
     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
     // Open GUI and register view_port
     gui_add_view_port(plugin_state->gui, view_port, GuiLayerFullscreen);
     gui_add_view_port(plugin_state->gui, view_port, GuiLayerFullscreen);
@@ -207,24 +214,24 @@ int32_t totp_app() {
     PluginEvent event;
     PluginEvent event;
     bool processing = true;
     bool processing = true;
     while(processing) {
     while(processing) {
-        FuriStatus event_status = furi_message_queue_get(event_queue, &event, FuriWaitForever);
-
-        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) {
                 if(event.type == EventTypeKey && plugin_state->idle_timeout_context != NULL) {
                     idle_timeout_report_activity(plugin_state->idle_timeout_context);
                     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);
     totp_cli_unregister_command_handler(cli_context);
@@ -233,7 +240,7 @@ int32_t totp_app() {
     view_port_enabled_set(view_port, false);
     view_port_enabled_set(view_port, false);
     gui_remove_view_port(plugin_state->gui, view_port);
     gui_remove_view_port(plugin_state->gui, view_port);
     view_port_free(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);
     totp_plugin_state_free(plugin_state);
     return 0;
     return 0;
 }
 }

+ 1 - 1
types/event_type.h

@@ -3,4 +3,4 @@
 
 
 typedef uint8_t EventType;
 typedef uint8_t EventType;
 
 
-enum EventTypes { EventTypeTick, EventTypeKey, EventForceCloseApp };
+enum EventTypes { EventTypeTick, EventTypeKey, EventForceCloseApp, EventForceRedraw };

+ 20 - 16
types/plugin_state.h

@@ -12,8 +12,7 @@
 #ifdef TOTP_BADBT_TYPE_ENABLED
 #ifdef TOTP_BADBT_TYPE_ENABLED
 #include "../workers/bt_type_code/bt_type_code.h"
 #include "../workers/bt_type_code/bt_type_code.h"
 #endif
 #endif
-
-#define TOTP_IV_SIZE (16)
+#include "../services/crypto/constants.h"
 
 
 /**
 /**
  * @brief Application state structure
  * @brief Application state structure
@@ -29,11 +28,6 @@ typedef struct {
      */
      */
     void* current_scene_state;
     void* current_scene_state;
 
 
-    /**
-     * @brief Reference to the firmware notification subsystem
-     */
-    NotificationApp* notification_app;
-
     /**
     /**
      * @brief Reference to the firmware dialogs subsystem 
      * @brief Reference to the firmware dialogs subsystem 
      */
      */
@@ -55,12 +49,12 @@ typedef struct {
     ConfigFileContext* config_file_context;
     ConfigFileContext* config_file_context;
 
 
     /**
     /**
-     * @brief Encrypted well-known string data
+     * @brief Encrypted well-known data
      */
      */
     uint8_t* crypto_verify_data;
     uint8_t* crypto_verify_data;
 
 
     /**
     /**
-     * @brief Encrypted well-known string data length
+     * @brief Encrypted well-known data length
      */
      */
     size_t crypto_verify_data_length;
     size_t crypto_verify_data_length;
 
 
@@ -72,23 +66,18 @@ typedef struct {
     /**
     /**
      * @brief Initialization vector (IV) to be used for encryption\decryption 
      * @brief Initialization vector (IV) to be used for encryption\decryption 
      */
      */
-    uint8_t iv[TOTP_IV_SIZE];
+    uint8_t iv[CRYPTO_IV_LENGTH];
 
 
     /**
     /**
      * @brief Basic randomly-generated initialization vector (IV)
      * @brief Basic randomly-generated initialization vector (IV)
      */
      */
-    uint8_t base_iv[TOTP_IV_SIZE];
+    uint8_t base_iv[CRYPTO_IV_LENGTH];
 
 
     /**
     /**
      * @brief Notification method
      * @brief Notification method
      */
      */
     NotificationMethod notification_method;
     NotificationMethod notification_method;
 
 
-    /**
-     * @brief Main rendering loop mutex
-     */
-    FuriMutex* mutex;
-
     /**
     /**
      * @brief Automation method
      * @brief Automation method
      */
      */
@@ -110,4 +99,19 @@ typedef struct {
      * @brief Font index to be used to draw TOTP token
      * @brief Font index to be used to draw TOTP token
      */
      */
     uint8_t active_font_index;
     uint8_t active_font_index;
+
+    /**
+     * @brief Crypto key slot to be used
+     */
+    uint8_t crypto_key_slot;
+
+    /**
+     * @brief Crypto algorithms version to be used
+     */
+    uint8_t crypto_version;
+
+    /**
+     * @brief Application even queue
+     */
+    FuriMessageQueue* event_queue;
 } PluginState;
 } PluginState;

+ 11 - 4
types/token_info.c

@@ -3,7 +3,7 @@
 #include <base64.h>
 #include <base64.h>
 #include <memset_s.h>
 #include <memset_s.h>
 #include "common.h"
 #include "common.h"
-#include "../services/crypto/crypto.h"
+#include "../services/crypto/crypto_facade.h"
 
 
 TokenInfo* token_info_alloc() {
 TokenInfo* token_info_alloc() {
     TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
     TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
@@ -25,7 +25,9 @@ bool token_info_set_secret(
     const char* plain_token_secret,
     const char* plain_token_secret,
     size_t token_secret_length,
     size_t token_secret_length,
     PlainTokenSecretEncoding plain_token_secret_encoding,
     PlainTokenSecretEncoding plain_token_secret_encoding,
-    const uint8_t* iv) {
+    const uint8_t* iv,
+    uint8_t crypto_version,
+    uint8_t crypto_key_slot) {
     if(token_secret_length == 0) return false;
     if(token_secret_length == 0) return false;
     uint8_t* plain_secret;
     uint8_t* plain_secret;
     size_t plain_secret_length;
     size_t plain_secret_length;
@@ -54,8 +56,13 @@ bool token_info_set_secret(
             free(token_info->token);
             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,
+            iv,
+            crypto_version,
+            crypto_key_slot,
+            &token_info->token_length);
         result = true;
         result = true;
     } else {
     } else {
         result = false;
         result = false;

+ 5 - 1
types/token_info.h

@@ -201,6 +201,8 @@ void token_info_free(TokenInfo* token_info);
  * @param token_secret_length plain token secret length
  * @param token_secret_length plain token secret length
  * @param plain_token_secret_encoding plain token secret encoding
  * @param plain_token_secret_encoding plain token secret encoding
  * @param iv initialization vecor (IV) to be used for encryption
  * @param iv initialization vecor (IV) to be used for encryption
+ * @param crypto_version crypto algorithm version to be used
+ * @param crypto_key_slot crypto key slot to be used
  * @return \c true if token successfully set; \c false otherwise
  * @return \c true if token successfully set; \c false otherwise
  */
  */
 bool token_info_set_secret(
 bool token_info_set_secret(
@@ -208,7 +210,9 @@ bool token_info_set_secret(
     const char* plain_token_secret,
     const char* plain_token_secret,
     size_t token_secret_length,
     size_t token_secret_length,
     PlainTokenSecretEncoding plain_token_secret_encoding,
     PlainTokenSecretEncoding plain_token_secret_encoding,
-    const uint8_t* iv);
+    const uint8_t* iv,
+    uint8_t crypto_version,
+    uint8_t crypto_key_slot);
 
 
 /**
 /**
  * @brief Sets token digits count from \c uint8_t value
  * @brief Sets token digits count from \c uint8_t value

+ 5 - 0
ui/scene_director.c

@@ -116,3 +116,8 @@ bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* con
 
 
     return processing;
     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);
+}

+ 6 - 0
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
  * @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);
 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);

+ 9 - 2
ui/scenes/add_new_token/totp_scene_add_new_token.c

@@ -43,6 +43,8 @@ typedef struct {
 struct TotpAddContext {
 struct TotpAddContext {
     SceneState* scene_state;
     SceneState* scene_state;
     uint8_t* iv;
     uint8_t* iv;
+    uint8_t crypto_version;
+    uint8_t crypto_key_slot;
 };
 };
 
 
 enum TotpIteratorUpdateTokenResultsEx { TotpIteratorUpdateTokenResultInvalidSecret = 1 };
 enum TotpIteratorUpdateTokenResultsEx { TotpIteratorUpdateTokenResultInvalidSecret = 1 };
@@ -58,7 +60,9 @@ static TotpIteratorUpdateTokenResult add_token_handler(TokenInfo* tokenInfo, con
            context_t->scene_state->token_secret,
            context_t->scene_state->token_secret,
            context_t->scene_state->token_secret_length,
            context_t->scene_state->token_secret_length,
            PlainTokenSecretEncodingBase32,
            PlainTokenSecretEncodingBase32,
-           context_t->iv)) {
+           context_t->iv,
+           context_t->crypto_version,
+           context_t->crypto_key_slot)) {
         return TotpIteratorUpdateTokenResultInvalidSecret;
         return TotpIteratorUpdateTokenResultInvalidSecret;
     }
     }
 
 
@@ -271,7 +275,10 @@ bool totp_scene_add_new_token_handle_event(
             break;
             break;
         case ConfirmButton: {
         case ConfirmButton: {
             struct TotpAddContext add_context = {
             struct TotpAddContext add_context = {
-                .iv = plugin_state->iv, .scene_state = scene_state};
+                .iv = plugin_state->iv,
+                .scene_state = scene_state,
+                .crypto_version = plugin_state->crypto_version,
+                .crypto_key_slot = plugin_state->crypto_key_slot};
             TokenInfoIteratorContext* iterator_context =
             TokenInfoIteratorContext* iterator_context =
                 totp_config_get_token_iterator_context(plugin_state);
                 totp_config_get_token_iterator_context(plugin_state);
             TotpIteratorUpdateTokenResult add_result = totp_token_info_iterator_add_new_token(
             TotpIteratorUpdateTokenResult add_result = totp_token_info_iterator_add_new_token(

+ 6 - 4
ui/scenes/authenticate/totp_scene_authenticate.c

@@ -6,10 +6,10 @@
 #include "../../../services/config/config.h"
 #include "../../../services/config/config.h"
 #include "../../scene_director.h"
 #include "../../scene_director.h"
 #include "../../totp_scenes_enum.h"
 #include "../../totp_scenes_enum.h"
-#include "../../../services/crypto/crypto.h"
+#include "../../../services/crypto/crypto_facade.h"
 #include "../../../types/user_pin_codes.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_RADIUS = 3;
 static const uint8_t PIN_ASTERISK_STEP = (PIN_ASTERISK_RADIUS << 1) + 2;
 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;
     scene_state->code_length = 0;
     memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
     memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
     plugin_state->current_scene_state = scene_state;
     plugin_state->current_scene_state = scene_state;
-    memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
+    memset(&plugin_state->iv[0], 0, CRYPTO_IV_LENGTH);
 }
 }
 
 
 void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) {
 void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) {
@@ -132,11 +132,13 @@ bool totp_scene_authenticate_handle_event(
 
 
         if(totp_crypto_verify_key(plugin_state)) {
         if(totp_crypto_verify_key(plugin_state)) {
             FURI_LOG_D(LOGGING_TAG, "PIN is valid");
             FURI_LOG_D(LOGGING_TAG, "PIN is valid");
+            totp_config_file_ensure_latest_encryption(
+                plugin_state, &scene_state->code_input[0], scene_state->code_length);
             totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
             totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken);
         } else {
         } else {
             FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid");
             FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid");
             memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
             memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
-            memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
+            memset(&plugin_state->iv[0], 0, CRYPTO_IV_LENGTH);
             scene_state->code_length = 0;
             scene_state->code_length = 0;
 
 
             DialogMessage* message = dialog_message_alloc();
             DialogMessage* message = dialog_message_alloc();

+ 18 - 8
ui/scenes/generate_token/totp_scene_generate_token.c

@@ -39,6 +39,7 @@ typedef struct {
     TotpGenerateCodeWorkerContext* generate_code_worker_context;
     TotpGenerateCodeWorkerContext* generate_code_worker_context;
     UiPrecalculatedDimensions ui_precalculated_dimensions;
     UiPrecalculatedDimensions ui_precalculated_dimensions;
     const FONT_INFO* active_font;
     const FONT_INFO* active_font;
+    NotificationApp* notification_app;
 } SceneState;
 } SceneState;
 
 
 static const NotificationSequence*
 static const NotificationSequence*
@@ -153,7 +154,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) {
 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 =
     const TokenInfoIteratorContext* iterator_context =
         totp_config_get_token_iterator_context(plugin_state);
         totp_config_get_token_iterator_context(plugin_state);
     if(totp_token_info_iterator_get_total_count(iterator_context) == 0) {
     if(totp_token_info_iterator_get_total_count(iterator_context) == 0) {
@@ -174,13 +175,16 @@ static void on_new_token_code_generated(bool time_left, void* context) {
 
 
     if(time_left) {
     if(time_left) {
         notification_message(
         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) {
 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 =
     scene_state->ui_precalculated_dimensions.progress_bar_width =
         (uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * code_lifetime_percent);
         (uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * code_lifetime_percent);
     scene_state->ui_precalculated_dimensions.progress_bar_x =
     scene_state->ui_precalculated_dimensions.progress_bar_x =
@@ -188,6 +192,7 @@ static void on_code_lifetime_updated_generated(float code_lifetime_percent, void
           scene_state->ui_precalculated_dimensions.progress_bar_width) >>
           scene_state->ui_precalculated_dimensions.progress_bar_width) >>
          1) +
          1) +
         PROGRESS_BAR_MARGIN;
         PROGRESS_BAR_MARGIN;
+    totp_scene_director_force_redraw(plugin_state);
 }
 }
 
 
 void totp_scene_generate_token_activate(PluginState* plugin_state) {
 void totp_scene_generate_token_activate(PluginState* plugin_state) {
@@ -204,6 +209,7 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) {
     }
     }
 
 
     scene_state->active_font = available_fonts[plugin_state->active_font_index];
     scene_state->active_font = available_fonts[plugin_state->active_font_index];
+    scene_state->notification_app = furi_record_open(RECORD_NOTIFICATION);
 
 
 #ifdef TOTP_BADBT_TYPE_ENABLED
 #ifdef TOTP_BADBT_TYPE_ENABLED
 
 
@@ -225,7 +231,9 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) {
         totp_token_info_iterator_get_current_token(iterator_context),
         totp_token_info_iterator_get_current_token(iterator_context),
         scene_state->last_code_update_sync,
         scene_state->last_code_update_sync,
         plugin_state->timezone_offset,
         plugin_state->timezone_offset,
-        plugin_state->iv);
+        plugin_state->iv,
+        plugin_state->crypto_version,
+        plugin_state->crypto_key_slot);
 
 
     totp_generate_code_worker_set_code_generated_handler(
     totp_generate_code_worker_set_code_generated_handler(
         scene_state->generate_code_worker_context, &on_new_token_code_generated, plugin_state);
         scene_state->generate_code_worker_context, &on_new_token_code_generated, plugin_state);
@@ -233,7 +241,7 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) {
     totp_generate_code_worker_set_lifetime_changed_handler(
     totp_generate_code_worker_set_lifetime_changed_handler(
         scene_state->generate_code_worker_context,
         scene_state->generate_code_worker_context,
         &on_code_lifetime_updated_generated,
         &on_code_lifetime_updated_generated,
-        scene_state);
+        plugin_state);
 
 
     update_totp_params(
     update_totp_params(
         plugin_state, totp_token_info_iterator_get_current_token_index(iterator_context));
         plugin_state, totp_token_info_iterator_get_current_token_index(iterator_context));
@@ -350,7 +358,7 @@ bool totp_scene_generate_token_handle_event(
                 TotpUsbTypeCodeWorkerEventType,
                 TotpUsbTypeCodeWorkerEventType,
                 totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
                 totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
             notification_message(
             notification_message(
-                plugin_state->notification_app,
+                scene_state->notification_app,
                 get_notification_sequence_automation(plugin_state, scene_state));
                 get_notification_sequence_automation(plugin_state, scene_state));
             return true;
             return true;
         }
         }
@@ -366,7 +374,7 @@ bool totp_scene_generate_token_handle_event(
                 TotpBtTypeCodeWorkerEventType,
                 TotpBtTypeCodeWorkerEventType,
                 totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
                 totp_token_info_iterator_get_current_token(iterator_context)->automation_features);
             notification_message(
             notification_message(
-                plugin_state->notification_app,
+                scene_state->notification_app,
                 get_notification_sequence_automation(plugin_state, scene_state));
                 get_notification_sequence_automation(plugin_state, scene_state));
             return true;
             return true;
         }
         }
@@ -427,6 +435,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
 
 
     totp_generate_code_worker_stop(scene_state->generate_code_worker_context);
     totp_generate_code_worker_stop(scene_state->generate_code_worker_context);
 
 
+    furi_record_close(RECORD_NOTIFICATION);
+
     if(plugin_state->automation_method & AutomationMethodBadUsb) {
     if(plugin_state->automation_method & AutomationMethodBadUsb) {
         totp_usb_type_code_worker_stop(scene_state->usb_type_code_worker_context);
         totp_usb_type_code_worker_stop(scene_state->usb_type_code_worker_context);
     }
     }

+ 14 - 3
workers/generate_totp_code/generate_totp_code.c

@@ -1,6 +1,6 @@
 #include "generate_totp_code.h"
 #include "generate_totp_code.h"
 #include <furi/core/thread.h>
 #include <furi/core/thread.h>
-#include "../../services/crypto/crypto.h"
+#include "../../services/crypto/crypto_facade.h"
 #include "../../services/totp/totp.h"
 #include "../../services/totp/totp.h"
 #include "../../services/convert/convert.h"
 #include "../../services/convert/convert.h"
 #include <furi_hal_rtc.h>
 #include <furi_hal_rtc.h>
@@ -15,6 +15,8 @@ struct TotpGenerateCodeWorkerContext {
     const TokenInfo* token_info;
     const TokenInfo* token_info;
     float timezone_offset;
     float timezone_offset;
     uint8_t* iv;
     uint8_t* iv;
+    uint8_t crypto_version;
+    uint8_t crypto_key_slot;
     TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler;
     TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler;
     void* on_new_code_generated_handler_context;
     void* on_new_code_generated_handler_context;
     TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler;
     TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler;
@@ -69,7 +71,12 @@ static void generate_totp_code(
     if(token_info->token != NULL && token_info->token_length > 0) {
     if(token_info->token != NULL && token_info->token_length > 0) {
         size_t key_length;
         size_t key_length;
         uint8_t* key = totp_crypto_decrypt(
         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->iv,
+            context->crypto_version,
+            context->crypto_key_slot,
+            &key_length);
 
 
         int_token_to_str(
         int_token_to_str(
             totp_at(
             totp_at(
@@ -147,7 +154,9 @@ TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
     const TokenInfo* token_info,
     const TokenInfo* token_info,
     FuriMutex* code_buffer_sync,
     FuriMutex* code_buffer_sync,
     float timezone_offset,
     float timezone_offset,
-    uint8_t* iv) {
+    uint8_t* iv,
+    uint8_t crypto_version,
+    uint8_t crypto_key_slot) {
     TotpGenerateCodeWorkerContext* context = malloc(sizeof(TotpGenerateCodeWorkerContext));
     TotpGenerateCodeWorkerContext* context = malloc(sizeof(TotpGenerateCodeWorkerContext));
     furi_check(context != NULL);
     furi_check(context != NULL);
     context->code_buffer = code_buffer;
     context->code_buffer = code_buffer;
@@ -155,6 +164,8 @@ TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
     context->code_buffer_sync = code_buffer_sync;
     context->code_buffer_sync = code_buffer_sync;
     context->timezone_offset = timezone_offset;
     context->timezone_offset = timezone_offset;
     context->iv = iv;
     context->iv = iv;
+    context->crypto_version = crypto_version;
+    context->crypto_key_slot = crypto_key_slot;
     context->thread = furi_thread_alloc();
     context->thread = furi_thread_alloc();
     furi_thread_set_name(context->thread, "TOTPGenerateWorker");
     furi_thread_set_name(context->thread, "TOTPGenerateWorker");
     furi_thread_set_stack_size(context->thread, 2048);
     furi_thread_set_stack_size(context->thread, 2048);

+ 4 - 1
workers/generate_totp_code/generate_totp_code.h

@@ -39,6 +39,7 @@ enum TotGenerateCodeWorkerEvents {
  * @param code_buffer_sync code buffer synchronization primitive
  * @param code_buffer_sync code buffer synchronization primitive
  * @param timezone_offset timezone offset to be used to generate code
  * @param timezone_offset timezone offset to be used to generate code
  * @param iv initialization vector (IV) to be used to decrypt token secret
  * @param iv initialization vector (IV) to be used to decrypt token secret
+ * @param crypto_key_slot crypto key slot to be used
  * @return worker context
  * @return worker context
  */
  */
 TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
 TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
@@ -46,7 +47,9 @@ TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
     const TokenInfo* token_info,
     const TokenInfo* token_info,
     FuriMutex* code_buffer_sync,
     FuriMutex* code_buffer_sync,
     float timezone_offset,
     float timezone_offset,
-    uint8_t* iv);
+    uint8_t* iv,
+    uint8_t crypto_version,
+    uint8_t crypto_key_slot);
 
 
 /**
 /**
  * @brief Stops generate code worker
  * @brief Stops generate code worker