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