Implement secure key via KDF for transparent data encryption/decryption #60
This commit is contained in:
		| @@ -50,9 +50,11 @@ public: | ||||
|  | ||||
| private: | ||||
|   s3_config s3_config_; | ||||
|  | ||||
| private: | ||||
|   bool legacy_bucket_{true}; | ||||
|   utils::encryption::kdf_config master_kdf_cfg_; | ||||
|   utils::hash::hash_256_t master_key_; | ||||
|   utils::encryption::kdf_config master_kdf_cfg_{}; | ||||
|   utils::hash::hash_256_t master_key_{}; | ||||
|  | ||||
| private: | ||||
|   [[nodiscard]] auto add_if_not_found(api_file &file, | ||||
| @@ -71,8 +73,8 @@ private: | ||||
|                                        api_meta_map &meta) | ||||
|       -> api_error override; | ||||
|  | ||||
|   [[nodiscard]] auto decrypt_object_name(std::string &object_name, | ||||
|                                          bool &uses_kdf) const -> api_error; | ||||
|   [[nodiscard]] auto decrypt_object_name(std::string &object_name) const | ||||
|       -> api_error; | ||||
|  | ||||
|   [[nodiscard]] auto get_last_modified(bool directory, | ||||
|                                        const std::string &api_path, | ||||
| @@ -95,11 +97,6 @@ private: | ||||
|     return s3_config_; | ||||
|   } | ||||
|  | ||||
|   [[nodiscard]] auto read_file_bytes(const std::string &api_path, | ||||
|                                      std::size_t size, std::uint64_t offset, | ||||
|                                      data_buffer &data, bool encrypted, | ||||
|                                      stop_type &stop_requested) -> api_error; | ||||
|  | ||||
|   [[nodiscard]] auto search_keys_for_kdf(std::string_view encryption_token) | ||||
|       -> bool; | ||||
|  | ||||
|   | ||||
| @@ -32,6 +32,7 @@ | ||||
| #include "types/repertory.hpp" | ||||
| #include "types/s3.hpp" | ||||
| #include "utils/collection.hpp" | ||||
| #include "utils/common.hpp" | ||||
| #include "utils/config.hpp" | ||||
| #include "utils/encrypting_reader.hpp" | ||||
| #include "utils/encryption.hpp" | ||||
| @@ -240,8 +241,16 @@ auto s3_provider::create_file_extra(const std::string &api_path, | ||||
|  | ||||
| auto s3_provider::decrypt_object_name(std::string &object_name) const | ||||
|     -> api_error { | ||||
|   if (utils::encryption::decrypt_file_path(get_s3_config().encryption_token, | ||||
|                                            object_name)) { | ||||
|   if (legacy_bucket_) { | ||||
|     if (utils::encryption::decrypt_file_path(get_s3_config().encryption_token, | ||||
|                                              object_name)) { | ||||
|       return api_error::success; | ||||
|     } | ||||
|  | ||||
|     return api_error::decryption_error; | ||||
|   } | ||||
|  | ||||
|   if (utils::encryption::decrypt_file_path(master_key_, object_name)) { | ||||
|     return api_error::success; | ||||
|   } | ||||
|  | ||||
| @@ -278,8 +287,7 @@ auto s3_provider::get_directory_item_count(const std::string &api_path) const | ||||
|     std::string token{}; | ||||
|     std::uint64_t total_count{}; | ||||
|     while (grab_more) { | ||||
|       if (not get_object_list(response_data, response_code, "/", prefix, | ||||
|                               token)) { | ||||
|       if (not get_object_list(response_data, response_code, "/", "", token)) { | ||||
|         return total_count; | ||||
|       } | ||||
|  | ||||
| @@ -936,7 +944,7 @@ auto s3_provider::search_keys_for_kdf(std::string_view encryption_token) | ||||
|   while (grab_more) { | ||||
|     std::string response_data{}; | ||||
|     long response_code{}; | ||||
|     if (not get_object_list(response_data, response_code, "/", prefix, token)) { | ||||
|     if (not get_object_list(response_data, response_code, "/", "", token)) { | ||||
|       throw utils::error::create_exception(function_name, | ||||
|                                            {"failed to get object list"}); | ||||
|     } | ||||
| @@ -969,12 +977,12 @@ auto s3_provider::search_keys_for_kdf(std::string_view encryption_token) | ||||
|                   .as_string(); | ||||
|     } | ||||
|  | ||||
|     node_list = doc.select_nodes("/ListBucketResult/Contents"); | ||||
|     auto node_list = doc.select_nodes("/ListBucketResult/Contents"); | ||||
|     for (const auto &node : node_list) { | ||||
|       auto object_name{ | ||||
|               node.node().select_node("Key").node().text().as_string()), | ||||
|       std::string object_name{ | ||||
|           node.node().select_node("Key").node().text().as_string(), | ||||
|       }; | ||||
|       if (object_name == "/")) { | ||||
|       if (object_name == "/") { | ||||
|         continue; | ||||
|       } | ||||
|  | ||||
| @@ -983,8 +991,8 @@ auto s3_provider::search_keys_for_kdf(std::string_view encryption_token) | ||||
|         continue; | ||||
|       } | ||||
|  | ||||
|       kdf_config cfg; | ||||
|       if (not kdf_config::from_header(buffer, cfg)) { | ||||
|       utils::encryption::kdf_config cfg; | ||||
|       if (not utils::encryption::kdf_config::from_header(buffer, cfg)) { | ||||
|         continue; | ||||
|       } | ||||
|  | ||||
| @@ -1040,13 +1048,15 @@ auto s3_provider::set_meta_key(const std::string &api_path, api_meta_map &meta) | ||||
|         cfg.encryption_token, | ||||
|         *(utils::string::split(api_path, '/', false).end() - 1U), result); | ||||
|   } else { | ||||
|     auto [key, cfg] = master_kdf_cfg_.create_subkey( | ||||
|         utils::encryption::kdf_context::path, id, master_key_); | ||||
|     auto [path_key, path_cfg] = master_kdf_cfg_.create_subkey( | ||||
|         utils::encryption::kdf_context::path, | ||||
|         utils::generate_secure_random<std::uint64_t>(), master_key_); | ||||
|  | ||||
|     utils::encryption::encrypt_data( | ||||
|         key, *(utils::string::split(api_path, '/', false).end() - 1U), result); | ||||
|         path_key, *(utils::string::split(api_path, '/', false).end() - 1U), | ||||
|         result); | ||||
|  | ||||
|     auto hdr = cfg.to_header(); | ||||
|     auto hdr = path_cfg.to_header(); | ||||
|     result.insert(result.begin(), hdr.begin(), hdr.end()); | ||||
|   } | ||||
|  | ||||
| @@ -1070,7 +1080,7 @@ auto s3_provider::start(api_item_added_callback api_item_added, | ||||
|   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; | ||||
|     ret = res == api_error::success; | ||||
|     if (ret) { | ||||
|       if (kdf_str.empty()) { | ||||
|         try { | ||||
| @@ -1082,9 +1092,9 @@ auto s3_provider::start(api_item_added_callback api_item_added, | ||||
|                   utils::encryption::generate_key<utils::hash::hash_256_t>( | ||||
|                       cfg.encryption_token, master_kdf_cfg_); | ||||
|  | ||||
|               auto res = set_item_meta("/", META_KDF, | ||||
|                                        nlohmann::json(master_kdf_cfg_).dump()); | ||||
|               ret == res == api_error::success; | ||||
|               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"); | ||||
| @@ -1212,19 +1222,11 @@ auto s3_provider::upload_file_impl(const std::string &api_path, | ||||
| auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size, | ||||
|                                   std::uint64_t offset, data_buffer &data, | ||||
|                                   stop_type &stop_requested) -> api_error { | ||||
|   return read_file_bytes(api_path, size, offset, data, | ||||
|                          not get_s3_config().encryption_token.empty(), | ||||
|                          stop_requested); | ||||
| } | ||||
|  | ||||
| auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size, | ||||
|                                   std::uint64_t offset, data_buffer &data, | ||||
|                                   bool encrypted, stop_type &stop_requested) | ||||
|     -> api_error { | ||||
|   REPERTORY_USES_FUNCTION_NAME(); | ||||
|  | ||||
|   try { | ||||
|     const auto &cfg{get_s3_config()}; | ||||
|     bool encrypted{not cfg.encryption_token.empty()}; | ||||
|  | ||||
|     std::string key; | ||||
|     if (encrypted) { | ||||
| @@ -1313,9 +1315,9 @@ auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size, | ||||
|       return res; | ||||
|     } | ||||
|  | ||||
|     utils::hash::hash_256_t key; | ||||
|     utils::hash::hash_256_t data_key; | ||||
|     if (legacy_bucket_) { | ||||
|       key = utils::encryption::generate_key<utils::hash::hash_256_t>( | ||||
|       data_key = utils::encryption::generate_key<utils::hash::hash_256_t>( | ||||
|           cfg.encryption_token); | ||||
|     } else { | ||||
|       res = get_item_meta(api_path, META_KDF, temp); | ||||
| @@ -1323,19 +1325,15 @@ auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size, | ||||
|         return res; | ||||
|       } | ||||
|  | ||||
|       if (not utils::encryption::recreate_key_argon2id( | ||||
|               cfg.encryption_token, | ||||
|               nlohmann::json::parse(temp).get<utils::encryption::kdf_config>(), | ||||
|               key)) { | ||||
|         throw utils::error::create_exception( | ||||
|             function_name, {"failed to recreate data key from kdf"}); | ||||
|         return api_error::error; | ||||
|       } | ||||
|       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)}; | ||||
|     return utils::encryption::read_encrypted_range( | ||||
|                {.begin = offset, .end = offset + size - 1U}, key, | ||||
|                {.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 { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user