#ifndef FORTUNA_FORTUNA_H #define FORTUNA_FORTUNA_H #include "accumulator.h" #include "generator.h" #include "pool.h" #include #include #include #include #include #include #include namespace fortuna { class Fortuna { public: static constexpr const char NUM_OF_POOLS{32}; std::mutex mtx; std::mutex mtx_random_data; std::mutex mtx_p_pools; std::mutex mtx_accu; std::mutex print_mtx; std::thread th_gen; std::thread th_accu; std::thread th_sfm; std::thread th_urandom; std::latch sync_point{1}; // wait for init before spawning the threads Fortuna(); ~Fortuna() noexcept; [[optimize_for_synchronized]] auto random_data(unsigned int) -> void; auto set_reseed_ctr_to_null() -> void { std::lock_guard lg(mtx); Fortuna::R.null_da_ctr(); } auto incr_reseed_ctr() -> void { std::lock_guard lg(mtx); ++Fortuna::R.reseed_ctr; } auto get_reseed_ctr() const -> uint64_t { return R.reseed_ctr; } auto initialize_prng() -> void { // TODO(me): handle the reseeds here as per Cryptography Engineering, // p. 153 set_reseed_ctr_to_null(); std::unique_lock p_ul(print_mtx); std::unique_lock a_ul(mtx_accu, std::defer_lock); std::unique_lock pp_ul(mtx_p_pools, std::defer_lock); try { std::lock(a_ul, pp_ul); R.initialize_pools(); fmt::print("[i] fortuna: pools initialized\n"); p_ul.unlock(); accumulator.set_pools_ptr(R._p_pools); accumulator.set_gen(R.Gen); a_ul.unlock(); // FIXME: bogus first reseed here, P_0 definitely hasn't collected // enough entropy by now incr_reseed_ctr(); p_ul.lock(); fmt::print("first reseed\n"); p_ul.unlock(); std::unique_lock ul(mtx); R.Gen.reseed("fortuna"); ul.unlock(); } catch (std::exception& e) { p_ul.try_lock(); fmt::print( "{}\n[!] fortuna: fatal error, PRNG initialization FAILED!\n\n", e.what()); } p_ul.try_lock(); this->sync_point.count_down(); fmt::print("[*] fortuna: PRNG initialized\n"); } auto generator_service(std::shared_ptr Gen) -> void; auto accumulator_service() -> void; auto seed_file_manager_service() -> void; auto urandom_entropy_src_service() -> void; // PRNG state class R_state { friend fortuna::Fortuna; public: R_state() noexcept {} ~R_state() noexcept = default; protected: auto null_da_ctr() -> void { reseed_ctr = 0x00; fmt::print("reseed_ctr set to 0x00\n"); } auto initialize_pools() -> void { for (unsigned int i = accumulator::Accumulator::init_pool_num; i < Fortuna::NUM_OF_POOLS; ++i) { this->_p_pools->at(i).initialize_pool(i); } } private: generator::Generator Gen; uint64_t reseed_ctr{0x00}; // da_pools is to be used solely for creating a shared_ptr of the // object: _p_pools. any further access to the structure should be // facilitated by the subject _p_pools shared_ptr. to convey this, // da_pools is declared const const std::array da_pools; // _p_pools points to the da_pools array of 32 Pool objects std::shared_ptr> _p_pools{std::make_shared< std::array>()}; std::chrono::steady_clock::time_point last_reseed; }; // class R_state fortuna::Fortuna::R_state R; fortuna::accumulator::Accumulator accumulator; }; // class Fortuna } // namespace fortuna #endif // FORTUNA_FORTUNA_H