diff --git a/application.fam b/application.fam index 87a7f86fde5..52896ee63d4 100644 --- a/application.fam +++ b/application.fam @@ -28,7 +28,10 @@ App( name="base32", ), Lib( - name="list", + name="base64", + ), + Lib( + name="linked_list" ), Lib( name="timezone_utils", diff --git a/cli/cli_helpers.c b/cli/cli_helpers.c index 9c524b42625..36b98cf6503 100644 --- a/cli/cli_helpers.c +++ b/cli/cli_helpers.c @@ -41,7 +41,9 @@ bool totp_cli_read_line(Cli* cli, FuriString* out_str, bool mask_user_input) { } else if(c == CliSymbolAsciiETX) { cli_nl(); return false; - } else if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + } else if( + (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + c == '/' || c == '=' || c == '+') { if(mask_user_input) { putc('*', stdout); } else { diff --git a/cli/cli_helpers.h b/cli/cli_helpers.h index f3f8d963d46..dd5a282d48a 100644 --- a/cli/cli_helpers.h +++ b/cli/cli_helpers.h @@ -14,24 +14,13 @@ #define DOCOPT_OPTIONS "[options]" #define DOCOPT_DEFAULT(val) "[default: " val "]" -#define TOTP_CLI_PRINTF(format, ...) \ - do { \ - _Pragma(STRINGIFY(GCC diagnostic push)) \ - _Pragma(STRINGIFY(GCC diagnostic ignored "-Wdouble-promotion")) \ - printf(format, ##__VA_ARGS__); \ - _Pragma(STRINGIFY(GCC diagnostic pop)) \ - } while(false) - -#define TOTP_CLI_PRINTF_COLORFUL(color, format, ...) \ - do { \ - _Pragma(STRINGIFY(GCC diagnostic push)) \ - _Pragma(STRINGIFY(GCC diagnostic ignored "-Wdouble-promotion")) \ - printf("\e[%s", color); \ - printf(format, ##__VA_ARGS__); \ - printf("\e[0m"); \ - fflush(stdout); \ - _Pragma(STRINGIFY(GCC diagnostic pop)) \ - } while(false) +#define TOTP_CLI_PRINTF(format, ...) printf(format, ##__VA_ARGS__) + +#define TOTP_CLI_PRINTF_COLORFUL(color, format, ...) \ + printf("\e[%s", color); \ + printf(format, ##__VA_ARGS__); \ + printf("\e[0m"); \ + fflush(stdout) #define TOTP_CLI_COLOR_ERROR "91m" #define TOTP_CLI_COLOR_WARNING "93m" diff --git a/cli/commands/add/add.c b/cli/commands/add/add.c index 4cfd4fe06f0..f842a2dace9 100644 --- a/cli/commands/add/add.c +++ b/cli/commands/add/add.c @@ -1,7 +1,7 @@ #include "add.h" #include #include -#include "../../../lib/list/list.h" +#include #include "../../../types/token_info.h" #include "../../../services/config/config.h" #include "../../../services/convert/convert.h" @@ -35,11 +35,21 @@ void totp_cli_command_add_docopt_options() { TOTP_CLI_COMMAND_ARG_ALGO)) " Token hashing algorithm. Must be one of: " TOTP_TOKEN_ALGO_SHA1_NAME ", " TOTP_TOKEN_ALGO_SHA256_NAME ", " TOTP_TOKEN_ALGO_SHA512_NAME + ", " TOTP_TOKEN_ALGO_STEAM_NAME " " DOCOPT_DEFAULT(TOTP_TOKEN_ALGO_SHA1_NAME) "\r\n"); TOTP_CLI_PRINTF(" " DOCOPT_OPTION( TOTP_CLI_COMMAND_ARG_DIGITS_PREFIX, DOCOPT_ARGUMENT( - TOTP_CLI_COMMAND_ARG_DIGITS)) " Number of digits to generate, one of: 6, 8 " DOCOPT_DEFAULT("6") "\r\n"); + TOTP_CLI_COMMAND_ARG_DIGITS)) " Number of digits to generate, one of: 5, 6, 8 " DOCOPT_DEFAULT("6") "\r\n"); + + TOTP_CLI_PRINTF(" " DOCOPT_OPTION( + TOTP_CLI_COMMAND_ARG_SECRET_ENCODING_PREFIX, + DOCOPT_ARGUMENT( + TOTP_CLI_COMMAND_ARG_SECRET_ENCODING)) " Token secret encoding, one of " PLAIN_TOKEN_ENCODING_BASE32_NAME + ", " PLAIN_TOKEN_ENCODING_BASE64_NAME + " " DOCOPT_DEFAULT( + PLAIN_TOKEN_ENCODING_BASE32_NAME) "\r\n"); + TOTP_CLI_PRINTF(" " DOCOPT_OPTION( TOTP_CLI_COMMAND_ARG_DURATION_PREFIX, DOCOPT_ARGUMENT( @@ -83,13 +93,16 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl // Read optional arguments bool mask_user_input = true; + PlainTokenSecretEncoding token_secret_encoding = PLAIN_TOKEN_ENCODING_BASE32; while(args_read_string_and_trim(args, temp_str)) { bool parsed = false; if(!totp_cli_try_read_algo(token_info, temp_str, args, &parsed) && !totp_cli_try_read_digits(token_info, temp_str, args, &parsed) && !totp_cli_try_read_duration(token_info, temp_str, args, &parsed) && !totp_cli_try_read_unsecure_flag(temp_str, &parsed, &mask_user_input) && - !totp_cli_try_read_automation_features(token_info, temp_str, args, &parsed)) { + !totp_cli_try_read_automation_features(token_info, temp_str, args, &parsed) && + !totp_cli_try_read_plain_token_secret_encoding( + temp_str, args, &parsed, &token_secret_encoding)) { totp_cli_printf_unknown_argument(temp_str); } @@ -115,31 +128,34 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl TOTP_CLI_DELETE_LAST_LINE(); - if(!token_info_set_secret( - token_info, - furi_string_get_cstr(temp_str), - furi_string_size(temp_str), - plugin_state->iv)) { - TOTP_CLI_PRINTF_ERROR("Token secret seems to be invalid and can not be parsed\r\n"); - furi_string_secure_free(temp_str); - token_info_free(token_info); - return; - } - - furi_string_secure_free(temp_str); - bool load_generate_token_scene = false; if(plugin_state->current_scene == TotpSceneGenerateToken) { totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL); load_generate_token_scene = true; } - TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, token_info, furi_check); - plugin_state->tokens_count++; - if(totp_config_file_save_new_token(token_info) == TotpConfigFileUpdateSuccess) { - TOTP_CLI_PRINTF_SUCCESS("Token \"%s\" has been successfully added\r\n", token_info->name); + bool secret_set = token_info_set_secret( + token_info, + furi_string_get_cstr(temp_str), + furi_string_size(temp_str), + token_secret_encoding, + plugin_state->iv); + + furi_string_secure_free(temp_str); + + if(secret_set) { + TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, token_info, furi_check); + plugin_state->tokens_count++; + + if(totp_config_file_save_new_token(token_info) == TotpConfigFileUpdateSuccess) { + TOTP_CLI_PRINTF_SUCCESS( + "Token \"%s\" has been successfully added\r\n", token_info->name); + } else { + TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE(); + } } else { - TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE(); + token_info_free(token_info); + TOTP_CLI_PRINTF_ERROR("Token secret seems to be invalid and can not be parsed\r\n"); } if(load_generate_token_scene) { diff --git a/cli/commands/delete/delete.c b/cli/commands/delete/delete.c index 96a205f577d..a45525e4b0b 100644 --- a/cli/commands/delete/delete.c +++ b/cli/commands/delete/delete.c @@ -3,7 +3,7 @@ #include #include #include -#include "../../../lib/list/list.h" +#include #include "../../../services/config/config.h" #include "../../cli_helpers.h" #include "../../../ui/scene_director.h" diff --git a/cli/commands/details/details.c b/cli/commands/details/details.c index aa16295a499..1b928945475 100644 --- a/cli/commands/details/details.c +++ b/cli/commands/details/details.c @@ -1,7 +1,7 @@ #include "details.h" #include #include -#include "../../../lib/list/list.h" +#include #include "../../../types/token_info.h" #include "../../../services/config/constants.h" #include "../../cli_helpers.h" diff --git a/cli/commands/list/list.c b/cli/commands/list/list.c index 6314b1b33b3..951c102a0a5 100644 --- a/cli/commands/list/list.c +++ b/cli/commands/list/list.c @@ -1,6 +1,6 @@ #include "list.h" #include -#include "../../../lib/list/list.h" +#include #include "../../../types/token_info.h" #include "../../../services/config/constants.h" #include "../../cli_helpers.h" diff --git a/cli/commands/move/move.c b/cli/commands/move/move.c index 265c7bc64cb..5c4bdfcd62b 100644 --- a/cli/commands/move/move.c +++ b/cli/commands/move/move.c @@ -2,7 +2,7 @@ #include #include -#include "../../../lib/list/list.h" +#include #include "../../../types/token_info.h" #include "../../../services/config/config.h" #include "../../cli_helpers.h" diff --git a/cli/commands/pin/pin.c b/cli/commands/pin/pin.c index b5b4943d6b4..92c9c59c418 100644 --- a/cli/commands/pin/pin.c +++ b/cli/commands/pin/pin.c @@ -2,11 +2,12 @@ #include #include +#include #include "../../../types/token_info.h" #include "../../../types/user_pin_codes.h" #include "../../../services/config/config.h" #include "../../cli_helpers.h" -#include "../../../lib/polyfills/memset_s.h" +#include #include "../../../services/crypto/crypto.h" #include "../../../ui/scene_director.h" diff --git a/cli/commands/timezone/timezone.c b/cli/commands/timezone/timezone.c index 265d80e5335..61e4fa06593 100644 --- a/cli/commands/timezone/timezone.c +++ b/cli/commands/timezone/timezone.c @@ -35,7 +35,7 @@ void totp_cli_command_timezone_handle(PluginState* plugin_state, FuriString* arg if(*strtof_endptr == 0 && tz >= -12.75f && tz <= 12.75f) { plugin_state->timezone_offset = tz; if(totp_config_file_update_timezone_offset(tz) == TotpConfigFileUpdateSuccess) { - TOTP_CLI_PRINTF_SUCCESS("Timezone is set to %f\r\n", tz); + TOTP_CLI_PRINTF_SUCCESS("Timezone is set to %f\r\n", (double)tz); } else { TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE(); } @@ -50,7 +50,8 @@ void totp_cli_command_timezone_handle(PluginState* plugin_state, FuriString* arg TOTP_CLI_PRINTF_ERROR("Invalid timezone offset\r\n"); } } else { - TOTP_CLI_PRINTF_INFO("Current timezone offset is %f\r\n", plugin_state->timezone_offset); + TOTP_CLI_PRINTF_INFO( + "Current timezone offset is %f\r\n", (double)plugin_state->timezone_offset); } furi_string_free(temp_str); } \ No newline at end of file diff --git a/cli/commands/update/update.c b/cli/commands/update/update.c index 669a36db897..117cc220f15 100644 --- a/cli/commands/update/update.c +++ b/cli/commands/update/update.c @@ -1,7 +1,7 @@ #include "update.h" #include #include -#include "../../../lib/list/list.h" +#include #include "../../../types/token_info.h" #include "../../../services/config/config.h" #include "../../../services/convert/convert.h" @@ -18,17 +18,20 @@ void totp_cli_command_update_docopt_commands() { void totp_cli_command_update_docopt_usage() { TOTP_CLI_PRINTF( " " TOTP_CLI_COMMAND_NAME - " " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_UPDATE) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_INDEX) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_ALGO_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_ALGO))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_NAME_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_NAME))) " " DOCOPT_OPTIONAL( + " " DOCOPT_REQUIRED(TOTP_CLI_COMMAND_UPDATE) " " DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_INDEX) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_ALGO_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_ALGO))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_NAME_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_NAME))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_DIGITS_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_DIGITS))) " " DOCOPT_OPTIONAL( DOCOPT_OPTION( - TOTP_CLI_COMMAND_ARG_DIGITS_PREFIX, + TOTP_CLI_COMMAND_ARG_DURATION_PREFIX, DOCOPT_ARGUMENT( - TOTP_CLI_COMMAND_ARG_DIGITS))) " " DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_DURATION_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_DURATION))) " " DOCOPT_OPTIONAL(DOCOPT_SWITCH(TOTP_CLI_COMMAND_ARG_UNSECURE_PREFIX)) " " DOCOPT_MULTIPLE(DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE)))) "\r\n"); + TOTP_CLI_COMMAND_ARG_DURATION))) " " DOCOPT_OPTIONAL(DOCOPT_SWITCH(TOTP_CLI_COMMAND_ARG_UNSECURE_PREFIX)) " " DOCOPT_OPTIONAL(DOCOPT_SWITCH(TOTP_CLI_COMMAND_UPDATE_ARG_SECRET_PREFIX)) " " DOCOPT_MULTIPLE(DOCOPT_OPTIONAL(DOCOPT_OPTION(TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE)))) "\r\n"); } void totp_cli_command_update_docopt_options() { TOTP_CLI_PRINTF(" " DOCOPT_OPTION( TOTP_CLI_COMMAND_ARG_NAME_PREFIX, DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ARG_NAME)) " Token name\r\n"); + + TOTP_CLI_PRINTF(" " DOCOPT_SWITCH( + TOTP_CLI_COMMAND_UPDATE_ARG_SECRET_PREFIX) " Update token secret\r\n"); } static bool @@ -85,6 +88,7 @@ void totp_cli_command_update_handle(PluginState* plugin_state, FuriString* args, // Read optional arguments bool mask_user_input = true; bool update_token_secret = false; + PlainTokenSecretEncoding token_secret_encoding = PLAIN_TOKEN_ENCODING_BASE32; while(args_read_string_and_trim(args, temp_str)) { bool parsed = false; if(!totp_cli_try_read_name(token_info, temp_str, args, &parsed) && @@ -93,7 +97,9 @@ void totp_cli_command_update_handle(PluginState* plugin_state, FuriString* args, !totp_cli_try_read_duration(token_info, temp_str, args, &parsed) && !totp_cli_try_read_unsecure_flag(temp_str, &parsed, &mask_user_input) && !totp_cli_try_read_change_secret_flag(temp_str, &parsed, &update_token_secret) && - !totp_cli_try_read_automation_features(token_info, temp_str, args, &parsed)) { + !totp_cli_try_read_automation_features(token_info, temp_str, args, &parsed) && + !totp_cli_try_read_plain_token_secret_encoding( + temp_str, args, &parsed, &token_secret_encoding)) { totp_cli_printf_unknown_argument(temp_str); } @@ -105,54 +111,55 @@ void totp_cli_command_update_handle(PluginState* plugin_state, FuriString* args, } } + bool token_secret_read = false; if(update_token_secret) { // Reading token secret furi_string_reset(temp_str); TOTP_CLI_PRINTF("Enter token secret and confirm with [ENTER]\r\n"); - if(!totp_cli_read_line(cli, temp_str, mask_user_input) || - !totp_cli_ensure_authenticated(plugin_state, cli)) { - TOTP_CLI_DELETE_LAST_LINE(); + token_secret_read = totp_cli_read_line(cli, temp_str, mask_user_input); + TOTP_CLI_DELETE_LAST_LINE(); + if(!token_secret_read) { TOTP_CLI_PRINTF_INFO("Cancelled by user\r\n"); - furi_string_secure_free(temp_str); - token_info_free(token_info); - return; } + } - TOTP_CLI_DELETE_LAST_LINE(); + bool load_generate_token_scene = false; + if(plugin_state->current_scene == TotpSceneGenerateToken) { + totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL); + load_generate_token_scene = true; + } + bool token_secret_set = false; + if(update_token_secret && token_secret_read) { if(token_info->token != NULL) { free(token_info->token); } - - if(!token_info_set_secret( - token_info, - furi_string_get_cstr(temp_str), - furi_string_size(temp_str), - plugin_state->iv)) { + token_secret_set = token_info_set_secret( + token_info, + furi_string_get_cstr(temp_str), + furi_string_size(temp_str), + token_secret_encoding, + plugin_state->iv); + if(!token_secret_set) { TOTP_CLI_PRINTF_ERROR("Token secret seems to be invalid and can not be parsed\r\n"); - furi_string_secure_free(temp_str); - token_info_free(token_info); - return; } } furi_string_secure_free(temp_str); - bool load_generate_token_scene = false; - if(plugin_state->current_scene == TotpSceneGenerateToken) { - totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL); - load_generate_token_scene = true; - } - - list_item->data = token_info; + if(!update_token_secret || (token_secret_read && token_secret_set)) { + list_item->data = token_info; - if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) { - TOTP_CLI_PRINTF_SUCCESS( - "Token \"%s\" has been successfully updated\r\n", token_info->name); - token_info_free(existing_token_info); + if(totp_full_save_config_file(plugin_state) == TotpConfigFileUpdateSuccess) { + TOTP_CLI_PRINTF_SUCCESS( + "Token \"%s\" has been successfully updated\r\n", token_info->name); + token_info_free(existing_token_info); + } else { + TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE(); + list_item->data = existing_token_info; + token_info_free(token_info); + } } else { - TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE(); - list_item->data = existing_token_info; token_info_free(token_info); } diff --git a/cli/common_command_arguments.c b/cli/common_command_arguments.c index 0ef121add9a..9ed9f0126b9 100644 --- a/cli/common_command_arguments.c +++ b/cli/common_command_arguments.c @@ -108,5 +108,34 @@ bool totp_cli_try_read_unsecure_flag(const FuriString* arg, bool* parsed, bool* return true; } + return false; +} + +bool totp_cli_try_read_plain_token_secret_encoding( + FuriString* arg, + FuriString* args, + bool* parsed, + PlainTokenSecretEncoding* secret_encoding) { + if(furi_string_cmpi_str(arg, TOTP_CLI_COMMAND_ARG_SECRET_ENCODING_PREFIX) == 0) { + if(!args_read_string_and_trim(args, arg)) { + totp_cli_printf_missed_argument_value(TOTP_CLI_COMMAND_ARG_SECRET_ENCODING_PREFIX); + } else { + if(furi_string_cmpi_str(arg, PLAIN_TOKEN_ENCODING_BASE32_NAME) == 0) { + *secret_encoding = PLAIN_TOKEN_ENCODING_BASE32; + *parsed = true; + } else if(furi_string_cmpi_str(arg, PLAIN_TOKEN_ENCODING_BASE64_NAME) == 0) { + *secret_encoding = PLAIN_TOKEN_ENCODING_BASE64; + *parsed = true; + } else { + TOTP_CLI_PRINTF_ERROR( + "\"%s\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ARG_SECRET_ENCODING_PREFIX + "\"\r\n", + furi_string_get_cstr(arg)); + } + } + + return true; + } + return false; } \ No newline at end of file diff --git a/cli/common_command_arguments.h b/cli/common_command_arguments.h index 85413a321dd..be01c216d06 100644 --- a/cli/common_command_arguments.h +++ b/cli/common_command_arguments.h @@ -15,6 +15,8 @@ #define TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE_PREFIX "-b" #define TOTP_CLI_COMMAND_ARG_AUTOMATION_FEATURE "feature" #define TOTP_CLI_COMMAND_ARG_INDEX "index" +#define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING_PREFIX "-e" +#define TOTP_CLI_COMMAND_ARG_SECRET_ENCODING "encoding" void totp_cli_printf_unknown_argument(const FuriString* arg); void totp_cli_printf_missed_argument_value(char* arg); @@ -34,4 +36,10 @@ bool totp_cli_try_read_automation_features( FuriString* arg, FuriString* args, bool* parsed); -bool totp_cli_try_read_unsecure_flag(const FuriString* arg, bool* parsed, bool* unsecure_flag); \ No newline at end of file +bool totp_cli_try_read_unsecure_flag(const FuriString* arg, bool* parsed, bool* unsecure_flag); + +bool totp_cli_try_read_plain_token_secret_encoding( + FuriString* arg, + FuriString* args, + bool* parsed, + PlainTokenSecretEncoding* secret_encoding); \ No newline at end of file diff --git a/lib/base32/base32.c b/lib/base32/base32.c index 9781c831fd6..827aa1e9419 100644 --- a/lib/base32/base32.c +++ b/lib/base32/base32.c @@ -17,10 +17,10 @@ #include "base32.h" -int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize) { +size_t base32_decode(const uint8_t* encoded, uint8_t* result, size_t bufSize) { int buffer = 0; int bitsLeft = 0; - int count = 0; + size_t count = 0; for(const uint8_t* ptr = encoded; count < bufSize && *ptr; ++ptr) { uint8_t ch = *ptr; if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-') { @@ -43,7 +43,7 @@ int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize) { } else if(ch >= '2' && ch <= '7') { ch -= '2' - 26; } else { - return -1; + return 0; } buffer |= ch; diff --git a/lib/base32/base32.h b/lib/base32/base32.h index dea1a1c8197..8cb9bddcb71 100644 --- a/lib/base32/base32.h +++ b/lib/base32/base32.h @@ -27,6 +27,7 @@ #pragma once +#include #include /** @@ -34,6 +35,6 @@ * @param encoded Base-32 encoded bytes * @param[out] result result output buffer * @param bufSize result output buffer size - * @return Decoded result length in bytes if successfully decoded; \c -1 otherwise + * @return Decoded result length in bytes if successfully decoded; \c 0 otherwise */ -int base32_decode(const uint8_t* encoded, uint8_t* result, int bufSize); +size_t base32_decode(const uint8_t* encoded, uint8_t* result, size_t bufSize); diff --git a/lib/base64/base64.c b/lib/base64/base64.c new file mode 100644 index 00000000000..1dfcf8814af --- /dev/null +++ b/lib/base64/base64.c @@ -0,0 +1,72 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + */ + +#include "base64.h" +#include + +static const uint8_t dtable[] = {0x3e, 0x80, 0x80, 0x80, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x80, 0x80, 0x80, 0x0, 0x80, + 0x80, 0x80, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33}; +// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static uint8_t get_dtable_value(uint8_t index) { + return (index < 43 || index > 122) ? 0x80 : dtable[index - 43]; +} + +uint8_t* base64_decode(const uint8_t* src, size_t len, size_t* out_len, size_t* out_size) { + uint8_t *out; + uint8_t *pos; + uint8_t in[4]; + uint8_t block[4]; + uint8_t tmp; + size_t i; + size_t count; + size_t olen; + + count = 0; + for(i = 0; i < len; i++) { + if(get_dtable_value(src[i]) != 0x80) count++; + } + + if(count == 0 || count % 4) return NULL; + olen = count / 4 * 3; + pos = out = malloc(olen); + *out_size = olen; + if(out == NULL) return NULL; + count = 0; + for(i = 0; i < len; i++) { + tmp = get_dtable_value(src[i]); + if(tmp == 0x80) continue; + in[count] = src[i]; + block[count] = tmp; + count++; + if(count == 4) { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + } + } + if(pos > out) { + if(in[2] == '=') + pos -= 2; + else if(in[3] == '=') + pos--; + } + *out_len = pos - out; + return out; +} \ No newline at end of file diff --git a/lib/base64/base64.h b/lib/base64/base64.h new file mode 100644 index 00000000000..059ec5a9099 --- /dev/null +++ b/lib/base64/base64.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +/** + * @brief Decodes Base-64 encoded bytes into plain bytes. + * @param src Base-64 encoded bytes + * @param len Base-64 encoded bytes count + * @param[out] out_len decoded buffer length + * @param[out] out_size decoded buffer allocated size + * @return Decoded result buffer if successfully decoded; \c NULL otherwise + */ +uint8_t* base64_decode(const uint8_t* src, size_t len, size_t* out_len, size_t* out_size); \ No newline at end of file diff --git a/lib/list/list.c b/lib/linked_list/linked_list.c similarity index 99% rename from lib/list/list.c rename to lib/linked_list/linked_list.c index f7abb6c8ef9..23d10c548fb 100644 --- a/lib/list/list.c +++ b/lib/linked_list/linked_list.c @@ -1,4 +1,4 @@ -#include "list.h" +#include "linked_list.h" ListNode* list_init_head(void* data) { ListNode* new = malloc(sizeof(ListNode)); diff --git a/lib/list/list.h b/lib/linked_list/linked_list.h similarity index 79% rename from lib/list/list.h rename to lib/linked_list/linked_list.h index c52d4c25a2f..3c938e59a08 100644 --- a/lib/list/list.h +++ b/lib/linked_list/linked_list.h @@ -84,19 +84,15 @@ ListNode* list_insert_at(ListNode* head, uint16_t index, void* data); void list_free(ListNode* head); #define TOTP_LIST_INIT_OR_ADD(head, item, assert) \ - do { \ - if(head == NULL) { \ - head = list_init_head(item); \ - assert(head != NULL); \ - } else { \ - assert(list_add(head, item) != NULL); \ - } \ - } while(false) + if(head == NULL) { \ + head = list_init_head(item); \ + assert(head != NULL); \ + } else { \ + assert(list_add(head, item) != NULL); \ + } #define TOTP_LIST_FOREACH(head, node, action) \ - do { \ - ListNode* node = head; \ - while(node != NULL) { \ - action node = node->next; \ - } \ - } while(false) + ListNode* node = head; \ + while(node != NULL) { \ + action node = node->next; \ + } diff --git a/services/config/config.c b/services/config/config.c index 52065ad32d0..adc85cbe59f 100644 --- a/services/config/config.c +++ b/services/config/config.c @@ -1,7 +1,7 @@ #include "config.h" #include #include -#include "../list/list.h" +#include #include "../../types/common.h" #include "../../types/token_info.h" #include "../../features_config.h" @@ -139,10 +139,11 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF furi_string_printf( temp_str, - " # Token hashing algorithm to use during code generation. Supported options are %s, %s and %s. If you are not use which one to use - use %s", + " # Token hashing algorithm to use during code generation. Supported options are %s, %s, %s, and %s. If you are not use which one to use - use %s", TOTP_TOKEN_ALGO_SHA1_NAME, TOTP_TOKEN_ALGO_SHA256_NAME, TOTP_TOKEN_ALGO_SHA512_NAME, + TOTP_TOKEN_ALGO_STEAM_NAME, TOTP_TOKEN_ALGO_SHA1_NAME); flipper_format_write_comment(fff_data_file, temp_str); furi_string_printf( @@ -152,7 +153,7 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF flipper_format_write_comment_cstr( fff_data_file, - "# How many digits there should be in generated code. Available options are 6 and 8. Majority websites requires 6 digits code, however some rare websites wants to get 8 digits code. If you are not sure which one to use - use 6"); + "# How many digits there should be in generated code. Available options are 5, 6 and 8. Majority websites requires 6 digits code, however some rare websites wants to get 8 digits code. If you are not sure which one to use - use 6"); furi_string_printf(temp_str, "%s: 6", TOTP_CONFIG_KEY_TOKEN_DIGITS); flipper_format_write_comment(fff_data_file, temp_str); flipper_format_write_comment_cstr(fff_data_file, " "); @@ -686,6 +687,7 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state) tokenInfo, furi_string_get_cstr(temp_str), furi_string_size(temp_str), + PLAIN_TOKEN_ENCODING_BASE32, &plugin_state->iv[0])) { FURI_LOG_W(LOGGING_TAG, "Token \"%s\" has plain secret", tokenInfo->name); } else { diff --git a/services/hmac/sha512.c b/services/hmac/sha512.c index f04c4d593b4..b56dd0f2eba 100644 --- a/services/hmac/sha512.c +++ b/services/hmac/sha512.c @@ -26,12 +26,9 @@ #include #include -#ifdef WORDS_BIGENDIAN -#define SWAP(n) (n) -#else #include "byteswap.h" + #define SWAP(n) swap_uint64(n) -#endif /* This array contains the bytes used to pad the buffer to the next 128-byte boundary. */ diff --git a/services/totp/totp.c b/services/totp/totp.c index 1a20d58c139..f6e0401e6ad 100644 --- a/services/totp/totp.c +++ b/services/totp/totp.c @@ -11,7 +11,7 @@ #include "../hmac/byteswap.h" #include "../../lib/timezone_utils/timezone_utils.h" -#define HMAC_MAX_SIZE 64 +#define HMAC_MAX_RESULT_SIZE HMAC_SHA512_RESULT_SIZE /** * @brief Generates the timeblock for a time in seconds. @@ -29,19 +29,17 @@ uint64_t totp_timecode(uint8_t interval, uint64_t for_time) { /** * @brief Generates an OTP (One Time Password) * @param algo hashing algorithm to be used - * @param digits desired TOTP code length * @param plain_secret plain token secret * @param plain_secret_length plain token secret length * @param input input data for OTP code generation * @return OTP code if code was successfully generated; 0 otherwise */ -uint32_t otp_generate( +uint64_t otp_generate( TOTP_ALGO algo, - uint8_t digits, const uint8_t* plain_secret, size_t plain_secret_length, uint64_t input) { - uint8_t hmac[HMAC_MAX_SIZE] = {0}; + uint8_t hmac[HMAC_MAX_RESULT_SIZE] = {0}; uint64_t input_swapped = swap_uint64(input); @@ -55,14 +53,12 @@ uint32_t otp_generate( uint64_t i_code = ((hmac[offset] & 0x7F) << 24 | (hmac[offset + 1] & 0xFF) << 16 | (hmac[offset + 2] & 0xFF) << 8 | (hmac[offset + 3] & 0xFF)); - i_code %= (uint64_t)pow(10, digits); return i_code; } -uint32_t totp_at( +uint64_t totp_at( TOTP_ALGO algo, - uint8_t digits, const uint8_t* plain_secret, size_t plain_secret_length, uint64_t for_time, @@ -71,11 +67,7 @@ uint32_t totp_at( uint64_t for_time_adjusted = timezone_offset_apply(for_time, timezone_offset_from_hours(timezone)); return otp_generate( - algo, - digits, - plain_secret, - plain_secret_length, - totp_timecode(interval, for_time_adjusted)); + algo, plain_secret, plain_secret_length, totp_timecode(interval, for_time_adjusted)); } static int totp_algo_sha1( diff --git a/services/totp/totp.h b/services/totp/totp.h index 3f45a022370..d578f6ea99d 100644 --- a/services/totp/totp.h +++ b/services/totp/totp.h @@ -39,7 +39,6 @@ extern const TOTP_ALGO TOTP_ALGO_SHA512; /** * @brief Generates a OTP key using the totp algorithm. * @param algo hashing algorithm to be used - * @param digits desired TOTP code length * @param plain_secret plain token secret * @param plain_secret_length plain token secret length * @param for_time the time the generated key will be created for @@ -47,9 +46,8 @@ extern const TOTP_ALGO TOTP_ALGO_SHA512; * @param interval token lifetime in seconds * @return TOTP code if code was successfully generated; 0 otherwise */ -uint32_t totp_at( +uint64_t totp_at( TOTP_ALGO algo, - uint8_t digits, const uint8_t* plain_secret, size_t plain_secret_length, uint64_t for_time, diff --git a/types/plugin_state.h b/types/plugin_state.h index 59a218ce3b7..b1d34a662fc 100644 --- a/types/plugin_state.h +++ b/types/plugin_state.h @@ -4,7 +4,7 @@ #include #include #include "../features_config.h" -#include "../lib/list/list.h" +#include #include "../ui/totp_scenes_enum.h" #include "notification_method.h" #include "automation_method.h" diff --git a/types/token_info.c b/types/token_info.c index fd9699ecf0d..b8196c56b07 100644 --- a/types/token_info.c +++ b/types/token_info.c @@ -1,11 +1,11 @@ -#include #include "token_info.h" -#include "stdlib.h" +#include +#include +#include +#include +#include #include "common.h" -#include "../lib/base32/base32.h" #include "../services/crypto/crypto.h" -#include "../lib/polyfills/memset_s.h" -#include "../lib/polyfills/strnlen.h" TokenInfo* token_info_alloc() { TokenInfo* tokenInfo = malloc(sizeof(TokenInfo)); @@ -26,15 +26,32 @@ void token_info_free(TokenInfo* token_info) { bool token_info_set_secret( TokenInfo* token_info, - const char* base32_token_secret, + const char* plain_token_secret, size_t token_secret_length, + PlainTokenSecretEncoding plain_token_secret_encoding, const uint8_t* iv) { if(token_secret_length == 0) return false; + uint8_t* plain_secret; + size_t plain_secret_length; + size_t plain_secret_size; + if(plain_token_secret_encoding == PLAIN_TOKEN_ENCODING_BASE32) { + plain_secret_size = token_secret_length; + plain_secret = malloc(plain_secret_size); + furi_check(plain_secret != NULL); + plain_secret_length = + base32_decode((const uint8_t*)plain_token_secret, plain_secret, plain_secret_size); + } else if(plain_token_secret_encoding == PLAIN_TOKEN_ENCODING_BASE64) { + plain_secret_length = 0; + plain_secret = base64_decode( + (const uint8_t*)plain_token_secret, + token_secret_length, + &plain_secret_length, + &plain_secret_size); + furi_check(plain_secret != NULL); + } else { + return false; + } - uint8_t* plain_secret = malloc(token_secret_length); - furi_check(plain_secret != NULL); - int plain_secret_length = - base32_decode((const uint8_t*)base32_token_secret, plain_secret, token_secret_length); bool result; if(plain_secret_length > 0) { token_info->token = @@ -44,13 +61,16 @@ bool token_info_set_secret( result = false; } - memset_s(plain_secret, token_secret_length, 0, token_secret_length); + memset_s(plain_secret, plain_secret_size, 0, plain_secret_size); free(plain_secret); return result; } bool token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits) { switch(digits) { + case 5: + token_info->digits = TOTP_5_DIGITS; + return true; case 6: token_info->digits = TOTP_6_DIGITS; return true; @@ -89,6 +109,11 @@ bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str) return true; } + if(furi_string_cmpi_str(str, TOTP_TOKEN_ALGO_STEAM_NAME) == 0) { + token_info->algo = STEAM; + return true; + } + return false; } @@ -100,6 +125,8 @@ char* token_info_get_algo_as_cstr(const TokenInfo* token_info) { return TOTP_TOKEN_ALGO_SHA256_NAME; case SHA512: return TOTP_TOKEN_ALGO_SHA512_NAME; + case STEAM: + return TOTP_TOKEN_ALGO_STEAM_NAME; default: break; } diff --git a/types/token_info.h b/types/token_info.h index fea0c09d72a..688e8028d8b 100644 --- a/types/token_info.h +++ b/types/token_info.h @@ -7,10 +7,14 @@ #define TOTP_TOKEN_DURATION_DEFAULT 30 #define TOTP_TOKEN_ALGO_SHA1_NAME "sha1" +#define TOTP_TOKEN_ALGO_STEAM_NAME "steam" #define TOTP_TOKEN_ALGO_SHA256_NAME "sha256" #define TOTP_TOKEN_ALGO_SHA512_NAME "sha512" #define TOTP_TOKEN_MAX_LENGTH 255 +#define PLAIN_TOKEN_ENCODING_BASE32_NAME "base32" +#define PLAIN_TOKEN_ENCODING_BASE64_NAME "base64" + #define TOTP_TOKEN_AUTOMATION_FEATURE_NONE_NAME "none" #define TOTP_TOKEN_AUTOMATION_FEATURE_ENTER_AT_THE_END_NAME "enter" #define TOTP_TOKEN_AUTOMATION_FEATURE_TAB_AT_THE_END_NAME "tab" @@ -19,6 +23,7 @@ typedef uint8_t TokenHashAlgo; typedef uint8_t TokenDigitsCount; typedef uint8_t TokenAutomationFeature; +typedef uint8_t PlainTokenSecretEncoding; /** * @brief Hashing algorithm to be used to generate token @@ -37,13 +42,23 @@ enum TokenHashAlgos { /** * @brief SHA512 hashing algorithm */ - SHA512 + SHA512, + + /** + * @brief Algorithm used by Steam (Valve) + */ + STEAM }; /** * @brief Token digits count to be generated. */ enum TokenDigitsCounts { + /** + * @brief 6 digits + */ + TOTP_5_DIGITS = 5, + /** * @brief 6 digits */ @@ -80,6 +95,11 @@ enum TokenAutomationFeatures { TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER = 0b100 }; +enum PlainTokenSecretEncodings { + PLAIN_TOKEN_ENCODING_BASE32 = 0, + PLAIN_TOKEN_ENCODING_BASE64 = 1 +}; + #define TOTP_TOKEN_DIGITS_MAX_COUNT 8 /** @@ -139,13 +159,15 @@ void token_info_free(TokenInfo* token_info); * @param token_info instance where secret should be updated * @param base32_token_secret plain token secret in Base32 format * @param token_secret_length plain token secret length + * @param plain_token_secret_encoding plain token secret encoding * @param iv initialization vecor (IV) to be used for encryption * @return \c true if token successfully set; \c false otherwise */ bool token_info_set_secret( TokenInfo* token_info, - const char* base32_token_secret, + const char* plain_token_secret, size_t token_secret_length, + PlainTokenSecretEncoding plain_token_secret_encoding, const uint8_t* iv); /** diff --git a/ui/fonts/font-info.h b/ui/fonts/font-info.h new file mode 100644 index 00000000000..86c131ec9b8 --- /dev/null +++ b/ui/fonts/font-info.h @@ -0,0 +1,24 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include + +// This structure describes a single character's display information +typedef struct { + const uint8_t width; // width, in bits (or pixels), of the character + const uint16_t + offset; // offset of the character's bitmap, in bytes, into the the FONT_INFO's data array + +} FONT_CHAR_INFO; + +// Describes a single font +typedef struct { + const uint8_t height; // height, in pages (8 pixels), of the font's characters + const uint8_t startChar; // the first character in the font (e.g. in charInfo and data) + const uint8_t endChar; // the last character in the font + const uint8_t spacePixels; // number of pixels that a space character takes up + const FONT_CHAR_INFO* charInfo; // pointer to array of char information + const uint8_t* data; // pointer to generated array of character visual representation + +} FONT_INFO; \ No newline at end of file diff --git a/ui/fonts/mode-nine/mode-nine.c b/ui/fonts/mode-nine/mode-nine.c new file mode 100644 index 00000000000..ab0e860ef77 --- /dev/null +++ b/ui/fonts/mode-nine/mode-nine.c @@ -0,0 +1,940 @@ +#include "mode-nine.h" + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +/* +** Font data for ModeNine 15pt +*/ + +/* Character bitmaps for ModeNine 15pt */ +const uint8_t modeNine_15ptBitmaps[] = { + /* @0 '-' (10 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @28 '0' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFE, + 0x01, + 0x87, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x87, + 0x03, + 0xFE, + 0x01, + 0xFC, + 0x00, + + /* @56 '1' (10 pixels wide) */ + 0x30, + 0x00, + 0x38, + 0x00, + 0x3C, + 0x00, + 0x3C, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0xFC, + 0x00, + 0xFC, + 0x00, + + /* @84 '2' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFE, + 0x01, + 0x87, + 0x03, + 0x03, + 0x03, + 0x00, + 0x03, + 0x80, + 0x03, + 0xFC, + 0x01, + 0xFE, + 0x00, + 0x07, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0xFF, + 0x03, + 0xFF, + 0x03, + + /* @112 '3' (10 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x80, + 0x03, + 0xC0, + 0x01, + 0xE0, + 0x00, + 0x70, + 0x00, + 0xF8, + 0x00, + 0xFC, + 0x01, + 0x80, + 0x03, + 0x00, + 0x03, + 0x03, + 0x03, + 0x87, + 0x03, + 0xFE, + 0x01, + 0xFC, + 0x00, + + /* @140 '4' (10 pixels wide) */ + 0xE0, + 0x00, + 0xF0, + 0x00, + 0xF8, + 0x00, + 0xDC, + 0x00, + 0xCE, + 0x00, + 0xC7, + 0x00, + 0xC3, + 0x00, + 0xC3, + 0x00, + 0xFF, + 0x03, + 0xFF, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + + /* @168 '5' (10 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x03, + 0x00, + 0x03, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x01, + 0x80, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x03, + 0x03, + 0x87, + 0x03, + 0xFE, + 0x01, + 0xFC, + 0x00, + + /* @196 '6' (10 pixels wide) */ + 0xF0, + 0x00, + 0xFC, + 0x00, + 0x0E, + 0x00, + 0x06, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x01, + 0x83, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x87, + 0x03, + 0xFE, + 0x01, + 0xFC, + 0x00, + + /* @224 '7' (10 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x00, + 0x03, + 0x80, + 0x01, + 0xC0, + 0x01, + 0xE0, + 0x00, + 0x30, + 0x00, + 0x18, + 0x00, + 0x1C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + + /* @252 '8' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFE, + 0x01, + 0x87, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x87, + 0x03, + 0xFE, + 0x01, + 0xFE, + 0x01, + 0x87, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x87, + 0x03, + 0xFE, + 0x01, + 0xFC, + 0x00, + + /* @280 '9' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFE, + 0x01, + 0x87, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x07, + 0x03, + 0xFE, + 0x03, + 0xFC, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x80, + 0x01, + 0xC0, + 0x01, + 0xFC, + 0x00, + 0x3C, + 0x00, + + /* @308 'B' (10 pixels wide) */ + 0xFF, + 0x00, + 0xFF, + 0x01, + 0x83, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x83, + 0x03, + 0xFF, + 0x01, + 0xFF, + 0x01, + 0x83, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x83, + 0x03, + 0xFF, + 0x01, + 0xFF, + 0x00, + + /* @336 'C' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFE, + 0x01, + 0x87, + 0x03, + 0x03, + 0x03, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x03, + 0x87, + 0x03, + 0xFE, + 0x01, + 0xFC, + 0x00, + + /* @364 'D' (10 pixels wide) */ + 0xFF, + 0x00, + 0xFF, + 0x01, + 0x83, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x83, + 0x03, + 0xFF, + 0x01, + 0xFF, + 0x00, + + /* @392 'F' (10 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + + /* @420 'G' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFE, + 0x01, + 0x87, + 0x03, + 0x03, + 0x03, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0xC3, + 0x03, + 0xC3, + 0x03, + 0x03, + 0x03, + 0x07, + 0x03, + 0xFE, + 0x03, + 0xFC, + 0x03, + + /* @448 'H' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + + /* @476 'J' (10 pixels wide) */ + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x03, + 0x03, + 0x87, + 0x03, + 0xFE, + 0x01, + 0xFC, + 0x00, + + /* @504 'K' (10 pixels wide) */ + 0x83, + 0x03, + 0xC3, + 0x01, + 0xE3, + 0x00, + 0x73, + 0x00, + 0x3B, + 0x00, + 0x1F, + 0x00, + 0x0F, + 0x00, + 0x0F, + 0x00, + 0x1F, + 0x00, + 0x3B, + 0x00, + 0x73, + 0x00, + 0xE3, + 0x00, + 0xC3, + 0x01, + 0x83, + 0x03, + + /* @532 'M' (10 pixels wide) */ + 0x03, + 0x03, + 0x87, + 0x03, + 0xCF, + 0x03, + 0xFF, + 0x03, + 0x7B, + 0x03, + 0x33, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + + /* @560 'N' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x07, + 0x03, + 0x0F, + 0x03, + 0x1F, + 0x03, + 0x3B, + 0x03, + 0x73, + 0x03, + 0xE3, + 0x03, + 0xC3, + 0x03, + 0x83, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + + /* @588 'P' (10 pixels wide) */ + 0xFF, + 0x00, + 0xFF, + 0x01, + 0x83, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x83, + 0x03, + 0xFF, + 0x01, + 0xFF, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + + /* @616 'Q' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFE, + 0x01, + 0x87, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x33, + 0x03, + 0x73, + 0x03, + 0xE7, + 0x03, + 0xFE, + 0x01, + 0xFC, + 0x03, + + /* @644 'R' (10 pixels wide) */ + 0xFF, + 0x00, + 0xFF, + 0x01, + 0x83, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x83, + 0x03, + 0xFF, + 0x01, + 0xFF, + 0x00, + 0x1F, + 0x00, + 0x3B, + 0x00, + 0x73, + 0x00, + 0xE3, + 0x00, + 0xC3, + 0x01, + 0x83, + 0x03, + + /* @672 'T' (10 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + + /* @700 'V' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x86, + 0x01, + 0x86, + 0x01, + 0xCC, + 0x00, + 0xCC, + 0x00, + 0x78, + 0x00, + 0x78, + 0x00, + 0x30, + 0x00, + + /* @728 'W' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0xFF, + 0x03, + 0xFE, + 0x01, + + /* @756 'X' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x87, + 0x03, + 0xCE, + 0x01, + 0xFC, + 0x00, + 0xFC, + 0x00, + 0xCE, + 0x01, + 0x87, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + + /* @784 'Y' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x87, + 0x03, + 0xCE, + 0x01, + 0xFC, + 0x00, + 0x78, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, +}; + +/* Character descriptors for ModeNine 15pt */ +/* { [Char width in bits], [Offset into modeNine_15ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO modeNine_15ptDescriptors[] = { + {10, 0}, /* - */ + {0, 0}, /* . */ + {0, 0}, /* / */ + {10, 28}, /* 0 */ + {10, 56}, /* 1 */ + {10, 84}, /* 2 */ + {10, 112}, /* 3 */ + {10, 140}, /* 4 */ + {10, 168}, /* 5 */ + {10, 196}, /* 6 */ + {10, 224}, /* 7 */ + {10, 252}, /* 8 */ + {10, 280}, /* 9 */ + {0, 0}, /* : */ + {0, 0}, /* ; */ + {0, 0}, /* < */ + {0, 0}, /* = */ + {0, 0}, /* > */ + {0, 0}, /* ? */ + {0, 0}, /* @ */ + {0, 0}, /* A */ + {10, 308}, /* B */ + {10, 336}, /* C */ + {10, 364}, /* D */ + {0, 0}, /* E */ + {10, 392}, /* F */ + {10, 420}, /* G */ + {10, 448}, /* H */ + {0, 0}, /* I */ + {10, 476}, /* J */ + {10, 504}, /* K */ + {0, 0}, /* L */ + {10, 532}, /* M */ + {10, 560}, /* N */ + {0, 0}, /* O */ + {10, 588}, /* P */ + {10, 616}, /* Q */ + {10, 644}, /* R */ + {0, 0}, /* S */ + {10, 672}, /* T */ + {0, 0}, /* U */ + {10, 700}, /* V */ + {10, 728}, /* W */ + {10, 756}, /* X */ + {10, 784}, /* Y */ +}; + +/* Font information for ModeNine 15pt */ +const FONT_INFO modeNine_15ptFontInfo = { + 14, /* Character height */ + '-', /* Start character */ + 'Y', /* End character */ + 2, /* Width, in pixels, of space character */ + modeNine_15ptDescriptors, /* Character descriptor array */ + modeNine_15ptBitmaps, /* Character bitmap array */ +}; diff --git a/ui/fonts/mode-nine/mode-nine.h b/ui/fonts/mode-nine/mode-nine.h new file mode 100644 index 00000000000..e5e4be35a6f --- /dev/null +++ b/ui/fonts/mode-nine/mode-nine.h @@ -0,0 +1,9 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include "../font-info.h" +#include + +/* Font data for ModeNine 15pt */ +extern const FONT_INFO modeNine_15ptFontInfo; diff --git a/ui/scenes/add_new_token/totp_scene_add_new_token.c b/ui/scenes/add_new_token/totp_scene_add_new_token.c index f35f0238bca..997ba65c1a8 100644 --- a/ui/scenes/add_new_token/totp_scene_add_new_token.c +++ b/ui/scenes/add_new_token/totp_scene_add_new_token.c @@ -4,17 +4,17 @@ #include "../../scene_director.h" #include "totp_input_text.h" #include "../../../types/token_info.h" -#include "../../../lib/list/list.h" +#include #include "../../../services/config/config.h" #include "../../ui_controls.h" #include "../../common_dialogs.h" -#include "../../../lib/roll_value/roll_value.h" +#include #include "../../../types/nullable.h" #include "../generate_token/totp_scene_generate_token.h" char* TOKEN_ALGO_LIST[] = {"SHA1", "SHA256", "SHA512"}; -char* TOKEN_DIGITS_TEXT_LIST[] = {"6 digits", "8 digits"}; -TokenDigitsCount TOKEN_DIGITS_VALUE_LIST[] = {TOTP_6_DIGITS, TOTP_8_DIGITS}; +char* TOKEN_DIGITS_TEXT_LIST[] = {"5 digits", "6 digits", "8 digits"}; +TokenDigitsCount TOKEN_DIGITS_VALUE_LIST[] = {TOTP_5_DIGITS, TOTP_6_DIGITS, TOTP_8_DIGITS}; typedef enum { TokenNameTextBox, @@ -95,6 +95,8 @@ void totp_scene_add_new_token_activate( scene_state->screen_y_offset = 0; + scene_state->digits_count_index = 1; + scene_state->input_state = NULL; scene_state->duration = TOTP_TOKEN_DURATION_DEFAULT; scene_state->duration_text = furi_string_alloc(); @@ -219,7 +221,7 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState totp_roll_value_uint8_t(&scene_state->algo, 1, SHA1, SHA512, RollOverflowBehaviorRoll); } else if(scene_state->selected_control == TokenLengthSelect) { totp_roll_value_uint8_t( - &scene_state->digits_count_index, 1, 0, 1, RollOverflowBehaviorRoll); + &scene_state->digits_count_index, 1, 0, 2, RollOverflowBehaviorRoll); } else if(scene_state->selected_control == TokenDurationSelect) { totp_roll_value_uint8_t(&scene_state->duration, 15, 15, 255, RollOverflowBehaviorStop); update_duration_text(scene_state); @@ -231,7 +233,7 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState &scene_state->algo, -1, SHA1, SHA512, RollOverflowBehaviorRoll); } else if(scene_state->selected_control == TokenLengthSelect) { totp_roll_value_uint8_t( - &scene_state->digits_count_index, -1, 0, 1, RollOverflowBehaviorRoll); + &scene_state->digits_count_index, -1, 0, 2, RollOverflowBehaviorRoll); } else if(scene_state->selected_control == TokenDurationSelect) { totp_roll_value_uint8_t( &scene_state->duration, -15, 15, 255, RollOverflowBehaviorStop); @@ -268,6 +270,7 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState tokenInfo, scene_state->token_secret, scene_state->token_secret_length, + PLAIN_TOKEN_ENCODING_BASE32, &plugin_state->iv[0]); if(token_secret_set) { diff --git a/ui/scenes/app_settings/totp_app_settings.c b/ui/scenes/app_settings/totp_app_settings.c index 1671542b87f..93fd3d91573 100644 --- a/ui/scenes/app_settings/totp_app_settings.c +++ b/ui/scenes/app_settings/totp_app_settings.c @@ -8,7 +8,7 @@ #include "../../constants.h" #include "../../../services/config/config.h" #include "../../../services/convert/convert.h" -#include "../../../lib/roll_value/roll_value.h" +#include #include "../../../types/nullable.h" #include "../../../features_config.h" #ifdef TOTP_BADBT_TYPE_ENABLED diff --git a/ui/scenes/generate_token/totp_scene_generate_token.c b/ui/scenes/generate_token/totp_scene_generate_token.c index d3b27fdc707..1fab7be7f3e 100644 --- a/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/ui/scenes/generate_token/totp_scene_generate_token.c @@ -19,7 +19,9 @@ #ifdef TOTP_BADBT_TYPE_ENABLED #include "../../../workers/bt_type_code/bt_type_code.h" #endif +#include "../../fonts/mode-nine/mode-nine.h" +static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY"; static const uint8_t PROGRESS_BAR_MARGIN = 3; static const uint8_t PROGRESS_BAR_HEIGHT = 4; @@ -121,13 +123,21 @@ static const NotificationSequence* return (NotificationSequence*)scene_state->notification_sequence_badusb; } -static void int_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) { +static void + int_token_to_str(uint64_t i_token_code, char* str, TokenDigitsCount len, TokenHashAlgo algo) { if(i_token_code == OTP_ERROR) { memset(&str[0], '-', len); } else { - for(int i = len - 1; i >= 0; i--) { - str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10); - i_token_code = i_token_code / 10; + if(algo == STEAM) { + for(uint8_t i = 0; i < len; i++) { + str[i] = STEAM_ALGO_ALPHABET[i_token_code % 26]; + i_token_code = i_token_code / 26; + } + } else { + for(int8_t i = len - 1; i >= 0; i--) { + str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10); + i_token_code = i_token_code / 10; + } } } @@ -137,6 +147,7 @@ static void int_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount static TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) { switch(algo) { case SHA1: + case STEAM: return TOTP_ALGO_SHA1; case SHA256: return TOTP_ALGO_SHA256; @@ -161,6 +172,27 @@ static void update_totp_params(PluginState* const plugin_state) { } } +static void draw_totp_code(Canvas* const canvas, const SceneState* const scene_state) { + uint8_t code_length = scene_state->current_token->digits; + uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width; + uint8_t total_length = code_length * (char_width + modeNine_15ptFontInfo.spacePixels); + uint8_t offset_x = (SCREEN_WIDTH - total_length) >> 1; + uint8_t offset_y = SCREEN_HEIGHT_CENTER - (modeNine_15ptFontInfo.height >> 1); + for(uint8_t i = 0; i < code_length; i++) { + char ch = scene_state->last_code[i]; + uint8_t char_index = ch - modeNine_15ptFontInfo.startChar; + canvas_draw_xbm( + canvas, + offset_x, + offset_y, + char_width, + modeNine_15ptFontInfo.height, + &modeNine_15ptFontInfo.data[modeNine_15ptFontInfo.charInfo[char_index].offset]); + + offset_x += char_width + modeNine_15ptFontInfo.spacePixels; + } +} + void totp_scene_generate_token_init(const PluginState* plugin_state) { UNUSED(plugin_state); } @@ -274,19 +306,19 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ int_token_to_str( totp_at( get_totp_algo_impl(tokenInfo->algo), - tokenInfo->digits, key, key_length, curr_ts, plugin_state->timezone_offset, tokenInfo->duration), scene_state->last_code, - tokenInfo->digits); + tokenInfo->digits, + tokenInfo->algo); memset_s(key, key_length, 0, key_length); free(key); } else { furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever); - int_token_to_str(0, scene_state->last_code, tokenInfo->digits); + int_token_to_str(0, scene_state->last_code, tokenInfo->digits, tokenInfo->algo); } furi_mutex_release(scene_state->last_code_update_sync); @@ -322,14 +354,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ canvas_set_color(canvas, ColorBlack); } - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned( - canvas, - SCREEN_WIDTH_CENTER, - SCREEN_HEIGHT_CENTER, - AlignCenter, - AlignCenter, - scene_state->last_code); + draw_totp_code(canvas, scene_state); const uint8_t TOKEN_LIFETIME = scene_state->current_token->duration; float percentDone = (float)(TOKEN_LIFETIME - curr_ts % TOKEN_LIFETIME) / (float)TOKEN_LIFETIME; diff --git a/ui/scenes/token_menu/totp_scene_token_menu.c b/ui/scenes/token_menu/totp_scene_token_menu.c index 16776260202..6c6986c6592 100644 --- a/ui/scenes/token_menu/totp_scene_token_menu.c +++ b/ui/scenes/token_menu/totp_scene_token_menu.c @@ -6,13 +6,13 @@ #include "../../constants.h" #include "../../scene_director.h" #include "../../../services/config/config.h" -#include "../../../lib/list/list.h" +#include #include "../../../types/token_info.h" #include "../generate_token/totp_scene_generate_token.h" #include "../add_new_token/totp_scene_add_new_token.h" #include "../app_settings/totp_app_settings.h" #include "../../../types/nullable.h" -#include "../../../lib/roll_value/roll_value.h" +#include #define SCREEN_HEIGHT_THIRD (SCREEN_HEIGHT / 3) #define SCREEN_HEIGHT_THIRD_CENTER (SCREEN_HEIGHT_THIRD >> 1) diff --git a/workers/common.c b/workers/common.c index 5ca5d4fdf24..8ad0c2b46d9 100644 --- a/workers/common.c +++ b/workers/common.c @@ -3,17 +3,15 @@ #include #include "../../services/convert/convert.h" -static const uint8_t hid_number_keys[10] = { - HID_KEYBOARD_0, - HID_KEYBOARD_1, - HID_KEYBOARD_2, - HID_KEYBOARD_3, - HID_KEYBOARD_4, - HID_KEYBOARD_5, - HID_KEYBOARD_6, - HID_KEYBOARD_7, - HID_KEYBOARD_8, - HID_KEYBOARD_9}; +static const uint8_t hid_number_keys[] = { + HID_KEYBOARD_0, HID_KEYBOARD_1, HID_KEYBOARD_2, HID_KEYBOARD_3, HID_KEYBOARD_4, + HID_KEYBOARD_5, HID_KEYBOARD_6, HID_KEYBOARD_7, HID_KEYBOARD_8, HID_KEYBOARD_9, + HID_KEYBOARD_A, HID_KEYBOARD_B, HID_KEYBOARD_C, HID_KEYBOARD_D, HID_KEYBOARD_E, + HID_KEYBOARD_F, HID_KEYBOARD_G, HID_KEYBOARD_H, HID_KEYBOARD_I, HID_KEYBOARD_J, + HID_KEYBOARD_K, HID_KEYBOARD_L, HID_KEYBOARD_M, HID_KEYBOARD_N, HID_KEYBOARD_O, + HID_KEYBOARD_P, HID_KEYBOARD_Q, HID_KEYBOARD_R, HID_KEYBOARD_S, HID_KEYBOARD_T, + HID_KEYBOARD_U, HID_KEYBOARD_V, HID_KEYBOARD_W, HID_KEYBOARD_X, HID_KEYBOARD_Y, + HID_KEYBOARD_Z}; static uint32_t get_keystroke_delay(TokenAutomationFeature features) { if(features & TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER) { @@ -49,10 +47,18 @@ void totp_type_code_worker_execute_automation( TokenAutomationFeature features) { furi_delay_ms(500); uint8_t i = 0; + totp_type_code_worker_press_key( + HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features); + while(i < string_length && string[i] != 0) { - uint8_t digit = CONVERT_CHAR_TO_DIGIT(string[i]); - if(digit > 9) break; - uint8_t hid_kb_key = hid_number_keys[digit]; + uint8_t char_index = CONVERT_CHAR_TO_DIGIT(string[i]); + if(char_index > 9) { + char_index = string[i] - 0x41 + 10; + } + + if(char_index > 35) break; + + uint8_t hid_kb_key = hid_number_keys[char_index]; totp_type_code_worker_press_key(hid_kb_key, key_press_fn, key_release_fn, features); furi_delay_ms(get_keystroke_delay(features)); i++; @@ -68,4 +74,7 @@ void totp_type_code_worker_execute_automation( furi_delay_ms(get_keystroke_delay(features)); totp_type_code_worker_press_key(HID_KEYBOARD_TAB, key_press_fn, key_release_fn, features); } + + totp_type_code_worker_press_key( + HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features); } \ No newline at end of file