From 31e328768e5c0ff72098fbb78a1defcd40638a2a Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 20 Mar 2020 04:19:25 +0100 Subject: [PATCH] implemented secure api for configuring wallets data --- src/common/config_encrypt_helper.h | 66 +++++++++++++ src/gui/qt-daemon/application/mainwindow.cpp | 94 +++++++------------ src/gui/qt-daemon/application/mainwindow.h | 9 +- src/wallet/plain_wallet_api.cpp | 40 +++++--- src/wallet/plain_wallet_api.h | 5 +- src/wallet/view_iface.h | 1 + .../core_concurrency_test.cpp | 6 +- tests/functional_tests/plain_wallet_tests.cpp | 15 ++- 8 files changed, 150 insertions(+), 86 deletions(-) create mode 100644 src/common/config_encrypt_helper.h diff --git a/src/common/config_encrypt_helper.h b/src/common/config_encrypt_helper.h new file mode 100644 index 00000000..c2208c79 --- /dev/null +++ b/src/common/config_encrypt_helper.h @@ -0,0 +1,66 @@ +// Copyright (c) 2014-2020 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include "wallet/view_iface.h" + + +namespace tools +{ + +#pragma pack(push, 1) + struct app_data_file_binary_header + { + uint64_t m_signature; + uint64_t m_cb_body; + }; +#pragma pack (pop) + + inline + std::string load_encrypted_file(const std::string& path, const std::string& key, std::string& body, uint64_t signature) + { + std::string app_data_buff; + bool r = epee::file_io_utils::load_file_to_string(path, app_data_buff); + if (!r) + { + return API_RETURN_CODE_NOT_FOUND; + } + + if (app_data_buff.size() < sizeof(app_data_file_binary_header)) + { + LOG_ERROR("app_data_buff.size()(" << app_data_buff.size() << ") < sizeof(app_data_file_binary_header) (" << sizeof(app_data_file_binary_header) << ") check failed while loading from " << path); + return API_RETURN_CODE_INVALID_FILE; + } + + crypto::chacha_crypt(app_data_buff, key); + + const app_data_file_binary_header* phdr = reinterpret_cast(app_data_buff.data()); + if (phdr->m_signature != signature) + { + return API_RETURN_CODE_WRONG_PASSWORD; + } + body = app_data_buff.substr(sizeof(app_data_file_binary_header)).c_str(); + return API_RETURN_CODE_OK; + } + inline + std::string store_encrypted_file(const std::string& path, const std::string& key, const std::string& body, uint64_t signature) + { + std::string buff(sizeof(app_data_file_binary_header), 0); + app_data_file_binary_header* phdr = (app_data_file_binary_header*)buff.data(); + phdr->m_signature = signature; + phdr->m_cb_body = 0; // for future use + + buff.append(body); + crypto::chacha_crypt(buff, key); + + bool r = epee::file_io_utils::save_string_to_file(path, buff); + if (r) + return API_RETURN_CODE_OK; + else + return API_RETURN_CODE_FAIL; + } + +} \ No newline at end of file diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index 5d0a148c..6da2ec90 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -12,6 +12,7 @@ #include "string_coding.h" #include "gui_utils.h" #include "notification_helper.h" +#include "common/config_encrypt_helper.h" #define PREPARE_ARG_FROM_JSON(arg_type, var_name) \ arg_type var_name = AUTO_VAL_INIT(var_name); \ @@ -1047,6 +1048,35 @@ void MainWindow::on_clear_events() CATCH_ENTRY2(void()); } + +QString MainWindow::store_secure_app_data(const QString& param) +{ + TRY_ENTRY(); + LOG_API_TIMING(); + if (!tools::create_directories_if_necessary(m_backend.get_config_folder())) + { + view::api_response ar; + LOG_PRINT_L0("Failed to create data directory: " << m_backend.get_config_folder()); + ar.error_code = API_RETURN_CODE_FAIL; + return MAKE_RESPONSE(ar); + } + + view::api_response ar = AUTO_VAL_INIT(ar); + ar.error_code = tools::store_encrypted_file(m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME, + m_master_password, param.toStdString(), APP_DATA_FILE_BINARY_SIGNATURE); + if (ar.error_code != API_RETURN_CODE_OK) + { + return MAKE_RESPONSE(ar); + } + + crypto::hash master_password_pre_hash = crypto::cn_fast_hash(m_master_password.c_str(), m_master_password.length()); + crypto::hash master_password_hash = crypto::cn_fast_hash(&master_password_pre_hash, sizeof master_password_pre_hash); + LOG_PRINT_L0("store_secure_app_data, r = " << ar.error_code << ", pass hash: " << master_password_hash); + + return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); +} + QString MainWindow::get_secure_app_data(const QString& param) { TRY_ENTRY(); @@ -1060,41 +1090,21 @@ QString MainWindow::get_secure_app_data(const QString& param) return MAKE_RESPONSE(ar); } - std::string app_data_buff; std::string filename = m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME; - bool r = file_io_utils::load_file_to_string(filename, app_data_buff); - if (!r) + std::string res_body; + std::string rsp_code = tools::load_encrypted_file(filename, pwd.pass, res_body, APP_DATA_FILE_BINARY_SIGNATURE); + if (rsp_code != API_RETURN_CODE_OK) { - LOG_PRINT_L1("gui secure config was not loaded from " << filename); - return ""; - } - - if (app_data_buff.size() < sizeof(app_data_file_binary_header)) - { - LOG_ERROR("app_data_buff.size() < sizeof(app_data_file_binary_header) check failed while loading from " << filename); view::api_response ar; - ar.error_code = API_RETURN_CODE_FAIL; + ar.error_code = rsp_code; return MAKE_RESPONSE(ar); } - - crypto::chacha_crypt(app_data_buff, pwd.pass); - - const app_data_file_binary_header* phdr = reinterpret_cast(app_data_buff.data()); - if (phdr->m_signature != APP_DATA_FILE_BINARY_SIGNATURE) - { - LOG_ERROR("gui secure config: password missmatch while loading from " << filename); - view::api_response ar; - ar.error_code = API_RETURN_CODE_WRONG_PASSWORD; - return MAKE_RESPONSE(ar); - } - m_master_password = pwd.pass; - crypto::hash master_password_pre_hash = crypto::cn_fast_hash(m_master_password.c_str(), m_master_password.length()); crypto::hash master_password_hash = crypto::cn_fast_hash(&master_password_pre_hash, sizeof master_password_pre_hash); LOG_PRINT_L0("gui secure config loaded ok from " << filename << ", pass hash: " << master_password_hash); - return app_data_buff.substr(sizeof(app_data_file_binary_header)).c_str(); + return res_body.c_str(); CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } @@ -1267,40 +1277,6 @@ QString MainWindow::get_app_data() CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } -QString MainWindow::store_secure_app_data(const QString& param) -{ - TRY_ENTRY(); - LOG_API_TIMING(); - if (!tools::create_directories_if_necessary(m_backend.get_config_folder())) - { - view::api_response ar; - LOG_PRINT_L0("Failed to create data directory: " << m_backend.get_config_folder()); - return MAKE_RESPONSE(ar); - } - - - std::string buff(sizeof(app_data_file_binary_header), 0); - app_data_file_binary_header* phdr = (app_data_file_binary_header*)buff.data(); - phdr->m_signature = APP_DATA_FILE_BINARY_SIGNATURE; - phdr->m_cb_body = 0; // for future use - - buff.append(param.toStdString()); - crypto::chacha_crypt(buff, m_master_password); - - bool r = file_io_utils::save_string_to_file(m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME, buff); - view::api_response ar; - if (r) - ar.error_code = API_RETURN_CODE_OK; - else - ar.error_code = API_RETURN_CODE_FAIL; - - crypto::hash master_password_pre_hash = crypto::cn_fast_hash(m_master_password.c_str(), m_master_password.length()); - crypto::hash master_password_hash = crypto::cn_fast_hash(&master_password_pre_hash, sizeof master_password_pre_hash); - LOG_PRINT_L0("store_secure_app_data, r = " << r << ", pass hash: " << master_password_hash); - - return MAKE_RESPONSE(ar); - CATCH_ENTRY_FAIL_API_RESPONCE(); -} QString MainWindow::have_secure_app_data() { diff --git a/src/gui/qt-daemon/application/mainwindow.h b/src/gui/qt-daemon/application/mainwindow.h index 2acdd34f..4ea84e1d 100644 --- a/src/gui/qt-daemon/application/mainwindow.h +++ b/src/gui/qt-daemon/application/mainwindow.h @@ -8,6 +8,7 @@ #include #include "wallet/view_iface.h" + #ifndef Q_MOC_RUN #include "wallet/wallets_manager.h" #include "currency_core/offers_services_helpers.h" @@ -18,13 +19,7 @@ class QWebEngineView; class QLineEdit; QT_END_NAMESPACE -#pragma pack(push, 1) -struct app_data_file_binary_header -{ - uint64_t m_signature; - uint64_t m_cb_body; -}; -#pragma pack (pop) + #define APP_DATA_FILE_BINARY_SIGNATURE 0x1000111101101021LL diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 486778f3..c76ef533 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -11,6 +11,8 @@ #include "string_tools.h" #include "currency_core/currency_format_utils.h" #include "wallets_manager.h" +#include "common/base58.h" +#include "common/config_encrypt_helper.h" #define ANDROID_PACKAGE_NAME "com.zano_mobile" #ifdef IOS_BUILD @@ -22,7 +24,9 @@ #endif #define WALLETS_FOLDER_NAME "wallets" #define APP_CONFIG_FOLDER "app_config" -#define APP_CONFIG_FILENAME "app_cfg.json" +#define APP_CONFIG_FILENAME "app_cfg.bin" + +#define MOBILE_APP_DATA_FILE_BINARY_SIGNATURE 0x1000111201101011LL //Bender's nightmare #define GENERAL_INTERNAL_ERRROR_INSTANCE "GENERAL_INTERNAL_ERROR: WALLET INSTNACE NOT FOUND" #define GENERAL_INTERNAL_ERRROR_INIT "Failed to intialize library" @@ -155,20 +159,27 @@ namespace plain_wallet return epee::serialization::store_t_to_json(ok_response); } - std::string get_appconfig() + std::string get_appconfig(const std::string& encryption_key) { - std::string res_str = "{}"; + std::string res_str; std::string app_config_config_path = get_app_config_folder() + APP_CONFIG_FILENAME; - epee::file_io_utils::load_file_to_string(app_config_config_path, res_str); - return res_str; - } - std::string set_appconfig(const std::string& conf_str) - { - std::string app_config_config_path = get_app_config_folder() + APP_CONFIG_FILENAME; - if (!epee::file_io_utils::save_string_to_file(app_config_config_path, conf_str)) + std::string ret_code = tools::load_encrypted_file(app_config_config_path, encryption_key, res_str, MOBILE_APP_DATA_FILE_BINARY_SIGNATURE); + if (ret_code != API_RETURN_CODE_OK) { error_response err_result = AUTO_VAL_INIT(err_result); - err_result.error.code = API_RETURN_CODE_NOT_FOUND; + err_result.error.code = ret_code; + return epee::serialization::store_t_to_json(err_result); + } + return res_str; + } + std::string set_appconfig(const std::string& conf_str, const std::string& encryption_key) + { + std::string app_config_config_path = get_app_config_folder() + APP_CONFIG_FILENAME; + std::string ret_code = tools::store_encrypted_file(app_config_config_path, encryption_key, conf_str, MOBILE_APP_DATA_FILE_BINARY_SIGNATURE); + if (ret_code != API_RETURN_CODE_OK) + { + error_response err_result = AUTO_VAL_INIT(err_result); + err_result.error.code = ret_code; return epee::serialization::store_t_to_json(err_result); } else @@ -177,7 +188,14 @@ namespace plain_wallet ok_response.result.return_code = API_RETURN_CODE_OK; return epee::serialization::store_t_to_json(ok_response); } + } + std::string generate_random_key(uint64_t lenght) + { + std::string buff; + buff.resize(lenght); + crypto::generate_random_bytes(lenght, const_cast(buff.data())); + return tools::base58::encode(buff); } std::string get_logs_buffer() diff --git a/src/wallet/plain_wallet_api.h b/src/wallet/plain_wallet_api.h index 5f05e8b7..45abefde 100644 --- a/src/wallet/plain_wallet_api.h +++ b/src/wallet/plain_wallet_api.h @@ -15,8 +15,9 @@ namespace plain_wallet std::string get_version(); std::string get_wallet_files(); - std::string get_appconfig(); - std::string set_appconfig(const std::string& conf_str); + std::string get_appconfig(const std::string& encryption_key); + std::string set_appconfig(const std::string& conf_str, const std::string& encryption_key); + std::string generate_random_key(uint64_t lenght); std::string get_logs_buffer(); std::string truncate_log(); diff --git a/src/wallet/view_iface.h b/src/wallet/view_iface.h index a08996e2..5d6f4aea 100644 --- a/src/wallet/view_iface.h +++ b/src/wallet/view_iface.h @@ -779,6 +779,7 @@ public: #define API_RETURN_CODE_CORE_BUSY "CORE_BUSY" #define API_RETURN_CODE_OVERFLOW "OVERFLOW" #define API_RETURN_CODE_BUSY "BUSY" +#define API_RETURN_CODE_INVALID_FILE "INVALID_FILE" #define API_MAX_ALIASES_COUNT 10000 diff --git a/tests/functional_tests/core_concurrency_test.cpp b/tests/functional_tests/core_concurrency_test.cpp index 55c4bdeb..52ff1b8c 100644 --- a/tests/functional_tests/core_concurrency_test.cpp +++ b/tests/functional_tests/core_concurrency_test.cpp @@ -461,8 +461,7 @@ bool core_concurrency_test(boost::program_options::variables_map& vm, size_t wth test_protocol_handler protocol_handler(c, core_listener.get()); c.set_currency_protocol(&protocol_handler); - tools::db::db_backend_selector dbbs; - if (!c.init(vm, dbbs)) + if (!c.init(vm)) { LOG_ERROR("Failed to init core"); return false; @@ -528,8 +527,7 @@ bool core_concurrency_test(boost::program_options::variables_map& vm, size_t wth test_protocol_handler protocol_handler(c, core_listener.get()); c.set_currency_protocol(&protocol_handler); - tools::db::db_backend_selector dbbs; - if (!c.init(vm, dbbs)) + if (!c.init(vm)) { LOG_ERROR("Failed to init core"); return false; diff --git a/tests/functional_tests/plain_wallet_tests.cpp b/tests/functional_tests/plain_wallet_tests.cpp index ea932417..00f1047d 100644 --- a/tests/functional_tests/plain_wallet_tests.cpp +++ b/tests/functional_tests/plain_wallet_tests.cpp @@ -32,9 +32,18 @@ void run_plain_wallet_api_test() LOG_PRINT_L0("Creating instance..."); std::string s = plain_wallet::init("195.201.107.230", "11211", 1); - std::string fres = plain_wallet::get_logs_buffer(); - std::string fres2 = plain_wallet::truncate_log(); - std::string fres3 = plain_wallet::get_logs_buffer(); + std::string key = plain_wallet::generate_random_key(10); + std::string test_data = "1234567890 test test "; + std::string res = plain_wallet::set_appconfig(test_data, key); + std::string test_data2 = plain_wallet::get_appconfig(key); + if (test_data2 != test_data) + { + LOG_ERROR("Error"); + } + return; + //std::string fres = plain_wallet::get_logs_buffer(); + //std::string fres2 = plain_wallet::truncate_log(); + //std::string fres3 = plain_wallet::get_logs_buffer();