MX 2022-10-17 21:22:34 +03:00
parent 4f7ca617cc
commit 04d67ca8ae
No known key found for this signature in database
GPG key ID: 6C4C311DFD4B4AB5
10 changed files with 234 additions and 77 deletions

View file

@ -6,10 +6,9 @@
#include "../../services/config/config.h" #include "../../services/config/config.h"
#include "../scene_director.h" #include "../scene_director.h"
#include "../totp_scenes_enum.h" #include "../totp_scenes_enum.h"
#include "../../services/crypto/crypto.h"
#define MAX_CODE_LENGTH TOTP_IV_SIZE #define MAX_CODE_LENGTH TOTP_IV_SIZE
#define CRYPTO_VERIFY_KEY "FFF_Crypto_pass"
#define CRYPTO_VERIFY_KEY_LENGTH 16
typedef struct { typedef struct {
uint8_t code_input[MAX_CODE_LENGTH]; uint8_t code_input[MAX_CODE_LENGTH];
@ -111,52 +110,10 @@ bool totp_scene_authenticate_handle_event(PluginEvent* const event, PluginState*
} }
break; break;
case InputKeyOk: case InputKeyOk:
if(plugin_state->crypto_verify_data == NULL) { totp_crypto_seed_iv(
FURI_LOG_D(LOGGING_TAG, "Generating new IV"); plugin_state, &scene_state->code_input[0], scene_state->code_length);
furi_hal_random_fill_buf(&plugin_state->base_iv[0], TOTP_IV_SIZE);
}
memcpy(&plugin_state->iv[0], &plugin_state->base_iv[0], TOTP_IV_SIZE); if(totp_crypto_verify_key(plugin_state)) {
for(uint8_t i = 0; i < scene_state->code_length; i++) {
plugin_state->iv[i] = plugin_state->iv[i] ^
(uint8_t)(scene_state->code_input[i] * (i + 1));
}
if(plugin_state->crypto_verify_data == NULL) {
FURI_LOG_D(LOGGING_TAG, "Generating crypto verify data");
plugin_state->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH);
plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
Storage* storage = totp_open_storage();
FlipperFormat* config_file = totp_open_config_file(storage);
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, &plugin_state->iv[0]);
furi_hal_crypto_encrypt(
(uint8_t*)CRYPTO_VERIFY_KEY,
plugin_state->crypto_verify_data,
CRYPTO_VERIFY_KEY_LENGTH);
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
flipper_format_insert_or_update_hex(
config_file, TOTP_CONFIG_KEY_BASE_IV, plugin_state->base_iv, TOTP_IV_SIZE);
flipper_format_insert_or_update_hex(
config_file,
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
plugin_state->crypto_verify_data,
CRYPTO_VERIFY_KEY_LENGTH);
totp_close_config_file(config_file);
totp_close_storage();
}
uint8_t decrypted_key[CRYPTO_VERIFY_KEY_LENGTH];
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, &plugin_state->iv[0]);
furi_hal_crypto_decrypt(
plugin_state->crypto_verify_data, &decrypted_key[0], CRYPTO_VERIFY_KEY_LENGTH);
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
bool key_valid = true;
for(uint8_t i = 0; i < CRYPTO_VERIFY_KEY_LENGTH && key_valid; i++) {
if(decrypted_key[i] != CRYPTO_VERIFY_KEY[i]) key_valid = false;
}
if(key_valid) {
FURI_LOG_D(LOGGING_TAG, "PIN is valid"); FURI_LOG_D(LOGGING_TAG, "PIN is valid");
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
} else { } else {

View file

@ -8,6 +8,7 @@
#include "../../services/ui/constants.h" #include "../../services/ui/constants.h"
#include "../../services/totp/totp.h" #include "../../services/totp/totp.h"
#include "../../services/config/config.h" #include "../../services/config/config.h"
#include "../../services/crypto/crypto.h"
#include "../scene_director.h" #include "../scene_director.h"
#include "../token_menu/totp_scene_token_menu.h" #include "../token_menu/totp_scene_token_menu.h"
@ -156,24 +157,22 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
plugin_state->tokens_list, scene_state->current_token_index) plugin_state->tokens_list, scene_state->current_token_index)
->data); ->data);
uint8_t* key = malloc(tokenInfo->token_length); uint8_t key_length;
uint8_t* key = totp_crypto_decrypt(
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, &plugin_state->iv[0]); tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length);
furi_hal_crypto_decrypt(tokenInfo->token, key, tokenInfo->token_length);
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
i_token_to_str( i_token_to_str(
totp_at( totp_at(
get_totp_algo_impl(tokenInfo->algo), get_totp_algo_impl(tokenInfo->algo),
token_info_get_digits_count(tokenInfo), token_info_get_digits_count(tokenInfo),
key, key,
tokenInfo->token_length, key_length,
curr_ts, curr_ts,
plugin_state->timezone_offset, plugin_state->timezone_offset,
TOKEN_LIFETIME), TOKEN_LIFETIME),
scene_state->last_code, scene_state->last_code,
tokenInfo->digits); tokenInfo->digits);
memset(key, 0, tokenInfo->token_length); memset(key, 0, key_length);
free(key); free(key);
if(is_new_token_time) { if(is_new_token_time) {

View file

@ -199,6 +199,7 @@ void totp_full_save_config_file(PluginState* const plugin_state) {
plugin_state->crypto_verify_data_length); plugin_state->crypto_verify_data_length);
flipper_format_write_float( flipper_format_write_float(
fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1); fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1);
flipper_format_write_bool(fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1);
ListNode* node = plugin_state->tokens_list; ListNode* node = plugin_state->tokens_list;
while(node != NULL) { while(node != NULL) {
TokenInfo* token_info = node->data; TokenInfo* token_info = node->data;
@ -272,7 +273,8 @@ void totp_config_file_load_base(PluginState* const plugin_state) {
flipper_format_rewind(fff_data_file); flipper_format_rewind(fff_data_file);
uint32_t crypto_size; uint32_t crypto_size;
if(flipper_format_get_value_count(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, &crypto_size)) { if(flipper_format_get_value_count(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, &crypto_size) &&
crypto_size > 0) {
plugin_state->crypto_verify_data = malloc(sizeof(uint8_t) * crypto_size); plugin_state->crypto_verify_data = malloc(sizeof(uint8_t) * crypto_size);
plugin_state->crypto_verify_data_length = crypto_size; plugin_state->crypto_verify_data_length = crypto_size;
if(!flipper_format_read_hex( if(!flipper_format_read_hex(
@ -283,7 +285,11 @@ void totp_config_file_load_base(PluginState* const plugin_state) {
FURI_LOG_D(LOGGING_TAG, "Missing crypto verify token"); FURI_LOG_D(LOGGING_TAG, "Missing crypto verify token");
free(plugin_state->crypto_verify_data); free(plugin_state->crypto_verify_data);
plugin_state->crypto_verify_data = NULL; plugin_state->crypto_verify_data = NULL;
plugin_state->crypto_verify_data_length = 0;
} }
} else {
plugin_state->crypto_verify_data = NULL;
plugin_state->crypto_verify_data_length = 0;
} }
flipper_format_rewind(fff_data_file); flipper_format_rewind(fff_data_file);
@ -294,6 +300,13 @@ void totp_config_file_load_base(PluginState* const plugin_state) {
FURI_LOG_D(LOGGING_TAG, "Missing timezone offset information, defaulting to 0"); FURI_LOG_D(LOGGING_TAG, "Missing timezone offset information, defaulting to 0");
} }
flipper_format_rewind(fff_data_file);
if(!flipper_format_read_bool(
fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1)) {
plugin_state->pin_set = true;
}
furi_string_free(temp_str); furi_string_free(temp_str);
totp_close_config_file(fff_data_file); totp_close_config_file(fff_data_file);
totp_close_storage(); totp_close_storage();

View file

@ -10,6 +10,7 @@
#define TOTP_CONFIG_KEY_TOKEN_DIGITS "TokenDigits" #define TOTP_CONFIG_KEY_TOKEN_DIGITS "TokenDigits"
#define TOTP_CONFIG_KEY_CRYPTO_VERIFY "Crypto" #define TOTP_CONFIG_KEY_CRYPTO_VERIFY "Crypto"
#define TOTP_CONFIG_KEY_BASE_IV "BaseIV" #define TOTP_CONFIG_KEY_BASE_IV "BaseIV"
#define TOTP_CONFIG_KEY_PINSET "PinIsSet"
#define TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME "sha1" #define TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME "sha1"
#define TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME "sha256" #define TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME "sha256"

View file

@ -0,0 +1,134 @@
#include "crypto.h"
#include <furi.h>
#include <furi_hal.h>
#include "../config/config.h"
#include "../../types/common.h"
#define CRYPTO_KEY_SLOT 2
#define CRYPTO_VERIFY_KEY "FFF_Crypto_pass"
#define CRYPTO_VERIFY_KEY_LENGTH 16
#define CRYPTO_ALIGNMENT_FACTOR 16
uint8_t* totp_crypto_encrypt(
const uint8_t* plain_data,
const uint8_t plain_data_length,
const uint8_t* iv,
uint8_t* encrypted_data_length) {
uint8_t* encrypted_data;
size_t remain = plain_data_length % CRYPTO_ALIGNMENT_FACTOR;
if(remain) {
uint8_t plain_data_aligned_length = plain_data_length - remain + CRYPTO_ALIGNMENT_FACTOR;
uint8_t* plain_data_aligned = malloc(plain_data_aligned_length);
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);
*encrypted_data_length = plain_data_aligned_length;
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
furi_hal_crypto_encrypt(plain_data_aligned, encrypted_data, plain_data_aligned_length);
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
memset(plain_data_aligned, 0, plain_data_aligned_length);
free(plain_data_aligned);
} else {
encrypted_data = malloc(plain_data_length);
*encrypted_data_length = plain_data_length;
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
furi_hal_crypto_encrypt(plain_data, encrypted_data, plain_data_length);
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
}
return encrypted_data;
}
uint8_t* totp_crypto_decrypt(
const uint8_t* encrypted_data,
const uint8_t encrypted_data_length,
const uint8_t* iv,
uint8_t* decrypted_data_length) {
*decrypted_data_length = encrypted_data_length;
uint8_t* decrypted_data = malloc(*decrypted_data_length);
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
furi_hal_crypto_decrypt(encrypted_data, decrypted_data, encrypted_data_length);
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
return decrypted_data;
}
void totp_crypto_seed_iv(PluginState* plugin_state, uint8_t* pin, uint8_t pin_length) {
if(plugin_state->crypto_verify_data == NULL) {
FURI_LOG_D(LOGGING_TAG, "Generating new IV");
furi_hal_random_fill_buf(&plugin_state->base_iv[0], TOTP_IV_SIZE);
}
memcpy(&plugin_state->iv[0], &plugin_state->base_iv[0], TOTP_IV_SIZE);
if(pin != NULL && pin_length > 0) {
uint8_t max_i;
if(pin_length > TOTP_IV_SIZE) {
max_i = TOTP_IV_SIZE;
} else {
max_i = pin_length;
}
for(uint8_t i = 0; i < max_i; i++) {
plugin_state->iv[i] = plugin_state->iv[i] ^ (uint8_t)(pin[i] * (i + 1));
}
} else {
uint8_t max_i;
size_t uid_size = furi_hal_version_uid_size();
if(uid_size > TOTP_IV_SIZE) {
max_i = TOTP_IV_SIZE;
} else {
max_i = uid_size;
}
const uint8_t* uid = furi_hal_version_uid();
for(uint8_t i = 0; i < max_i; i++) {
plugin_state->iv[i] = plugin_state->iv[i] ^ uid[i];
}
}
if(plugin_state->crypto_verify_data == NULL) {
FURI_LOG_D(LOGGING_TAG, "Generating crypto verify data");
plugin_state->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH);
plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
Storage* storage = totp_open_storage();
FlipperFormat* config_file = totp_open_config_file(storage);
plugin_state->crypto_verify_data = totp_crypto_encrypt(
(uint8_t*)CRYPTO_VERIFY_KEY,
CRYPTO_VERIFY_KEY_LENGTH,
&plugin_state->iv[0],
&plugin_state->crypto_verify_data_length);
flipper_format_insert_or_update_hex(
config_file, TOTP_CONFIG_KEY_BASE_IV, plugin_state->base_iv, TOTP_IV_SIZE);
flipper_format_insert_or_update_hex(
config_file,
TOTP_CONFIG_KEY_CRYPTO_VERIFY,
plugin_state->crypto_verify_data,
CRYPTO_VERIFY_KEY_LENGTH);
plugin_state->pin_set = pin != NULL && pin_length > 0;
flipper_format_insert_or_update_bool(
config_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1);
totp_close_config_file(config_file);
totp_close_storage();
}
}
bool totp_crypto_verify_key(const PluginState* plugin_state) {
uint8_t decrypted_key_length;
uint8_t* decrypted_key = totp_crypto_decrypt(
plugin_state->crypto_verify_data,
plugin_state->crypto_verify_data_length,
&plugin_state->iv[0],
&decrypted_key_length);
bool key_valid = true;
for(uint8_t i = 0; i < CRYPTO_VERIFY_KEY_LENGTH && key_valid; i++) {
if(decrypted_key[i] != CRYPTO_VERIFY_KEY[i]) key_valid = false;
}
return key_valid;
}

View file

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

View file

@ -16,6 +16,8 @@
#include "types/event_type.h" #include "types/event_type.h"
#include "types/common.h" #include "types/common.h"
#include "scenes/scene_director.h" #include "scenes/scene_director.h"
#include "services/ui/constants.h"
#include "services/crypto/crypto.h"
#define IDLE_TIMEOUT 60000 #define IDLE_TIMEOUT 60000
@ -35,14 +37,58 @@ static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queu
furi_message_queue_put(event_queue, &event, FuriWaitForever); furi_message_queue_put(event_queue, &event, FuriWaitForever);
} }
static void totp_state_init(PluginState* const plugin_state) { static bool totp_state_init(PluginState* const plugin_state) {
plugin_state->gui = furi_record_open(RECORD_GUI); plugin_state->gui = furi_record_open(RECORD_GUI);
plugin_state->notification = furi_record_open(RECORD_NOTIFICATION); plugin_state->notification = furi_record_open(RECORD_NOTIFICATION);
plugin_state->dialogs = furi_record_open(RECORD_DIALOGS); plugin_state->dialogs = furi_record_open(RECORD_DIALOGS);
totp_config_file_load_base(plugin_state); totp_config_file_load_base(plugin_state);
totp_scene_director_init_scenes(plugin_state); totp_scene_director_init_scenes(plugin_state);
if(plugin_state->crypto_verify_data == NULL) {
DialogMessage* message = dialog_message_alloc();
dialog_message_set_buttons(message, "No", NULL, "Yes");
dialog_message_set_text(
message,
"Would you like to setup PIN?",
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER,
AlignCenter,
AlignCenter);
DialogMessageButton dialog_result = dialog_message_show(plugin_state->dialogs, message);
dialog_message_free(message);
if(dialog_result == DialogMessageButtonRight) {
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
} else {
totp_crypto_seed_iv(plugin_state, NULL, 0);
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
}
} else if(plugin_state->pin_set) {
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
} else {
totp_crypto_seed_iv(plugin_state, NULL, 0);
if(totp_crypto_verify_key(plugin_state)) {
totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
} else {
FURI_LOG_E(
LOGGING_TAG,
"Digital signature verification failed. Looks like conf file was created on another flipper and can't be used on any other");
DialogMessage* message = dialog_message_alloc();
dialog_message_set_buttons(message, "Exit", NULL, NULL);
dialog_message_set_text(
message,
"Digital signature verification failed",
SCREEN_WIDTH_CENTER,
SCREEN_HEIGHT_CENTER,
AlignCenter,
AlignCenter);
dialog_message_show(plugin_state->dialogs, message);
dialog_message_free(message);
return false;
}
}
return true;
} }
static void dispose_plugin_state(PluginState* plugin_state) { static void dispose_plugin_state(PluginState* plugin_state) {
@ -74,7 +120,11 @@ int32_t totp_app() {
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
PluginState* plugin_state = malloc(sizeof(PluginState)); PluginState* plugin_state = malloc(sizeof(PluginState));
totp_state_init(plugin_state); if(!totp_state_init(plugin_state)) {
FURI_LOG_E(LOGGING_TAG, "App state initialization failed\r\n");
dispose_plugin_state(plugin_state);
return 254;
}
ValueMutex state_mutex; ValueMutex state_mutex;
if(!init_mutex(&state_mutex, plugin_state, sizeof(PluginState))) { if(!init_mutex(&state_mutex, plugin_state, sizeof(PluginState))) {
@ -107,7 +157,7 @@ int32_t totp_app() {
processing = totp_scene_director_handle_event(&event, plugin_state); processing = totp_scene_director_handle_event(&event, plugin_state);
} else if( } else if(
plugin_state->current_scene != TotpSceneAuthentication && plugin_state->pin_set && plugin_state->current_scene != TotpSceneAuthentication &&
furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) { furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) {
totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL); totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
} }

View file

@ -1,4 +1,3 @@
#pragma once #pragma once
#define LOGGING_TAG "TOTP APP" #define LOGGING_TAG "TOTP APP"
#define CRYPTO_KEY_SLOT 2

View file

@ -23,6 +23,7 @@ typedef struct {
uint8_t* crypto_verify_data; uint8_t* crypto_verify_data;
uint8_t crypto_verify_data_length; uint8_t crypto_verify_data_length;
bool pin_set;
uint8_t iv[TOTP_IV_SIZE]; uint8_t iv[TOTP_IV_SIZE];
uint8_t base_iv[TOTP_IV_SIZE]; uint8_t base_iv[TOTP_IV_SIZE];
} PluginState; } PluginState;

View file

@ -4,6 +4,7 @@
#include "stdlib.h" #include "stdlib.h"
#include "common.h" #include "common.h"
#include "../services/base32/base32.h" #include "../services/base32/base32.h"
#include "../services/crypto/crypto.h"
TokenInfo* token_info_alloc() { TokenInfo* token_info_alloc() {
TokenInfo* tokenInfo = malloc(sizeof(TokenInfo)); TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
@ -27,25 +28,11 @@ void token_info_set_secret(
uint8_t* plain_secret = malloc(token_secret_length); uint8_t* plain_secret = malloc(token_secret_length);
int plain_secret_length = int plain_secret_length =
base32_decode((uint8_t*)base32_token_secret, plain_secret, token_secret_length); base32_decode((uint8_t*)base32_token_secret, plain_secret, token_secret_length);
token_info->token_length = plain_secret_length;
size_t remain = token_info->token_length % 16; token_info->token =
if(remain) { totp_crypto_encrypt(plain_secret, plain_secret_length, iv, &token_info->token_length);
token_info->token_length = token_info->token_length - remain + 16;
uint8_t* plain_secret_aligned = malloc(token_info->token_length);
memcpy(plain_secret_aligned, plain_secret, plain_secret_length);
memset(plain_secret, 0, plain_secret_length);
free(plain_secret);
plain_secret = plain_secret_aligned;
}
token_info->token = malloc(token_info->token_length); memset(plain_secret, 0, token_secret_length);
furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, iv);
furi_hal_crypto_encrypt(plain_secret, token_info->token, token_info->token_length);
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
memset(plain_secret, 0, token_info->token_length);
free(plain_secret); free(plain_secret);
} }