diff --git a/repertory/librepertory/include/providers/s3/s3_provider.hpp b/repertory/librepertory/include/providers/s3/s3_provider.hpp index b239b730..c33728f5 100644 --- a/repertory/librepertory/include/providers/s3/s3_provider.hpp +++ b/repertory/librepertory/include/providers/s3/s3_provider.hpp @@ -76,6 +76,11 @@ private: [[nodiscard]] auto decrypt_object_name(std::string &object_name) const -> api_error; + [[nodiscard]] auto + get_kdf_config_from_meta(const std::string &api_path, + utils::encryption::kdf_config &cfg) const + -> api_error; + [[nodiscard]] auto get_last_modified(bool directory, const std::string &api_path, std::uint64_t &last_modified) const diff --git a/repertory/librepertory/src/providers/s3/s3_provider.cpp b/repertory/librepertory/src/providers/s3/s3_provider.cpp index d734c849..1b652c23 100644 --- a/repertory/librepertory/src/providers/s3/s3_provider.cpp +++ b/repertory/librepertory/src/providers/s3/s3_provider.cpp @@ -640,6 +640,23 @@ auto s3_provider::get_file_list(api_file_list &list, std::string &marker) const return api_error::error; } +auto s3_provider::get_kdf_config_from_meta( + const std::string &api_path, utils::encryption::kdf_config &cfg) const + -> api_error { + std::string kdf_str; + auto ret = get_item_meta(api_path, META_KDF, kdf_str); + if (ret != api_error::success) { + return ret; + } + + if (kdf_str.empty()) { + return api_error::item_not_found; + } + + cfg = nlohmann::json::parse(kdf_str).get(); + return api_error::success; +} + auto s3_provider::get_last_modified(bool directory, const std::string &api_path, std::uint64_t &last_modified) const -> api_error { @@ -1078,46 +1095,47 @@ auto s3_provider::start(api_item_added_callback api_item_added, auto ret = base_provider::start(api_item_added, mgr); if (ret && not cfg.encryption_token.empty()) { - std::string kdf_str; - auto res = get_item_meta("/", META_KDF, kdf_str); - ret = res == api_error::success; - if (ret) { - if (kdf_str.empty()) { - try { - if (not search_keys_for_kdf(cfg.encryption_token)) { - if (get_directory_item_count("/") == 0U) { - legacy_bucket_ = false; - master_kdf_cfg_.seal(); - master_key_ = - utils::encryption::generate_key( - cfg.encryption_token, master_kdf_cfg_); + auto res = get_kdf_config_from_meta("/", master_kdf_cfg_); + switch (res) { + case api_error::item_not_found: { + try { + if (not search_keys_for_kdf(cfg.encryption_token)) { + if (get_directory_item_count("/") == 0U) { + legacy_bucket_ = false; + master_kdf_cfg_.seal(); + master_key_ = + utils::encryption::generate_key( + cfg.encryption_token, master_kdf_cfg_); - res = set_item_meta("/", META_KDF, - nlohmann::json(master_kdf_cfg_).dump()); - ret = res == api_error::success; - if (not ret) { - utils::error::raise_api_path_error(function_name, "/", res, - "set kdf in meta failed"); - } + res = set_item_meta("/", META_KDF, + nlohmann::json(master_kdf_cfg_).dump()); + if (res != api_error::success) { + utils::error::raise_api_path_error(function_name, "/", res, + "set kdf in meta failed"); + ret = false; } } - } catch (const std::exception &e) { - utils::error::raise_error(function_name, e, "exception occurred"); - ret = false; - } - } else { - master_kdf_cfg_ = - nlohmann::json::parse(kdf_str).get(); - if (not utils::encryption::recreate_key_argon2id( - cfg.encryption_token, master_kdf_cfg_, master_key_)) { - ret = false; - utils::error::raise_error(function_name, - "failed to recreate master key from kdf"); } + } catch (const std::exception &e) { + utils::error::raise_error(function_name, e, "exception occurred"); + ret = false; } - } else { + } break; + + case api_error::success: { + if (not utils::encryption::recreate_key_argon2id( + cfg.encryption_token, master_kdf_cfg_, master_key_)) { + utils::error::raise_error(function_name, + "failed to recreate master key from kdf"); + ret = false; + } + } break; + + default: { utils::error::raise_api_path_error(function_name, "/", res, "get kdf from meta failed"); + ret = false; + } } if (not ret) { @@ -1226,10 +1244,10 @@ auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size, try { const auto &cfg{get_s3_config()}; - bool encrypted{not cfg.encryption_token.empty()}; + bool is_encrypted{not cfg.encryption_token.empty()}; std::string key; - if (encrypted) { + if (is_encrypted) { auto res{get_item_meta(api_path, META_KEY, key)}; if (res != api_error::success) { return res; @@ -1237,7 +1255,7 @@ auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size, } auto object_name{ - utils::path::create_api_path(encrypted ? key : api_path), + utils::path::create_api_path(is_encrypted ? key : api_path), }; const auto read_bytes = @@ -1305,14 +1323,14 @@ auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size, return res; }; - if (not encrypted) { + if (not is_encrypted) { return read_bytes(size, offset, data); } - std::string temp; - auto res{get_item_meta(api_path, META_SIZE, temp)}; - if (res != api_error::success) { - return res; + std::string size_str; + auto ret{get_item_meta(api_path, META_SIZE, size_str)}; + if (ret != api_error::success) { + return ret; } utils::hash::hash_256_t data_key; @@ -1320,21 +1338,23 @@ auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size, data_key = utils::encryption::generate_key( cfg.encryption_token); } else { - res = get_item_meta(api_path, META_KDF, temp); - if (res != api_error::success) { - return res; + utils::encryption::kdf_config data_cfg; + ret = get_kdf_config_from_meta(api_path, data_cfg); + if (ret != api_error::success) { + return ret; } - auto data_cfg = - nlohmann::json::parse(temp).get(); data_key = data_cfg.recreate_subkey(utils::encryption::kdf_context::data, master_key_); } - auto total_size{utils::string::to_uint64(temp)}; + auto total_size{utils::string::to_uint64(size_str)}; return utils::encryption::read_encrypted_range( - {.begin = offset, .end = offset + size - 1U}, data_key, - not legacy_bucket_, + { + .begin = offset, + .end = offset + size - 1U, + }, + data_key, not legacy_bucket_, [&](data_buffer &ct_buffer, std::uint64_t start_offset, std::uint64_t end_offset) -> bool { return read_bytes((end_offset - start_offset + 1U), diff --git a/support/include/utils/encryption.hpp b/support/include/utils/encryption.hpp index dd80e5a7..41cc015e 100644 --- a/support/include/utils/encryption.hpp +++ b/support/include/utils/encryption.hpp @@ -133,10 +133,20 @@ struct kdf_config final { [[nodiscard]] auto create_subkey(kdf_context ctx, std::size_t unique_id_, const hash_t &master_key) const -> std::pair { + REPERTORY_USES_FUNCTION_NAME(); + hash_t sub_key; - crypto_kdf_derive_from_key(sub_key.data(), sub_key.size(), unique_id_, - get_kdf_context_name(ctx).data(), - master_key.data()); + auto res = crypto_kdf_derive_from_key( + sub_key.data(), sub_key.size(), unique_id_, + get_kdf_context_name(ctx).data(), master_key.data()); + if (res != 0) { + throw repertory::utils::error::create_exception( + function_name, { + "failed to create sub-key", + std::to_string(res), + }); + } + auto cfg = *this; cfg.unique_id = unique_id_; cfg.checksum = cfg.generate_checksum(); @@ -146,10 +156,20 @@ struct kdf_config final { template [[nodiscard]] auto recreate_subkey(kdf_context ctx, const hash_t &master_key) const -> hash_t { + REPERTORY_USES_FUNCTION_NAME(); + hash_t sub_key; - crypto_kdf_derive_from_key(sub_key.data(), sub_key.size(), unique_id, - get_kdf_context_name(ctx).data(), - master_key.data()); + auto res = crypto_kdf_derive_from_key( + sub_key.data(), sub_key.size(), unique_id, + get_kdf_context_name(ctx).data(), master_key.data()); + if (res != 0) { + throw repertory::utils::error::create_exception( + function_name, { + "failed to recreate sub-key", + std::to_string(res), + }); + } + return sub_key; } diff --git a/support/include/utils/file.hpp b/support/include/utils/file.hpp index d0993ef3..104593d0 100644 --- a/support/include/utils/file.hpp +++ b/support/include/utils/file.hpp @@ -41,13 +41,13 @@ namespace repertory::utils::file { [[nodiscard]] auto create_temp_name(std::string_view file_part) -> std::string; // INFO: has test -[[nodiscard]] auto -create_temp_name(std::wstring_view file_part) -> std::wstring; +[[nodiscard]] auto create_temp_name(std::wstring_view file_part) + -> std::wstring; // INFO: has test [[nodiscard]] inline auto -directory_exists_in_path(std::string_view path, - std::string_view sub_directory) -> bool; +directory_exists_in_path(std::string_view path, std::string_view sub_directory) + -> bool; // INFO: has test [[nodiscard]] inline auto @@ -55,45 +55,46 @@ directory_exists_in_path(std::wstring_view path, std::wstring_view sub_directory) -> bool; // INFO: has test -[[nodiscard]] inline auto -file_exists_in_path(std::string_view path, std::string_view file_name) -> bool; +[[nodiscard]] inline auto file_exists_in_path(std::string_view path, + std::string_view file_name) + -> bool; // INFO: has test -[[nodiscard]] inline auto -file_exists_in_path(std::wstring_view path, - std::wstring_view file_name) -> bool; +[[nodiscard]] inline auto file_exists_in_path(std::wstring_view path, + std::wstring_view file_name) + -> bool; // INFO: has test -[[nodiscard]] auto -get_free_drive_space(std::string_view path) -> std::optional; +[[nodiscard]] auto get_free_drive_space(std::string_view path) + -> std::optional; // INFO: has test -[[nodiscard]] auto -get_free_drive_space(std::wstring_view path) -> std::optional; +[[nodiscard]] auto get_free_drive_space(std::wstring_view path) + -> std::optional; // INFO: has test -[[nodiscard]] auto get_time(std::string_view path, - time_type type) -> std::optional; +[[nodiscard]] auto get_time(std::string_view path, time_type type) + -> std::optional; // INFO: has test -[[nodiscard]] auto get_time(std::wstring_view path, - time_type type) -> std::optional; +[[nodiscard]] auto get_time(std::wstring_view path, time_type type) + -> std::optional; // INFO: has test -[[nodiscard]] auto -get_times(std::string_view path) -> std::optional; +[[nodiscard]] auto get_times(std::string_view path) + -> std::optional; // INFO: has test -[[nodiscard]] auto -get_times(std::wstring_view path) -> std::optional; +[[nodiscard]] auto get_times(std::wstring_view path) + -> std::optional; // INFO: has test -[[nodiscard]] auto -get_total_drive_space(std::string_view path) -> std::optional; +[[nodiscard]] auto get_total_drive_space(std::string_view path) + -> std::optional; // INFO: has test -[[nodiscard]] auto -get_total_drive_space(std::wstring_view path) -> std::optional; +[[nodiscard]] auto get_total_drive_space(std::wstring_view path) + -> std::optional; #if defined(PROJECT_ENABLE_LIBDSM) [[nodiscard]] auto @@ -101,20 +102,20 @@ smb_create_and_validate_relative_path(std::string_view smb_path, std::string_view rel_path) -> std::string; // INFO: has test -[[nodiscard]] auto -smb_create_relative_path(std::string_view smb_path) -> std::string; +[[nodiscard]] auto smb_create_relative_path(std::string_view smb_path) + -> std::string; // INFO: has test -[[nodiscard]] auto -smb_create_search_path(std::string_view smb_path) -> std::string; +[[nodiscard]] auto smb_create_search_path(std::string_view smb_path) + -> std::string; // INFO: has test -[[nodiscard]] auto -smb_create_smb_path(std::string_view smb_path, - std::string_view rel_path) -> std::string; +[[nodiscard]] auto smb_create_smb_path(std::string_view smb_path, + std::string_view rel_path) + -> std::string; -[[nodiscard]] auto -smb_get_parent_path(std::string_view smb_path) -> std::string; +[[nodiscard]] auto smb_get_parent_path(std::string_view smb_path) + -> std::string; [[nodiscard]] auto smb_get_root_path(std::string_view smb_path) -> std::string; @@ -143,27 +144,30 @@ read_json_file(std::string_view path, nlohmann::json &data, std::optional password = std::nullopt) -> bool; // INFO: has test -[[nodiscard]] auto read_json_file( - std::wstring_view path, nlohmann::json &data, - std::optional password = std::nullopt) -> bool; +[[nodiscard]] auto +read_json_file(std::wstring_view path, nlohmann::json &data, + std::optional password = std::nullopt) + -> bool; // INFO: has test -[[nodiscard]] auto write_json_file( - std::string_view path, const nlohmann::json &data, - std::optional password = std::nullopt) -> bool; +[[nodiscard]] auto +write_json_file(std::string_view path, const nlohmann::json &data, + std::optional password = std::nullopt) + -> bool; // INFO: has test -[[nodiscard]] auto write_json_file( - std::wstring_view path, const nlohmann::json &data, - std::optional password = std::nullopt) -> bool; +[[nodiscard]] auto +write_json_file(std::wstring_view path, const nlohmann::json &data, + std::optional password = std::nullopt) + -> bool; #else // !defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) // INFO: has test -[[nodiscard]] auto read_json_file(std::string_view path, - nlohmann::json &data) -> bool; +[[nodiscard]] auto read_json_file(std::string_view path, nlohmann::json &data) + -> bool; // INFO: has test -[[nodiscard]] auto read_json_file(std::wstring_view path, - nlohmann::json &data) -> bool; +[[nodiscard]] auto read_json_file(std::wstring_view path, nlohmann::json &data) + -> bool; // INFO: has test [[nodiscard]] auto write_json_file(std::string_view path,