mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-13 07:18:35 -07:00
Merge branch 'dev' of https://github.com/DarkFlippers/unleashed-firmware into xfw-dev
This commit is contained in:
234
applications/external/totp/services/config/config.c
vendored
234
applications/external/totp/services/config/config.c
vendored
@@ -9,7 +9,8 @@
|
||||
#include "../../types/common.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "../../features_config.h"
|
||||
#include "../crypto/crypto.h"
|
||||
#include "../crypto/crypto_facade.h"
|
||||
#include "../crypto/constants.h"
|
||||
#include "migrations/common_migration.h"
|
||||
|
||||
#define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
|
||||
@@ -110,7 +111,16 @@ static char* totp_config_file_backup_i(Storage* storage) {
|
||||
static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
|
||||
if(storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK) {
|
||||
bool conf_file_exists = storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK;
|
||||
if(!conf_file_exists) {
|
||||
FURI_LOG_I(LOGGING_TAG, "Application catalog needs to be migrated");
|
||||
FS_Error migration_result =
|
||||
storage_common_migrate(storage, EXT_PATH("authenticator"), CONFIG_FILE_DIRECTORY_PATH);
|
||||
FURI_LOG_I(LOGGING_TAG, "Migrated catalog. Result code: %d", (int)migration_result);
|
||||
conf_file_exists = storage_common_stat(storage, CONFIG_FILE_PATH, NULL) == FSE_OK;
|
||||
}
|
||||
|
||||
if(conf_file_exists) {
|
||||
FURI_LOG_D(LOGGING_TAG, "Config file %s found", CONFIG_FILE_PATH);
|
||||
if(!flipper_format_file_open_existing(fff_data_file, CONFIG_FILE_PATH)) {
|
||||
FURI_LOG_E(LOGGING_TAG, "Error opening existing file %s", CONFIG_FILE_PATH);
|
||||
@@ -119,16 +129,6 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_D(LOGGING_TAG, "Config file %s is not found. Will create new.", CONFIG_FILE_PATH);
|
||||
if(storage_common_stat(storage, CONFIG_FILE_DIRECTORY_PATH, NULL) == FSE_NOT_EXIST) {
|
||||
FURI_LOG_D(
|
||||
LOGGING_TAG,
|
||||
"Directory %s doesn't exist. Will create new.",
|
||||
CONFIG_FILE_DIRECTORY_PATH);
|
||||
if(!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) {
|
||||
FURI_LOG_E(LOGGING_TAG, "Error creating directory %s", CONFIG_FILE_DIRECTORY_PATH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!flipper_format_file_open_new(fff_data_file, CONFIG_FILE_PATH)) {
|
||||
totp_close_config_file(fff_data_file);
|
||||
@@ -139,6 +139,13 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
||||
flipper_format_write_header_cstr(
|
||||
fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION);
|
||||
|
||||
uint32_t tmp_uint32 = CRYPTO_LATEST_VERSION;
|
||||
flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &tmp_uint32, 1);
|
||||
|
||||
tmp_uint32 = DEFAULT_CRYPTO_KEY_SLOT;
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &tmp_uint32, 1);
|
||||
|
||||
flipper_format_write_comment_cstr(
|
||||
fff_data_file,
|
||||
"Config file format specification can be found here: https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md");
|
||||
@@ -146,7 +153,7 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
||||
float tmp_tz = 0;
|
||||
flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1);
|
||||
|
||||
uint32_t tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
|
||||
tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
|
||||
|
||||
@@ -154,7 +161,11 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1);
|
||||
|
||||
tmp_uint32 = 0;
|
||||
tmp_uint32 = AutomationKeyboardLayoutQWERTY;
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1);
|
||||
|
||||
tmp_uint32 = 0; //-V1048
|
||||
flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1);
|
||||
|
||||
if(!flipper_format_rewind(fff_data_file)) {
|
||||
@@ -233,6 +244,12 @@ bool totp_config_file_update_automation_method(const PluginState* plugin_state)
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_uint32 = plugin_state->automation_kb_layout;
|
||||
if(!flipper_format_insert_or_update_uint32(
|
||||
file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
update_result = true;
|
||||
} while(false);
|
||||
|
||||
@@ -265,6 +282,12 @@ bool totp_config_file_update_user_settings(const PluginState* plugin_state) {
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_uint32 = plugin_state->automation_kb_layout;
|
||||
if(!flipper_format_insert_or_update_uint32(
|
||||
file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
update_result = true;
|
||||
} while(false);
|
||||
|
||||
@@ -344,8 +367,38 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t tmp_uint32;
|
||||
|
||||
if(!flipper_format_read_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &tmp_uint32, 1)) {
|
||||
FURI_LOG_E(LOGGING_TAG, "Missing required " TOTP_CONFIG_KEY_CRYPTO_VERSION "property");
|
||||
break;
|
||||
}
|
||||
|
||||
plugin_state->crypto_settings.crypto_version = tmp_uint32;
|
||||
|
||||
if(!flipper_format_rewind(fff_data_file)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &tmp_uint32, 1)) {
|
||||
FURI_LOG_E(
|
||||
LOGGING_TAG, "Missing required " TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT "property");
|
||||
break;
|
||||
}
|
||||
|
||||
plugin_state->crypto_settings.crypto_key_slot = tmp_uint32;
|
||||
|
||||
if(!flipper_format_rewind(fff_data_file)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_hex(
|
||||
fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE)) {
|
||||
fff_data_file,
|
||||
TOTP_CONFIG_KEY_BASE_IV,
|
||||
&plugin_state->crypto_settings.base_iv[0],
|
||||
CRYPTO_IV_LENGTH)) {
|
||||
FURI_LOG_D(LOGGING_TAG, "Missing base IV");
|
||||
}
|
||||
|
||||
@@ -357,22 +410,23 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
||||
if(flipper_format_get_value_count(
|
||||
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, &crypto_size) &&
|
||||
crypto_size > 0) {
|
||||
plugin_state->crypto_verify_data = malloc(sizeof(uint8_t) * crypto_size);
|
||||
furi_check(plugin_state->crypto_verify_data != NULL);
|
||||
plugin_state->crypto_verify_data_length = crypto_size;
|
||||
plugin_state->crypto_settings.crypto_verify_data =
|
||||
malloc(sizeof(uint8_t) * crypto_size);
|
||||
furi_check(plugin_state->crypto_settings.crypto_verify_data != NULL);
|
||||
plugin_state->crypto_settings.crypto_verify_data_length = crypto_size;
|
||||
if(!flipper_format_read_hex(
|
||||
fff_data_file,
|
||||
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
|
||||
plugin_state->crypto_verify_data,
|
||||
plugin_state->crypto_settings.crypto_verify_data,
|
||||
crypto_size)) {
|
||||
FURI_LOG_D(LOGGING_TAG, "Missing crypto verify token");
|
||||
free(plugin_state->crypto_verify_data);
|
||||
plugin_state->crypto_verify_data = NULL;
|
||||
plugin_state->crypto_verify_data_length = 0;
|
||||
free(plugin_state->crypto_settings.crypto_verify_data);
|
||||
plugin_state->crypto_settings.crypto_verify_data = NULL;
|
||||
plugin_state->crypto_settings.crypto_verify_data_length = 0;
|
||||
}
|
||||
} else {
|
||||
plugin_state->crypto_verify_data = NULL;
|
||||
plugin_state->crypto_verify_data_length = 0;
|
||||
plugin_state->crypto_settings.crypto_verify_data = NULL;
|
||||
plugin_state->crypto_settings.crypto_verify_data_length = 0;
|
||||
}
|
||||
|
||||
if(!flipper_format_rewind(fff_data_file)) {
|
||||
@@ -390,13 +444,17 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
||||
}
|
||||
|
||||
if(!flipper_format_read_bool(
|
||||
fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) {
|
||||
plugin_state->pin_set = true;
|
||||
fff_data_file,
|
||||
TOTP_CONFIG_KEY_PINSET,
|
||||
&plugin_state->crypto_settings.pin_required,
|
||||
1)) {
|
||||
plugin_state->crypto_settings.pin_required = true;
|
||||
}
|
||||
|
||||
flipper_format_rewind(fff_data_file);
|
||||
if(!flipper_format_rewind(fff_data_file)) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t tmp_uint32;
|
||||
if(!flipper_format_read_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
|
||||
tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
|
||||
@@ -404,7 +462,9 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
||||
|
||||
plugin_state->notification_method = tmp_uint32;
|
||||
|
||||
flipper_format_rewind(fff_data_file);
|
||||
if(!flipper_format_rewind(fff_data_file)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) {
|
||||
@@ -413,6 +473,21 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
||||
|
||||
plugin_state->automation_method = tmp_uint32;
|
||||
|
||||
if(!flipper_format_rewind(fff_data_file)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, &tmp_uint32, 1)) {
|
||||
tmp_uint32 = AutomationKeyboardLayoutQWERTY;
|
||||
}
|
||||
|
||||
plugin_state->automation_kb_layout = tmp_uint32;
|
||||
|
||||
if(!flipper_format_rewind(fff_data_file)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1)) {
|
||||
tmp_uint32 = 0;
|
||||
}
|
||||
@@ -425,7 +500,9 @@ bool totp_config_file_load(PluginState* const plugin_state) {
|
||||
plugin_state->config_file_context->config_file = fff_data_file;
|
||||
plugin_state->config_file_context->token_info_iterator_context =
|
||||
totp_token_info_iterator_alloc(
|
||||
storage, plugin_state->config_file_context->config_file, plugin_state->iv);
|
||||
storage,
|
||||
plugin_state->config_file_context->config_file,
|
||||
&plugin_state->crypto_settings);
|
||||
result = true;
|
||||
} while(false);
|
||||
|
||||
@@ -438,21 +515,39 @@ bool totp_config_file_update_crypto_signatures(const PluginState* plugin_state)
|
||||
flipper_format_rewind(config_file);
|
||||
bool update_result = false;
|
||||
do {
|
||||
uint32_t tmp_uint32 = plugin_state->crypto_settings.crypto_version;
|
||||
if(!flipper_format_insert_or_update_uint32(
|
||||
config_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &tmp_uint32, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_uint32 = plugin_state->crypto_settings.crypto_key_slot;
|
||||
if(!flipper_format_insert_or_update_uint32(
|
||||
config_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &tmp_uint32, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_insert_or_update_hex(
|
||||
config_file, TOTP_CONFIG_KEY_BASE_IV, plugin_state->base_iv, TOTP_IV_SIZE)) {
|
||||
config_file,
|
||||
TOTP_CONFIG_KEY_BASE_IV,
|
||||
plugin_state->crypto_settings.base_iv,
|
||||
CRYPTO_IV_LENGTH)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_insert_or_update_hex(
|
||||
config_file,
|
||||
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
|
||||
plugin_state->crypto_verify_data,
|
||||
plugin_state->crypto_verify_data_length)) {
|
||||
plugin_state->crypto_settings.crypto_verify_data,
|
||||
plugin_state->crypto_settings.crypto_verify_data_length)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_insert_or_update_bool(
|
||||
config_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) {
|
||||
config_file,
|
||||
TOTP_CONFIG_KEY_PINSET,
|
||||
&plugin_state->crypto_settings.pin_required,
|
||||
1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -480,6 +575,7 @@ void totp_config_file_reset(PluginState* const plugin_state) {
|
||||
|
||||
bool totp_config_file_update_encryption(
|
||||
PluginState* plugin_state,
|
||||
uint8_t new_crypto_key_slot,
|
||||
const uint8_t* new_pin,
|
||||
uint8_t new_pin_length) {
|
||||
FlipperFormat* config_file = plugin_state->config_file_context->config_file;
|
||||
@@ -489,23 +585,28 @@ bool totp_config_file_update_encryption(
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t old_iv[TOTP_IV_SIZE];
|
||||
memcpy(&old_iv[0], &plugin_state->iv[0], TOTP_IV_SIZE);
|
||||
|
||||
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
|
||||
memset(&plugin_state->base_iv[0], 0, TOTP_IV_SIZE);
|
||||
if(plugin_state->crypto_verify_data != NULL) {
|
||||
free(plugin_state->crypto_verify_data);
|
||||
plugin_state->crypto_verify_data = NULL;
|
||||
if(!totp_crypto_check_key_slot(new_crypto_key_slot)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CryptoSeedIVResult seed_result =
|
||||
totp_crypto_seed_iv(plugin_state, new_pin_length > 0 ? new_pin : NULL, new_pin_length);
|
||||
CryptoSettings old_crypto_settings = plugin_state->crypto_settings;
|
||||
|
||||
memset(&plugin_state->crypto_settings.iv[0], 0, CRYPTO_IV_LENGTH);
|
||||
memset(&plugin_state->crypto_settings.base_iv[0], 0, CRYPTO_IV_LENGTH);
|
||||
if(plugin_state->crypto_settings.crypto_verify_data != NULL) {
|
||||
free(plugin_state->crypto_settings.crypto_verify_data);
|
||||
plugin_state->crypto_settings.crypto_verify_data = NULL;
|
||||
}
|
||||
|
||||
plugin_state->crypto_settings.crypto_key_slot = new_crypto_key_slot;
|
||||
plugin_state->crypto_settings.crypto_version = CRYPTO_LATEST_VERSION;
|
||||
|
||||
CryptoSeedIVResult seed_result = totp_crypto_seed_iv(
|
||||
&plugin_state->crypto_settings, new_pin_length > 0 ? new_pin : NULL, new_pin_length);
|
||||
if(seed_result & CryptoSeedIVResultFlagSuccess &&
|
||||
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData) {
|
||||
if(!totp_config_file_update_crypto_signatures(plugin_state)) {
|
||||
return false;
|
||||
}
|
||||
seed_result & CryptoSeedIVResultFlagNewCryptoVerifyData &&
|
||||
!totp_config_file_update_crypto_signatures(plugin_state)) {
|
||||
return false;
|
||||
} else if(seed_result == CryptoSeedIVResultFailed) {
|
||||
return false;
|
||||
}
|
||||
@@ -552,12 +653,15 @@ bool totp_config_file_update_encryption(
|
||||
|
||||
size_t plain_token_length;
|
||||
uint8_t* plain_token = totp_crypto_decrypt(
|
||||
encrypted_token, secret_bytes_count, &old_iv[0], &plain_token_length);
|
||||
encrypted_token, secret_bytes_count, &old_crypto_settings, &plain_token_length);
|
||||
|
||||
free(encrypted_token);
|
||||
size_t encrypted_token_length;
|
||||
encrypted_token = totp_crypto_encrypt(
|
||||
plain_token, plain_token_length, &plugin_state->iv[0], &encrypted_token_length);
|
||||
plain_token,
|
||||
plain_token_length,
|
||||
&plugin_state->crypto_settings,
|
||||
&encrypted_token_length);
|
||||
|
||||
memset_s(plain_token, plain_token_length, 0, plain_token_length);
|
||||
free(plain_token);
|
||||
@@ -588,6 +692,36 @@ bool totp_config_file_update_encryption(
|
||||
return result;
|
||||
}
|
||||
|
||||
bool totp_config_file_ensure_latest_encryption(
|
||||
PluginState* plugin_state,
|
||||
const uint8_t* pin,
|
||||
uint8_t pin_length) {
|
||||
bool result = true;
|
||||
if(plugin_state->crypto_settings.crypto_version < CRYPTO_LATEST_VERSION) {
|
||||
FURI_LOG_I(LOGGING_TAG, "Migration to crypto v%d is needed", CRYPTO_LATEST_VERSION);
|
||||
char* backup_path = totp_config_file_backup(plugin_state);
|
||||
if(backup_path != NULL) {
|
||||
free(backup_path);
|
||||
uint8_t crypto_key_slot = plugin_state->crypto_settings.crypto_key_slot;
|
||||
if(!totp_crypto_check_key_slot(crypto_key_slot)) {
|
||||
crypto_key_slot = DEFAULT_CRYPTO_KEY_SLOT;
|
||||
}
|
||||
|
||||
result =
|
||||
totp_config_file_update_encryption(plugin_state, crypto_key_slot, pin, pin_length);
|
||||
FURI_LOG_I(
|
||||
LOGGING_TAG,
|
||||
"Migration to crypto v%d is done. Result: %d",
|
||||
CRYPTO_LATEST_VERSION,
|
||||
result);
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TokenInfoIteratorContext* totp_config_get_token_iterator_context(const PluginState* plugin_state) {
|
||||
return plugin_state->config_file_context->token_info_iterator_context;
|
||||
}
|
||||
|
||||
@@ -73,15 +73,29 @@ void totp_config_file_close(PluginState* const plugin_state);
|
||||
/**
|
||||
* @brief Updates config file encryption by re-encrypting it using new user's PIN and new randomly generated IV
|
||||
* @param plugin_state application state
|
||||
* @param new_crypto_key_slot new crypto key slot to be used
|
||||
* @param new_pin new user's PIN
|
||||
* @param new_pin_length new user's PIN length
|
||||
* @return \c true if config file encryption successfully updated; \c false otherwise
|
||||
*/
|
||||
bool totp_config_file_update_encryption(
|
||||
PluginState* plugin_state,
|
||||
uint8_t new_crypto_key_slot,
|
||||
const uint8_t* new_pin,
|
||||
uint8_t new_pin_length);
|
||||
|
||||
/**
|
||||
* @brief Ensures application config file uses latest encryption and upgrades encryption if needed
|
||||
* @param plugin_state application state
|
||||
* @param pin user's PIN
|
||||
* @param pin_length user's PIN length
|
||||
* @return \c true if operation succeeded; \c false otherwise
|
||||
*/
|
||||
bool totp_config_file_ensure_latest_encryption(
|
||||
PluginState* plugin_state,
|
||||
const uint8_t* pin,
|
||||
uint8_t pin_length);
|
||||
|
||||
/**
|
||||
* @brief Gets token info iterator context
|
||||
* @param plugin_state application state
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator")
|
||||
#define CONFIG_FILE_DIRECTORY_PATH STORAGE_APP_DATA_PATH_PREFIX
|
||||
#define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
|
||||
#define CONFIG_FILE_ACTUAL_VERSION (6)
|
||||
#define CONFIG_FILE_ACTUAL_VERSION (8)
|
||||
|
||||
#define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
|
||||
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
|
||||
@@ -18,4 +18,7 @@
|
||||
#define TOTP_CONFIG_KEY_PINSET "PinIsSet"
|
||||
#define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod"
|
||||
#define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod"
|
||||
#define TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT "AutomationKbLayout"
|
||||
#define TOTP_CONFIG_KEY_FONT "Font"
|
||||
#define TOTP_CONFIG_KEY_CRYPTO_VERSION "CryptoVersion"
|
||||
#define TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT "CryptoKeySlot"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "common_migration.h"
|
||||
#include "../constants.h"
|
||||
#include "../../../types/token_info.h"
|
||||
#include "../../../types/automation_kb_layout.h"
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
bool totp_config_migrate_to_latest(
|
||||
@@ -17,6 +18,28 @@ bool totp_config_migrate_to_latest(
|
||||
break;
|
||||
}
|
||||
|
||||
if(flipper_format_read_string(
|
||||
fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, temp_str)) {
|
||||
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, temp_str);
|
||||
} else {
|
||||
uint32_t old_crypto_version = 1;
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERSION, &old_crypto_version, 1);
|
||||
}
|
||||
|
||||
flipper_format_rewind(fff_backup_data_file);
|
||||
|
||||
if(flipper_format_read_string(
|
||||
fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, temp_str)) {
|
||||
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, temp_str);
|
||||
} else {
|
||||
uint32_t default_old_key_slot = 2;
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file, TOTP_CONFIG_KEY_CRYPTO_KEY_SLOT, &default_old_key_slot, 1);
|
||||
}
|
||||
|
||||
flipper_format_rewind(fff_backup_data_file);
|
||||
|
||||
if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) {
|
||||
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
|
||||
}
|
||||
@@ -68,6 +91,21 @@ bool totp_config_migrate_to_latest(
|
||||
|
||||
flipper_format_rewind(fff_backup_data_file);
|
||||
|
||||
if(flipper_format_read_string(
|
||||
fff_backup_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, temp_str)) {
|
||||
flipper_format_write_string(
|
||||
fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT, temp_str);
|
||||
} else {
|
||||
uint32_t default_automation_kb_layout = AutomationKeyboardLayoutQWERTY;
|
||||
flipper_format_write_uint32(
|
||||
fff_data_file,
|
||||
TOTP_CONFIG_KEY_AUTOMATION_KB_LAYOUT,
|
||||
&default_automation_kb_layout,
|
||||
1);
|
||||
}
|
||||
|
||||
flipper_format_rewind(fff_backup_data_file);
|
||||
|
||||
while(true) {
|
||||
if(!flipper_format_read_string(
|
||||
fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <flipper_format/flipper_format_stream.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include "../../types/common.h"
|
||||
#include "../../types/crypto_settings.h"
|
||||
|
||||
#define CONFIG_FILE_PART_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf.part"
|
||||
#define STREAM_COPY_BUFFER_SIZE 128
|
||||
@@ -15,7 +16,7 @@ struct TokenInfoIteratorContext {
|
||||
size_t last_seek_index;
|
||||
TokenInfo* current_token;
|
||||
FlipperFormat* config_file;
|
||||
uint8_t* iv;
|
||||
CryptoSettings* crypto_settings;
|
||||
Storage* storage;
|
||||
};
|
||||
|
||||
@@ -237,8 +238,10 @@ static bool
|
||||
return result;
|
||||
}
|
||||
|
||||
TokenInfoIteratorContext*
|
||||
totp_token_info_iterator_alloc(Storage* storage, FlipperFormat* config_file, uint8_t* iv) {
|
||||
TokenInfoIteratorContext* totp_token_info_iterator_alloc(
|
||||
Storage* storage,
|
||||
FlipperFormat* config_file,
|
||||
CryptoSettings* crypto_settings) {
|
||||
Stream* stream = flipper_format_get_raw_stream(config_file);
|
||||
stream_rewind(stream);
|
||||
size_t tokens_count = 0;
|
||||
@@ -256,7 +259,7 @@ TokenInfoIteratorContext*
|
||||
context->total_count = tokens_count;
|
||||
context->current_token = token_info_alloc();
|
||||
context->config_file = config_file;
|
||||
context->iv = iv;
|
||||
context->crypto_settings = crypto_settings;
|
||||
context->storage = storage;
|
||||
return context;
|
||||
}
|
||||
@@ -453,7 +456,7 @@ bool totp_token_info_iterator_go_to(TokenInfoIteratorContext* context, size_t to
|
||||
furi_string_get_cstr(temp_str),
|
||||
furi_string_size(temp_str),
|
||||
PlainTokenSecretEncodingBase32,
|
||||
context->iv)) {
|
||||
context->crypto_settings)) {
|
||||
FURI_LOG_W(
|
||||
LOGGING_TAG,
|
||||
"Token \"%s\" has plain secret",
|
||||
|
||||
@@ -28,11 +28,13 @@ enum TotpIteratorUpdateTokenResults {
|
||||
* @brief Initializes a new token info iterator
|
||||
* @param storage storage reference
|
||||
* @param config_file config file to use
|
||||
* @param iv initialization vector (IV) to be used for encryption\decryption
|
||||
* @param crypto_settings crypto settings
|
||||
* @return Token info iterator context
|
||||
*/
|
||||
TokenInfoIteratorContext*
|
||||
totp_token_info_iterator_alloc(Storage* storage, FlipperFormat* config_file, uint8_t* iv);
|
||||
TokenInfoIteratorContext* totp_token_info_iterator_alloc(
|
||||
Storage* storage,
|
||||
FlipperFormat* config_file,
|
||||
CryptoSettings* crypto_settings);
|
||||
|
||||
/**
|
||||
* @brief Navigates iterator to the token with given index
|
||||
|
||||
23
applications/external/totp/services/crypto/common_types.h
vendored
Normal file
23
applications/external/totp/services/crypto/common_types.h
vendored
Normal file
@@ -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
applications/external/totp/services/crypto/constants.h
vendored
Normal file
11
applications/external/totp/services/crypto/constants.h
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#define CRYPTO_IV_LENGTH (16)
|
||||
|
||||
// According to this explanation: https://github.com/flipperdevices/flipperzero-firmware/issues/2885#issuecomment-1646664666
|
||||
// disabling usage of any key which is "the same across all devices"
|
||||
#define ACCEPTABLE_CRYPTO_KEY_SLOT_START (12)
|
||||
#define ACCEPTABLE_CRYPTO_KEY_SLOT_END (100)
|
||||
|
||||
#define DEFAULT_CRYPTO_KEY_SLOT ACCEPTABLE_CRYPTO_KEY_SLOT_START
|
||||
#define CRYPTO_LATEST_VERSION (2)
|
||||
78
applications/external/totp/services/crypto/crypto_facade.c
vendored
Normal file
78
applications/external/totp/services/crypto/crypto_facade.c
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "crypto_facade.h"
|
||||
#include <furi_hal_crypto.h>
|
||||
#include <furi/core/check.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 CryptoSettings* crypto_settings,
|
||||
size_t* encrypted_data_length) {
|
||||
if(crypto_settings->crypto_version == 1) {
|
||||
return totp_crypto_encrypt_v1(
|
||||
plain_data, plain_data_length, crypto_settings, encrypted_data_length);
|
||||
}
|
||||
|
||||
if(crypto_settings->crypto_version == 2) {
|
||||
return totp_crypto_encrypt_v2(
|
||||
plain_data, plain_data_length, crypto_settings, encrypted_data_length);
|
||||
}
|
||||
|
||||
furi_crash("Unsupported crypto version");
|
||||
}
|
||||
|
||||
uint8_t* totp_crypto_decrypt(
|
||||
const uint8_t* encrypted_data,
|
||||
const size_t encrypted_data_length,
|
||||
const CryptoSettings* crypto_settings,
|
||||
size_t* decrypted_data_length) {
|
||||
if(crypto_settings->crypto_version == 1) {
|
||||
return totp_crypto_decrypt_v1(
|
||||
encrypted_data, encrypted_data_length, crypto_settings, decrypted_data_length);
|
||||
}
|
||||
|
||||
if(crypto_settings->crypto_version == 2) {
|
||||
return totp_crypto_decrypt_v2(
|
||||
encrypted_data, encrypted_data_length, crypto_settings, decrypted_data_length);
|
||||
}
|
||||
|
||||
furi_crash("Unsupported crypto version");
|
||||
}
|
||||
|
||||
CryptoSeedIVResult
|
||||
totp_crypto_seed_iv(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length) {
|
||||
if(crypto_settings->crypto_version == 1) {
|
||||
return totp_crypto_seed_iv_v1(crypto_settings, pin, pin_length);
|
||||
}
|
||||
|
||||
if(crypto_settings->crypto_version == 2) {
|
||||
return totp_crypto_seed_iv_v2(crypto_settings, pin, pin_length);
|
||||
}
|
||||
|
||||
furi_crash("Unsupported crypto version");
|
||||
}
|
||||
|
||||
bool totp_crypto_verify_key(const CryptoSettings* crypto_settings) {
|
||||
if(crypto_settings->crypto_version == 1) {
|
||||
return totp_crypto_verify_key_v1(crypto_settings);
|
||||
}
|
||||
|
||||
if(crypto_settings->crypto_version == 2) {
|
||||
return totp_crypto_verify_key_v2(crypto_settings);
|
||||
}
|
||||
|
||||
furi_crash("Unsupported crypto version");
|
||||
}
|
||||
@@ -1,68 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../types/plugin_state.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "../../types/crypto_settings.h"
|
||||
#include "common_types.h"
|
||||
|
||||
typedef uint8_t CryptoSeedIVResult;
|
||||
|
||||
enum CryptoSeedIVResults {
|
||||
|
||||
/**
|
||||
* @brief IV seeding operation failed
|
||||
*/
|
||||
CryptoSeedIVResultFailed = 0b00,
|
||||
|
||||
/**
|
||||
* @brief IV seeding operation succeeded
|
||||
*/
|
||||
CryptoSeedIVResultFlagSuccess = 0b01,
|
||||
|
||||
/**
|
||||
* @brief As a part of IV seeding operation new crypto verify data has been generated
|
||||
*/
|
||||
CryptoSeedIVResultFlagNewCryptoVerifyData = 0b10
|
||||
};
|
||||
/**
|
||||
* @brief Checks whether key slot can be used for encryption purposes
|
||||
* @param key_slot key slot index
|
||||
* @return \c true if key slot can be used for encryption; \c false otherwise
|
||||
*/
|
||||
bool totp_crypto_check_key_slot(uint8_t key_slot);
|
||||
|
||||
/**
|
||||
* @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
|
||||
* @param plain_data plain data to be encrypted
|
||||
* @param plain_data_length plain data length
|
||||
* @param iv initialization vector (IV) to be used to encrypt plain data
|
||||
* @param crypto_settings crypto settings
|
||||
* @param[out] encrypted_data_length encrypted data length
|
||||
* @return Encrypted data
|
||||
*/
|
||||
uint8_t* totp_crypto_encrypt(
|
||||
const uint8_t* plain_data,
|
||||
const size_t plain_data_length,
|
||||
const uint8_t* iv,
|
||||
const CryptoSettings* crypto_settings,
|
||||
size_t* encrypted_data_length);
|
||||
|
||||
/**
|
||||
* @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV)
|
||||
* @param encrypted_data encrypted data to be decrypted
|
||||
* @param encrypted_data_length encrypted data length
|
||||
* @param iv initialization vector (IV) to be used to encrypt plain data
|
||||
* @param crypto_settings crypto settings
|
||||
* @param[out] decrypted_data_length decrypted data length
|
||||
* @return Decrypted data
|
||||
*/
|
||||
uint8_t* totp_crypto_decrypt(
|
||||
const uint8_t* encrypted_data,
|
||||
const size_t encrypted_data_length,
|
||||
const uint8_t* iv,
|
||||
const CryptoSettings* crypto_settings,
|
||||
size_t* decrypted_data_length);
|
||||
|
||||
/**
|
||||
* @brief Seed initialization vector (IV) using user's PIN
|
||||
* @param plugin_state application state
|
||||
* @param crypto_settings crypto settings
|
||||
* @param pin user's PIN
|
||||
* @param pin_length user's PIN length
|
||||
* @return Results of seeding IV
|
||||
*/
|
||||
CryptoSeedIVResult
|
||||
totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length);
|
||||
totp_crypto_seed_iv(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length);
|
||||
|
||||
/**
|
||||
* @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption
|
||||
* @param plugin_state application state
|
||||
* @param crypto_settings crypto settings
|
||||
* @return \c true if cryptographic information is valid; \c false otherwise
|
||||
*/
|
||||
bool totp_crypto_verify_key(const PluginState* plugin_state);
|
||||
bool totp_crypto_verify_key(const CryptoSettings* crypto_settings);
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "crypto.h"
|
||||
#include "crypto_v1.h"
|
||||
#include <stdlib.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal_crypto.h>
|
||||
#include <furi_hal_random.h>
|
||||
#include <furi_hal_version.h>
|
||||
@@ -8,13 +10,14 @@
|
||||
#define CRYPTO_KEY_SLOT (2)
|
||||
#define CRYPTO_VERIFY_KEY_LENGTH (16)
|
||||
#define CRYPTO_ALIGNMENT_FACTOR (16)
|
||||
#define TOTP_IV_SIZE (16)
|
||||
|
||||
static const char* CRYPTO_VERIFY_KEY = "FFF_Crypto_pass";
|
||||
|
||||
uint8_t* totp_crypto_encrypt(
|
||||
uint8_t* totp_crypto_encrypt_v1(
|
||||
const uint8_t* plain_data,
|
||||
const size_t plain_data_length,
|
||||
const uint8_t* iv,
|
||||
const CryptoSettings* crypto_settings,
|
||||
size_t* encrypted_data_length) {
|
||||
uint8_t* encrypted_data;
|
||||
size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR;
|
||||
@@ -29,7 +32,7 @@ uint8_t* totp_crypto_encrypt(
|
||||
furi_check(encrypted_data != NULL);
|
||||
*encrypted_data_length = plain_data_aligned_length;
|
||||
|
||||
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
|
||||
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, crypto_settings->iv);
|
||||
furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length);
|
||||
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
|
||||
|
||||
@@ -40,7 +43,7 @@ uint8_t* totp_crypto_encrypt(
|
||||
furi_check(encrypted_data != NULL);
|
||||
*encrypted_data_length = plain_data_length;
|
||||
|
||||
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
|
||||
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, crypto_settings->iv);
|
||||
furi_hal_crypto_encrypt(plain_data, encrypted_data, plain_data_length);
|
||||
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
|
||||
}
|
||||
@@ -48,29 +51,31 @@ uint8_t* totp_crypto_encrypt(
|
||||
return encrypted_data;
|
||||
}
|
||||
|
||||
uint8_t* totp_crypto_decrypt(
|
||||
uint8_t* totp_crypto_decrypt_v1(
|
||||
const uint8_t* encrypted_data,
|
||||
const size_t encrypted_data_length,
|
||||
const uint8_t* iv,
|
||||
const CryptoSettings* crypto_settings,
|
||||
size_t* decrypted_data_length) {
|
||||
*decrypted_data_length = encrypted_data_length;
|
||||
uint8_t* decrypted_data = malloc(*decrypted_data_length);
|
||||
furi_check(decrypted_data != NULL);
|
||||
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
|
||||
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, crypto_settings->iv);
|
||||
furi_hal_crypto_decrypt(encrypted_data, decrypted_data, encrypted_data_length);
|
||||
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
|
||||
return decrypted_data;
|
||||
}
|
||||
|
||||
CryptoSeedIVResult
|
||||
totp_crypto_seed_iv(PluginState* plugin_state, const uint8_t* pin, uint8_t pin_length) {
|
||||
CryptoSeedIVResult totp_crypto_seed_iv_v1(
|
||||
CryptoSettings* crypto_settings,
|
||||
const uint8_t* pin,
|
||||
uint8_t pin_length) {
|
||||
CryptoSeedIVResult result;
|
||||
if(plugin_state->crypto_verify_data == NULL) {
|
||||
if(crypto_settings->crypto_verify_data == NULL) {
|
||||
FURI_LOG_I(LOGGING_TAG, "Generating new IV");
|
||||
furi_hal_random_fill_buf(&plugin_state->base_iv[0], TOTP_IV_SIZE);
|
||||
furi_hal_random_fill_buf(&crypto_settings->base_iv[0], TOTP_IV_SIZE);
|
||||
}
|
||||
|
||||
memcpy(&plugin_state->iv[0], &plugin_state->base_iv[0], TOTP_IV_SIZE);
|
||||
memcpy(&crypto_settings->iv[0], &crypto_settings->base_iv[0], TOTP_IV_SIZE);
|
||||
if(pin != NULL && pin_length > 0) {
|
||||
uint8_t max_i;
|
||||
if(pin_length > TOTP_IV_SIZE) {
|
||||
@@ -80,7 +85,7 @@ CryptoSeedIVResult
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < max_i; i++) {
|
||||
plugin_state->iv[i] = plugin_state->iv[i] ^ (uint8_t)(pin[i] * (i + 1));
|
||||
crypto_settings->iv[i] = crypto_settings->iv[i] ^ (uint8_t)(pin[i] * (i + 1));
|
||||
}
|
||||
} else {
|
||||
uint8_t max_i;
|
||||
@@ -93,24 +98,24 @@ CryptoSeedIVResult
|
||||
|
||||
const uint8_t* uid = (const uint8_t*)UID64_BASE; //-V566
|
||||
for(uint8_t i = 0; i < max_i; i++) {
|
||||
plugin_state->iv[i] = plugin_state->iv[i] ^ uid[i];
|
||||
crypto_settings->iv[i] = crypto_settings->iv[i] ^ uid[i];
|
||||
}
|
||||
}
|
||||
|
||||
result = CryptoSeedIVResultFlagSuccess;
|
||||
if(plugin_state->crypto_verify_data == NULL) {
|
||||
if(crypto_settings->crypto_verify_data == NULL) {
|
||||
FURI_LOG_I(LOGGING_TAG, "Generating crypto verify data");
|
||||
plugin_state->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH);
|
||||
furi_check(plugin_state->crypto_verify_data != NULL);
|
||||
plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
|
||||
crypto_settings->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH);
|
||||
furi_check(crypto_settings->crypto_verify_data != NULL);
|
||||
crypto_settings->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
|
||||
|
||||
plugin_state->crypto_verify_data = totp_crypto_encrypt(
|
||||
crypto_settings->crypto_verify_data = totp_crypto_encrypt_v1(
|
||||
(const uint8_t*)CRYPTO_VERIFY_KEY,
|
||||
CRYPTO_VERIFY_KEY_LENGTH,
|
||||
&plugin_state->iv[0],
|
||||
&plugin_state->crypto_verify_data_length);
|
||||
crypto_settings,
|
||||
&crypto_settings->crypto_verify_data_length);
|
||||
|
||||
plugin_state->pin_set = pin != NULL && pin_length > 0;
|
||||
crypto_settings->pin_required = pin != NULL && pin_length > 0;
|
||||
|
||||
result |= CryptoSeedIVResultFlagNewCryptoVerifyData;
|
||||
}
|
||||
@@ -118,12 +123,12 @@ CryptoSeedIVResult
|
||||
return result;
|
||||
}
|
||||
|
||||
bool totp_crypto_verify_key(const PluginState* plugin_state) {
|
||||
bool totp_crypto_verify_key_v1(const CryptoSettings* crypto_settings) {
|
||||
size_t decrypted_key_length;
|
||||
uint8_t* decrypted_key = totp_crypto_decrypt(
|
||||
plugin_state->crypto_verify_data,
|
||||
plugin_state->crypto_verify_data_length,
|
||||
&plugin_state->iv[0],
|
||||
uint8_t* decrypted_key = totp_crypto_decrypt_v1(
|
||||
crypto_settings->crypto_verify_data,
|
||||
crypto_settings->crypto_verify_data_length,
|
||||
crypto_settings,
|
||||
&decrypted_key_length);
|
||||
|
||||
bool key_valid = true;
|
||||
52
applications/external/totp/services/crypto/crypto_v1.h
vendored
Normal file
52
applications/external/totp/services/crypto/crypto_v1.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "../../types/crypto_settings.h"
|
||||
#include "common_types.h"
|
||||
|
||||
/**
|
||||
* @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
|
||||
* @param plain_data plain data to be encrypted
|
||||
* @param plain_data_length plain data length
|
||||
* @param crypto_settings crypto settings
|
||||
* @param[out] encrypted_data_length encrypted data length
|
||||
* @return Encrypted data
|
||||
*/
|
||||
uint8_t* totp_crypto_encrypt_v1(
|
||||
const uint8_t* plain_data,
|
||||
const size_t plain_data_length,
|
||||
const CryptoSettings* crypto_settings,
|
||||
size_t* encrypted_data_length);
|
||||
|
||||
/**
|
||||
* @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV)
|
||||
* @param encrypted_data encrypted data to be decrypted
|
||||
* @param encrypted_data_length encrypted data length
|
||||
* @param crypto_settings crypto settings
|
||||
* @param[out] decrypted_data_length decrypted data length
|
||||
* @return Decrypted data
|
||||
*/
|
||||
uint8_t* totp_crypto_decrypt_v1(
|
||||
const uint8_t* encrypted_data,
|
||||
const size_t encrypted_data_length,
|
||||
const CryptoSettings* crypto_settings,
|
||||
size_t* decrypted_data_length);
|
||||
|
||||
/**
|
||||
* @brief Seed initialization vector (IV) using user's PIN
|
||||
* @param crypto_settings crypto settings
|
||||
* @param pin user's PIN
|
||||
* @param pin_length user's PIN length
|
||||
* @return Results of seeding IV
|
||||
*/
|
||||
CryptoSeedIVResult
|
||||
totp_crypto_seed_iv_v1(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length);
|
||||
|
||||
/**
|
||||
* @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption
|
||||
* @param crypto_settings crypto settings
|
||||
* @return \c true if cryptographic information is valid; \c false otherwise
|
||||
*/
|
||||
bool totp_crypto_verify_key_v1(const CryptoSettings* crypto_settings);
|
||||
184
applications/external/totp/services/crypto/crypto_v2.c
vendored
Normal file
184
applications/external/totp/services/crypto/crypto_v2.c
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
#include "crypto_v2.h"
|
||||
#include <stdlib.h>
|
||||
#include <furi.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 CryptoSettings* crypto_settings,
|
||||
size_t* encrypted_data_length) {
|
||||
uint8_t* encrypted_data;
|
||||
size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR;
|
||||
if(remain) {
|
||||
size_t plain_data_aligned_length = plain_data_length - remain + CRYPTO_ALIGNMENT_FACTOR;
|
||||
uint8_t* plain_data_aligned = malloc(plain_data_aligned_length);
|
||||
furi_check(plain_data_aligned != NULL);
|
||||
memset(plain_data_aligned, 0, plain_data_aligned_length);
|
||||
memcpy(plain_data_aligned, plain_data, plain_data_length);
|
||||
|
||||
encrypted_data = malloc(plain_data_aligned_length);
|
||||
furi_check(encrypted_data != NULL);
|
||||
*encrypted_data_length = plain_data_aligned_length;
|
||||
|
||||
furi_check(
|
||||
furi_hal_crypto_store_load_key(crypto_settings->crypto_key_slot, crypto_settings->iv),
|
||||
"Encryption failed: store_load_key");
|
||||
furi_check(
|
||||
furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length),
|
||||
"Encryption failed: encrypt");
|
||||
furi_check(
|
||||
furi_hal_crypto_store_unload_key(crypto_settings->crypto_key_slot),
|
||||
"Encryption failed: store_unload_key");
|
||||
|
||||
memset_s(plain_data_aligned, plain_data_aligned_length, 0, plain_data_aligned_length);
|
||||
free(plain_data_aligned);
|
||||
} else {
|
||||
encrypted_data = malloc(plain_data_length);
|
||||
furi_check(encrypted_data != NULL);
|
||||
*encrypted_data_length = plain_data_length;
|
||||
|
||||
furi_check(
|
||||
furi_hal_crypto_store_load_key(crypto_settings->crypto_key_slot, crypto_settings->iv),
|
||||
"Encryption failed: store_load_key");
|
||||
furi_check(
|
||||
furi_hal_crypto_encrypt(plain_data, encrypted_data, plain_data_length),
|
||||
"Encryption failed: encrypt");
|
||||
furi_check(
|
||||
furi_hal_crypto_store_unload_key(crypto_settings->crypto_key_slot),
|
||||
"Encryption failed: store_unload_key");
|
||||
}
|
||||
|
||||
return encrypted_data;
|
||||
}
|
||||
|
||||
uint8_t* totp_crypto_decrypt_v2(
|
||||
const uint8_t* encrypted_data,
|
||||
const size_t encrypted_data_length,
|
||||
const CryptoSettings* crypto_settings,
|
||||
size_t* decrypted_data_length) {
|
||||
*decrypted_data_length = encrypted_data_length;
|
||||
uint8_t* decrypted_data = malloc(*decrypted_data_length);
|
||||
furi_check(decrypted_data != NULL);
|
||||
furi_check(
|
||||
furi_hal_crypto_store_load_key(crypto_settings->crypto_key_slot, crypto_settings->iv),
|
||||
"Decryption failed: store_load_key");
|
||||
furi_check(
|
||||
furi_hal_crypto_decrypt(encrypted_data, decrypted_data, encrypted_data_length),
|
||||
"Decryption failed: decrypt");
|
||||
furi_check(
|
||||
furi_hal_crypto_store_unload_key(crypto_settings->crypto_key_slot),
|
||||
"Decryption failed: store_unload_key");
|
||||
return decrypted_data;
|
||||
}
|
||||
|
||||
CryptoSeedIVResult totp_crypto_seed_iv_v2(
|
||||
CryptoSettings* crypto_settings,
|
||||
const uint8_t* pin,
|
||||
uint8_t pin_length) {
|
||||
CryptoSeedIVResult result;
|
||||
if(crypto_settings->crypto_verify_data == NULL) {
|
||||
FURI_LOG_I(LOGGING_TAG, "Generating new IV");
|
||||
furi_hal_random_fill_buf(&crypto_settings->base_iv[0], CRYPTO_IV_LENGTH);
|
||||
}
|
||||
|
||||
memcpy(&crypto_settings->iv[0], &crypto_settings->base_iv[0], CRYPTO_IV_LENGTH);
|
||||
|
||||
const uint8_t* device_uid = get_device_uid();
|
||||
uint8_t device_uid_length = get_device_uid_length();
|
||||
|
||||
uint8_t hmac_key_length = device_uid_length;
|
||||
if(pin != NULL && pin_length > 0) {
|
||||
hmac_key_length += pin_length;
|
||||
}
|
||||
|
||||
uint8_t* hmac_key = malloc(hmac_key_length);
|
||||
furi_check(hmac_key != NULL);
|
||||
|
||||
memcpy(hmac_key, device_uid, device_uid_length);
|
||||
|
||||
if(pin != NULL && pin_length > 0) {
|
||||
memcpy(hmac_key + device_uid_length, pin, pin_length);
|
||||
}
|
||||
|
||||
uint8_t hmac[HMAC_SHA512_RESULT_SIZE] = {0};
|
||||
int hmac_result_code = hmac_sha512(
|
||||
hmac_key, hmac_key_length, &crypto_settings->base_iv[0], CRYPTO_IV_LENGTH, &hmac[0]);
|
||||
|
||||
memset_s(hmac_key, hmac_key_length, 0, hmac_key_length);
|
||||
free(hmac_key);
|
||||
|
||||
if(hmac_result_code == 0) {
|
||||
uint8_t offset =
|
||||
hmac[HMAC_SHA512_RESULT_SIZE - 1] % (HMAC_SHA512_RESULT_SIZE - CRYPTO_IV_LENGTH - 1);
|
||||
memcpy(&crypto_settings->iv[0], &hmac[offset], CRYPTO_IV_LENGTH);
|
||||
|
||||
result = CryptoSeedIVResultFlagSuccess;
|
||||
if(crypto_settings->crypto_verify_data == NULL) {
|
||||
const uint8_t* crypto_vkey = get_crypto_verify_key();
|
||||
uint8_t crypto_vkey_length = get_crypto_verify_key_length();
|
||||
FURI_LOG_I(LOGGING_TAG, "Generating crypto verify data");
|
||||
crypto_settings->crypto_verify_data = malloc(crypto_vkey_length);
|
||||
furi_check(crypto_settings->crypto_verify_data != NULL);
|
||||
crypto_settings->crypto_verify_data_length = crypto_vkey_length;
|
||||
|
||||
crypto_settings->crypto_verify_data = totp_crypto_encrypt_v2(
|
||||
crypto_vkey,
|
||||
crypto_vkey_length,
|
||||
crypto_settings,
|
||||
&crypto_settings->crypto_verify_data_length);
|
||||
|
||||
crypto_settings->pin_required = pin != NULL && pin_length > 0;
|
||||
|
||||
result |= CryptoSeedIVResultFlagNewCryptoVerifyData;
|
||||
}
|
||||
} else {
|
||||
result = CryptoSeedIVResultFailed;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool totp_crypto_verify_key_v2(const CryptoSettings* crypto_settings) {
|
||||
size_t decrypted_key_length;
|
||||
uint8_t* decrypted_key = totp_crypto_decrypt_v2(
|
||||
crypto_settings->crypto_verify_data,
|
||||
crypto_settings->crypto_verify_data_length,
|
||||
crypto_settings,
|
||||
&decrypted_key_length);
|
||||
|
||||
const uint8_t* crypto_vkey = get_crypto_verify_key();
|
||||
uint8_t crypto_vkey_length = get_crypto_verify_key_length();
|
||||
bool key_valid = true;
|
||||
for(uint8_t i = 0; i < crypto_vkey_length && key_valid; i++) {
|
||||
if(decrypted_key[i] != crypto_vkey[i]) key_valid = false;
|
||||
}
|
||||
|
||||
free(decrypted_key);
|
||||
|
||||
return key_valid;
|
||||
}
|
||||
52
applications/external/totp/services/crypto/crypto_v2.h
vendored
Normal file
52
applications/external/totp/services/crypto/crypto_v2.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "../../types/crypto_settings.h"
|
||||
#include "common_types.h"
|
||||
|
||||
/**
|
||||
* @brief Encrypts plain data using built-in certificate and given initialization vector (IV)
|
||||
* @param plain_data plain data to be encrypted
|
||||
* @param plain_data_length plain data length
|
||||
* @param crypto_settings crypto settings
|
||||
* @param[out] encrypted_data_length encrypted data length
|
||||
* @return Encrypted data
|
||||
*/
|
||||
uint8_t* totp_crypto_encrypt_v2(
|
||||
const uint8_t* plain_data,
|
||||
const size_t plain_data_length,
|
||||
const CryptoSettings* crypto_settings,
|
||||
size_t* encrypted_data_length);
|
||||
|
||||
/**
|
||||
* @brief Decrypts encrypted data using built-in certificate and given initialization vector (IV)
|
||||
* @param encrypted_data encrypted data to be decrypted
|
||||
* @param encrypted_data_length encrypted data length
|
||||
* @param crypto_settings crypto settings
|
||||
* @param[out] decrypted_data_length decrypted data length
|
||||
* @return Decrypted data
|
||||
*/
|
||||
uint8_t* totp_crypto_decrypt_v2(
|
||||
const uint8_t* encrypted_data,
|
||||
const size_t encrypted_data_length,
|
||||
const CryptoSettings* crypto_settings,
|
||||
size_t* decrypted_data_length);
|
||||
|
||||
/**
|
||||
* @brief Seed initialization vector (IV) using user's PIN
|
||||
* @param crypto_settings crypto settings
|
||||
* @param pin user's PIN
|
||||
* @param pin_length user's PIN length
|
||||
* @return Results of seeding IV
|
||||
*/
|
||||
CryptoSeedIVResult
|
||||
totp_crypto_seed_iv_v2(CryptoSettings* crypto_settings, const uint8_t* pin, uint8_t pin_length);
|
||||
|
||||
/**
|
||||
* @brief Verifies whether cryptographic information (certificate + IV) is valid and can be used for encryption and decryption
|
||||
* @param crypto_settings crypto settings
|
||||
* @return \c true if cryptographic information is valid; \c false otherwise
|
||||
*/
|
||||
bool totp_crypto_verify_key_v2(const CryptoSettings* crypto_settings);
|
||||
Reference in New Issue
Block a user