diff --git a/.gitignore b/.gitignore index a4ac791..fa01839 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.swp +.fortuna.seed *cmake-build* .cache .idea diff --git a/CMakeLists.txt b/CMakeLists.txt index b4d65a4..b1f2d01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,7 +224,8 @@ set(FORTUNA_SOURCES generator.cpp accumulator.cpp pool.cpp - do_task.cpp) + do_task.cpp + seed_file_management.cpp) set(FORTUNA_HEADERS fortuna.h generator.h diff --git a/do_task.h b/do_task.h index 05294cf..e26698d 100644 --- a/do_task.h +++ b/do_task.h @@ -13,7 +13,7 @@ private: std::timed_mutex do_sleep; std::thread th; public: - DoTask() noexcept; + DoTask() noexcept = default; ~DoTask() noexcept; auto thread_pls(const std::chrono::seconds& interval, diff --git a/fortuna.cpp b/fortuna.cpp index 498c239..60d39b5 100644 --- a/fortuna.cpp +++ b/fortuna.cpp @@ -2,12 +2,16 @@ #define FORTUNA_FORTUNA_CPP #include "fortuna.h" +#include "seed_file_management.h" #include "util.h" -#include #include #include +#include +#include +#include + namespace fortuna { static constexpr const unsigned int min_pool_size{64}; auto now{std::chrono::steady_clock::now()}; @@ -20,7 +24,7 @@ Fortuna::Fortuna() { fmt::print(stderr, "{}\n", e.what()); } th_gen = std::thread(generator_service, &R.Gen); - th_sfm = std::thread(seed_file_manager_service); + th_sfm = std::thread(&Fortuna::seed_file_manager_service, this); } Fortuna::~Fortuna() noexcept { th_gen.join(); @@ -41,8 +45,7 @@ auto Fortuna::random_data(unsigned int n_bytes) -> void { now = std::chrono::steady_clock::now(); std::string s; // synchronise reads and writes to the between - // {generator,accumulator,fortuna} service threads - std::unique_lock uq_lock(mtx); + // {generator,accumulator,fortuna} service threads -> in member functions const int pools_to_use{ffsll(static_cast(get_reseed_ctr()))}; if (R.pools[0].get_s_length() >= min_pool_size && elapsed > R.Gen.reseed_interval) { @@ -71,7 +74,6 @@ auto Fortuna::random_data(unsigned int n_bytes) -> void { n_bytes, n); n.clear(); } - uq_lock.unlock(); const auto end{std::chrono::system_clock::now()}; std::chrono::duration diff = end-start; @@ -97,16 +99,28 @@ auto Fortuna::generator_service(fortuna::generator::Generator* Gen) -> void { } auto Fortuna::seed_file_manager_service() -> void { - // TODO(me): implement proper logic, i.e. include SeedFileManager + std::lock_guard lg(mtx); fmt::print("[i] fortuna: starting seed file manager service\n"); - // FIXME: proper interval is 10 minutes - uint interval{1}; // in seconds - auto now{fortuna::Util::current_time()}; + static constexpr const std::chrono::seconds checkup_interval{10}; + fmt::print("[*] sfm: checkup interval {}\n", checkup_interval); + auto right_now{fortuna::Util::current_time()}; + SeedFileManager sfm(this->accumulator); while(true) { - now = fortuna::Util::current_time(); - fmt::print("[*] sfm: hello now @{}\n", now); - std::this_thread::sleep_until(now + std::chrono::seconds(interval)); + right_now = fortuna::Util::current_time(); + fmt::print("[*] sfm: checkup time @{}\n", right_now); + if (! sfm.is_job_running()) { + fmt::print("[*] sfm: job not running, starting\n"); + try { + sfm.do_stuff(); + } catch (std::exception& e) { + fmt::print(stderr, "[!] sfm: exception caught: {}\n", e.what()); + } + } else { + fmt::print("[*] sfm: job running\n"); + } + std::this_thread::sleep_until(right_now + + std::chrono::seconds(checkup_interval)); } } diff --git a/fortuna.h b/fortuna.h index 373dde0..8e7ee74 100644 --- a/fortuna.h +++ b/fortuna.h @@ -60,7 +60,7 @@ public: static auto generator_service(fortuna::generator::Generator*) -> void; - static auto seed_file_manager_service() -> void; + auto seed_file_manager_service() -> void; // PRNG state class R_state { diff --git a/generator.cpp b/generator.cpp index eb8b8b7..ac9a8f7 100644 --- a/generator.cpp +++ b/generator.cpp @@ -12,6 +12,7 @@ #include #include +#include #include namespace fortuna { @@ -53,12 +54,12 @@ auto Generator::time_to_reseed() const -> bool { } auto Generator::reseed(const std::string& s) -> void { + std::unique_lock ul(reseed_mtx); // ref: https://www.cryptopp.com/wiki/SecBlock std::string da_key(reinterpret_cast(&G.k[0]), G.k.SizeInBytes() * 8); // we need the size in bits try { - std::lock_guard lg(mtx); std::string a{fortuna::Util::do_sha(da_key + s)}; std::memmove(G.k, a.c_str(), G.k_length); ++G.ctr; @@ -79,6 +80,7 @@ auto Generator::do_crypto() -> std::string { // William Shakespeare, Romeo and Juliet std::string plain{"Oh, I am fortune's fool!"}; std::string cipher, encoded_c; + std::unique_lock ul(crypt_mtx); // in case we need to convert counter to string std::string str_ctr{reinterpret_cast(&G.ctr)}; // 16 bytes --> 128bit @@ -89,6 +91,7 @@ auto Generator::do_crypto() -> std::string { try { CryptoPP::CTR_Mode::Encryption e; e.SetKeyWithIV(G.k,G.k.size(),ctr); + ul.unlock(); // The StreamTransformationFilter adds padding as required. ECB and // CBC Mode must be padded to the block size of the cipher. CTR diff --git a/generator.h b/generator.h index fdaf9f2..4cfada0 100644 --- a/generator.h +++ b/generator.h @@ -15,6 +15,8 @@ class Generator { public: std::chrono::milliseconds reseed_interval{100}; std::mutex mtx; + std::mutex crypt_mtx; + std::mutex reseed_mtx; Generator(); // ad noexcept: perhaps _do_ throw* Generator(const Generator& Gen) = delete; // no diff --git a/seed_file_management.cpp b/seed_file_management.cpp new file mode 100644 index 0000000..f1ca7ca --- /dev/null +++ b/seed_file_management.cpp @@ -0,0 +1,77 @@ +#ifndef FORTUNA_SEED_FILE_MANAGER_CPP +#define FORTUNA_SEED_FILE_MANAGER_CPP + +#include "seed_file_management.h" +#include "accumulator.h" +#include "util.h" + +#include +#include +#include +#include + +namespace fortuna { + +SeedFileManager::SeedFileManager(const fortuna::accumulator::Accumulator& accumulator) noexcept { + this->accumulator = accumulator; +} +SeedFileManager::~SeedFileManager() noexcept {set_job_running(false);}; + +auto SeedFileManager::is_job_running() -> bool { + return running; +} + +auto SeedFileManager::set_job_running(bool running) -> void { + this->running = running; +} + +auto SeedFileManager::do_stuff() -> void { + update_seed_file(); + do_task.thread_pls(config.write_interval, [this]{write_seed_file();}); + running = true; +} + +auto SeedFileManager::update_seed_file() -> void { + CryptoPP::SecByteBlock buff{config.seed_f_length}; + + { + std::ifstream f_stream{config.seed_f_path, std::ios::binary}; + if (!f_stream) { + std::string msg{"error opening seed file"}; + fmt::print("{} {}\n", msg, config.seed_f_path); + // FIXME: perhaps create a seed file instead of bailing... + throw std::runtime_error("error opening seed file"); + } + + f_stream.read(reinterpret_cast(buff.BytePtr()), config.seed_f_length); + if (static_cast(f_stream.gcount()) != config.seed_f_length) { + std::string msg{"error reading seed from file"}; + fmt::print("{} {}, length: {}\n", msg, config.seed_f_path, config.seed_f_length); + throw std::runtime_error(msg); + } + } + + try { + std::string str_buff(reinterpret_cast(&buff[0]), + buff.SizeInBytes() * 8); // we need the size in bits + accumulator.call_reseed(str_buff); + write_seed_file(); + } catch(std::exception& e) { + fmt::print("{}", e.what()); + } +} + +auto SeedFileManager::write_seed_file() -> void { + const std::size_t seed_file_length_blocks = fortuna::Util::b2b(config.seed_f_length); + CryptoPP::SecByteBlock buff{seed_file_length_blocks * fortuna::Util::gen_block_size}; + std::string da_buff{accumulator.get_random_data(seed_file_length_blocks)}; + fmt::print("[*] sfm: writing seed file\n"); + + std::ofstream f_stream{config.seed_f_path, std::ios::binary|std::ios::trunc}; + f_stream.write(reinterpret_cast(buff.BytePtr()), config.seed_f_length); +} + + +} // namespace fortuna + +#endif//FORTUNA_SEED_FILE_MANAGER_CPP diff --git a/seed_file_management.h b/seed_file_management.h index 878dae7..894de5e 100644 --- a/seed_file_management.h +++ b/seed_file_management.h @@ -1,30 +1,39 @@ #ifndef FORTUNA_SEED_FILE_MANAGER_H #define FORTUNA_SEED_FILE_MANAGER_H -#include -#include - #include "accumulator.h" #include "do_task.h" +#include +#include + namespace fortuna { class SeedFileManager { public: struct conf { - std::chrono::minutes write_interval{10}; - std::string seed_f_path = "./fortuna.seed"; + // std::chrono::minutes write_interval{10}; + // 10 minutes (as the standard recommends) is a lot, go with 120s + std::chrono::seconds write_interval{120}; + std::string seed_f_path = "./.fortuna.seed"; std::size_t seed_f_length = 64; conf(){}; }; - SeedFileManager(fortuna::accumulator::Accumulator& accumulator); - ~SeedFileManager(); + auto is_job_running() -> bool; + auto do_stuff() -> void; + + SeedFileManager(const fortuna::accumulator::Accumulator& accumulator) noexcept; + ~SeedFileManager() noexcept; + +protected: + auto set_job_running(bool) -> void; private: const conf config; + bool running = false; DoTask do_task; fortuna::accumulator::Accumulator accumulator; diff --git a/util.h b/util.h index f8f71d0..3109c15 100644 --- a/util.h +++ b/util.h @@ -34,6 +34,12 @@ static auto current_time() -> std::chrono::time_point