Implement secure key via KDF for transparent data encryption/decryption #60
This commit is contained in:
@@ -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
|
||||
|
@@ -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<utils::encryption::kdf_config>();
|
||||
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<utils::hash::hash_256_t>(
|
||||
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<utils::hash::hash_256_t>(
|
||||
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<utils::encryption::kdf_config>();
|
||||
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<utils::hash::hash_256_t>(
|
||||
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<utils::encryption::kdf_config>();
|
||||
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),
|
||||
|
Reference in New Issue
Block a user