Implement secure key via KDF for transparent data encryption/decryption #60
This commit is contained in:
		| @@ -102,8 +102,10 @@ private: | ||||
|     return s3_config_; | ||||
|   } | ||||
|  | ||||
|   [[nodiscard]] auto initialize_crypto(const s3_config &cfg) -> bool; | ||||
|  | ||||
|   [[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, | ||||
|                                   api_meta_map &meta) -> api_error; | ||||
| @@ -177,8 +179,8 @@ public: | ||||
|                                  const std::string &to_api_path) | ||||
|       -> api_error override; | ||||
|  | ||||
|   [[nodiscard]] auto start(api_item_added_callback api_item_added, | ||||
|                            i_file_manager *mgr) -> bool override; | ||||
|   auto start(api_item_added_callback api_item_added, i_file_manager *mgr) | ||||
|       -> bool 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); | ||||
| } | ||||
|  | ||||
| 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 | ||||
|     -> api_error { | ||||
|   REPERTORY_USES_FUNCTION_NAME(); | ||||
| @@ -955,8 +1018,8 @@ auto s3_provider::rename_file(const std::string & /* from_api_path */, | ||||
|   return api_error::not_implemented; | ||||
| } | ||||
|  | ||||
| auto s3_provider::search_keys_for_master_kdf(std::string_view encryption_token) | ||||
|     -> bool { | ||||
| auto s3_provider::search_keys_for_master_kdf( | ||||
|     const std::string &encryption_token) -> bool { | ||||
|   REPERTORY_USES_FUNCTION_NAME(); | ||||
|  | ||||
|   std::string token{}; | ||||
| @@ -998,30 +1061,34 @@ auto s3_provider::search_keys_for_master_kdf(std::string_view encryption_token) | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     utils::encryption::kdf_config cfg; | ||||
|     if (not utils::encryption::kdf_config::from_header(buffer, cfg)) { | ||||
|     if (not utils::encryption::kdf_config::from_header(buffer, | ||||
|                                                        master_kdf_cfg_)) { | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     cfg.unique_id = 0U; | ||||
|     cfg.seal(); | ||||
|     master_kdf_cfg_.unique_id = 0U; | ||||
|     master_kdf_cfg_.seal(); | ||||
|  | ||||
|     master_kdf_cfg_ = cfg; | ||||
|     if (not utils::encryption::recreate_key_argon2id( | ||||
|             encryption_token, master_kdf_cfg_, master_key_)) { | ||||
|       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 = | ||||
|         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) { | ||||
|       legacy_bucket_ = false; | ||||
|       event_system::instance().raise<debug_log>(function_name, | ||||
|                                                 "found master kdf config"); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     throw utils::error::create_exception(function_name, | ||||
|                                          {"failed to set meta kdf"}); | ||||
|                                          {"failed to set meta kdf config"}); | ||||
|   } | ||||
|  | ||||
|   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, | ||||
|                                                       "s3_provider"); | ||||
|  | ||||
|   auto ret = base_provider::start(api_item_added, mgr); | ||||
|   const auto &cfg{get_s3_config()}; | ||||
|  | ||||
|   auto ret = base_provider::start(api_item_added, mgr); | ||||
|   if (ret && not cfg.encryption_token.empty()) { | ||||
|     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"); | ||||
|         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) { | ||||
|     if (not initialize_crypto(cfg)) { | ||||
|       base_provider::stop(); | ||||
|     } | ||||
|   } | ||||
| @@ -1218,6 +1235,12 @@ auto s3_provider::upload_file_impl(const std::string &api_path, | ||||
|       res = set_item_meta( | ||||
|           api_path, META_KDF, | ||||
|           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) { | ||||
|         return res; | ||||
|       } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user