Implement secure key via KDF for transparent data encryption/decryption #60
This commit is contained in:
@@ -102,8 +102,10 @@ private:
|
|||||||
return s3_config_;
|
return s3_config_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto initialize_crypto(const s3_config &cfg) -> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto
|
||||||
search_keys_for_master_kdf(std::string_view encryption_token) -> bool;
|
search_keys_for_master_kdf(const std::string &encryption_token) -> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto set_meta_key(const std::string &api_path,
|
[[nodiscard]] auto set_meta_key(const std::string &api_path,
|
||||||
api_meta_map &meta) -> api_error;
|
api_meta_map &meta) -> api_error;
|
||||||
@@ -177,8 +179,8 @@ public:
|
|||||||
const std::string &to_api_path)
|
const std::string &to_api_path)
|
||||||
-> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto start(api_item_added_callback api_item_added,
|
auto start(api_item_added_callback api_item_added, i_file_manager *mgr)
|
||||||
i_file_manager *mgr) -> bool override;
|
-> bool override;
|
||||||
|
|
||||||
void stop() override;
|
void stop() override;
|
||||||
};
|
};
|
||||||
|
@@ -771,6 +771,69 @@ auto s3_provider::get_total_drive_space() const -> std::uint64_t {
|
|||||||
return std::numeric_limits<std::int64_t>::max() / std::int64_t(2);
|
return std::numeric_limits<std::int64_t>::max() / std::int64_t(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto s3_provider::initialize_crypto(const s3_config &cfg) -> bool {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto ret{true};
|
||||||
|
|
||||||
|
auto res = get_kdf_config_from_meta("/", master_kdf_cfg_);
|
||||||
|
switch (res) {
|
||||||
|
case api_error::item_not_found: {
|
||||||
|
try {
|
||||||
|
event_system::instance().raise<debug_log>(
|
||||||
|
function_name, "searching for master kdf config");
|
||||||
|
if (not search_keys_for_master_kdf(cfg.encryption_token)) {
|
||||||
|
if (get_directory_item_count("/") == 0U) {
|
||||||
|
event_system::instance().raise<debug_log>(
|
||||||
|
function_name, "creating master kdf config for empty bucket");
|
||||||
|
legacy_bucket_ = false;
|
||||||
|
master_kdf_cfg_.seal();
|
||||||
|
master_key_ =
|
||||||
|
utils::encryption::generate_key<utils::hash::hash_256_t>(
|
||||||
|
cfg.encryption_token, master_kdf_cfg_);
|
||||||
|
|
||||||
|
res = set_item_meta("/", META_KDF,
|
||||||
|
nlohmann::json(master_kdf_cfg_).dump());
|
||||||
|
event_system::instance().raise<debug_log>(
|
||||||
|
function_name,
|
||||||
|
fmt::format("master_kdf|{}",
|
||||||
|
nlohmann::json(master_kdf_cfg_).dump(2)));
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(function_name, "/", res,
|
||||||
|
"set kdf config in meta failed");
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
utils::error::raise_error(function_name, e, "exception occurred");
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case api_error::success: {
|
||||||
|
event_system::instance().raise<debug_log>(
|
||||||
|
function_name, "recreating master kdf config for existing bucket");
|
||||||
|
|
||||||
|
legacy_bucket_ = false;
|
||||||
|
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 config");
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
utils::error::raise_api_path_error(function_name, "/", res,
|
||||||
|
"get kdf config from meta failed");
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
auto s3_provider::is_directory(const std::string &api_path, bool &exists) const
|
auto s3_provider::is_directory(const std::string &api_path, bool &exists) const
|
||||||
-> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
@@ -955,8 +1018,8 @@ auto s3_provider::rename_file(const std::string & /* from_api_path */,
|
|||||||
return api_error::not_implemented;
|
return api_error::not_implemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::search_keys_for_master_kdf(std::string_view encryption_token)
|
auto s3_provider::search_keys_for_master_kdf(
|
||||||
-> bool {
|
const std::string &encryption_token) -> bool {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
std::string token{};
|
std::string token{};
|
||||||
@@ -998,30 +1061,34 @@ auto s3_provider::search_keys_for_master_kdf(std::string_view encryption_token)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::encryption::kdf_config cfg;
|
if (not utils::encryption::kdf_config::from_header(buffer,
|
||||||
if (not utils::encryption::kdf_config::from_header(buffer, cfg)) {
|
master_kdf_cfg_)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.unique_id = 0U;
|
master_kdf_cfg_.unique_id = 0U;
|
||||||
cfg.seal();
|
master_kdf_cfg_.seal();
|
||||||
|
|
||||||
master_kdf_cfg_ = cfg;
|
|
||||||
if (not utils::encryption::recreate_key_argon2id(
|
if (not utils::encryption::recreate_key_argon2id(
|
||||||
encryption_token, master_kdf_cfg_, master_key_)) {
|
encryption_token, master_kdf_cfg_, master_key_)) {
|
||||||
throw utils::error::create_exception(
|
throw utils::error::create_exception(
|
||||||
function_name, {"failed to recreate master key from kdf"});
|
function_name, {"failed to recreate master key from kdf config"});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res =
|
auto res =
|
||||||
set_item_meta("/", META_KDF, nlohmann::json(master_kdf_cfg_).dump());
|
set_item_meta("/", META_KDF, nlohmann::json(master_kdf_cfg_).dump());
|
||||||
|
event_system::instance().raise<debug_log>(
|
||||||
|
function_name,
|
||||||
|
fmt::format("master_kdf|{}", nlohmann::json(master_kdf_cfg_).dump(2)));
|
||||||
if (res == api_error::success) {
|
if (res == api_error::success) {
|
||||||
legacy_bucket_ = false;
|
legacy_bucket_ = false;
|
||||||
|
event_system::instance().raise<debug_log>(function_name,
|
||||||
|
"found master kdf config");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw utils::error::create_exception(function_name,
|
throw utils::error::create_exception(function_name,
|
||||||
{"failed to set meta kdf"});
|
{"failed to set meta kdf config"});
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -1081,61 +1148,11 @@ auto s3_provider::start(api_item_added_callback api_item_added,
|
|||||||
event_system::instance().raise<service_start_begin>(function_name,
|
event_system::instance().raise<service_start_begin>(function_name,
|
||||||
"s3_provider");
|
"s3_provider");
|
||||||
|
|
||||||
auto ret = base_provider::start(api_item_added, mgr);
|
|
||||||
const auto &cfg{get_s3_config()};
|
const auto &cfg{get_s3_config()};
|
||||||
|
|
||||||
|
auto ret = base_provider::start(api_item_added, mgr);
|
||||||
if (ret && not cfg.encryption_token.empty()) {
|
if (ret && not cfg.encryption_token.empty()) {
|
||||||
auto res = get_kdf_config_from_meta("/", master_kdf_cfg_);
|
if (not initialize_crypto(cfg)) {
|
||||||
switch (res) {
|
|
||||||
case api_error::item_not_found: {
|
|
||||||
try {
|
|
||||||
event_system::instance().raise<debug_log>(function_name,
|
|
||||||
"searching for master kdf");
|
|
||||||
if (not search_keys_for_master_kdf(cfg.encryption_token)) {
|
|
||||||
if (get_directory_item_count("/") == 0U) {
|
|
||||||
event_system::instance().raise<debug_log>(
|
|
||||||
function_name, "creating master kdf for empty bucket");
|
|
||||||
legacy_bucket_ = false;
|
|
||||||
master_kdf_cfg_.seal();
|
|
||||||
master_key_ =
|
|
||||||
utils::encryption::generate_key<utils::hash::hash_256_t>(
|
|
||||||
cfg.encryption_token, master_kdf_cfg_);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case api_error::success: {
|
|
||||||
event_system::instance().raise<debug_log>(
|
|
||||||
function_name, "recreating master kdf for existing bucket");
|
|
||||||
|
|
||||||
legacy_bucket_ = false;
|
|
||||||
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) {
|
|
||||||
base_provider::stop();
|
base_provider::stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1218,6 +1235,12 @@ auto s3_provider::upload_file_impl(const std::string &api_path,
|
|||||||
res = set_item_meta(
|
res = set_item_meta(
|
||||||
api_path, META_KDF,
|
api_path, META_KDF,
|
||||||
nlohmann::json(*put_file.reader->get_kdf_config_for_data()).dump());
|
nlohmann::json(*put_file.reader->get_kdf_config_for_data()).dump());
|
||||||
|
event_system::instance().raise<debug_log>(
|
||||||
|
function_name,
|
||||||
|
fmt::format(
|
||||||
|
"file_kdf|{}",
|
||||||
|
nlohmann::json(*put_file.reader->get_kdf_config_for_data())
|
||||||
|
.dump(2)));
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user