surtur
d404681889
All checks were successful
continuous-integration/drone/push Build is passing
general * make greater use of "this" Fortuna * declare da_pools as a proper std::array of 32 Pool objects * declare da_pools as const * use std::shared_ptr _p_pools to access da_pools and share access to it * reflect change of pools[] -> std::array in how the array elements are accessed, which is a) via _p_pools pointer and b) using ".at(i)" function * pass _p_pools shared_ptr to Accumulator * refactor member function names and variable names * add member function attribute [[optimize_for_synchronized]] * secure conversions with static_cast-s Accumulator * make use of _p_pools * add _p_pools-related member functions * add a static constexpr variable NUM_OF_POOLS UrandomEntropySrc * implement event adding logic using _p_pools * make std::vector<char> non-static in urandom_entropy_src * implement proper urandom entropy source event "sourcing" (from /dev/urandom), event adding, clear bytes array at the end * properly convert using reinterpret_cast * protect access to the main function with std::lock_guard * receive EventAdderImpl as a ref * use return value from "add_entropy()" member function and create sanity guard checking the return code "int ret" EventAdder * pass event (std::vector<char>) by const& EventAdderImpl * make use of _p_pools shared_ptr * implement proper pool-rotating event-adding logic Pool * delete all copy constructors and assignment operator, the objects will not be copied or assigned to * receive parameters by const& where possible/sensible * handle concurrency: * declare std:string s as mutable * declare a rw std::mutex intended for writing and mutable std::recursive_mutex for read-only operations in const member functions ref: https://herbsutter.com/2013/05/24/gotw-6a-const-correctness-part-1-3/ ref: https://arne-mertz.de/2017/10/mutable/ * use std::lock_guard and std::unique_lock * refactor "add_entropy()" member function * get rid of intermediate "event_str" and directly use the "event" std::vector<char> for all operations * add a lock guard to prevent multiple threads (should that route be taken) from modifying pool resources simultaneously * add all_ok bool for basic sanity checking * add print statements (at least for now) * rename "get_s_length()" member function to "get_s_byte_count()" and repurpose it to return byte count of the stored entropy std::string s
183 lines
5.0 KiB
C++
183 lines
5.0 KiB
C++
#ifndef FORTUNA_FORTUNA_CPP
|
|
#define FORTUNA_FORTUNA_CPP
|
|
|
|
#include "fortuna.h"
|
|
#include "seed_file_management.h"
|
|
#include "util.h"
|
|
|
|
#include <cryptopp/cryptlib.h>
|
|
#include <fmt/chrono.h>
|
|
|
|
#include <chrono>
|
|
#include <exception>
|
|
#include <memory>
|
|
#include <mutex>
|
|
|
|
namespace fortuna {
|
|
static constexpr const unsigned int min_pool_size{64};
|
|
auto now{std::chrono::steady_clock::now()};
|
|
|
|
|
|
Fortuna::Fortuna() {
|
|
try {
|
|
initialize_prng();
|
|
}
|
|
catch (CryptoPP::Exception& e) {
|
|
fmt::print(stderr, "{}\n", e.what());
|
|
}
|
|
th_gen = std::thread(&Fortuna::generator_service,
|
|
this,
|
|
std::make_shared<fortuna::generator::Generator>());
|
|
th_accu = std::thread(&Fortuna::accumulator_service, this);
|
|
th_sfm = std::thread(&Fortuna::seed_file_manager_service, this);
|
|
}
|
|
Fortuna::~Fortuna() noexcept {
|
|
if (th_gen.joinable()) {
|
|
th_gen.join();
|
|
}
|
|
if (th_gen.joinable()) {
|
|
th_accu.join();
|
|
}
|
|
if (th_sfm.joinable()) {
|
|
th_sfm.join();
|
|
}
|
|
}
|
|
|
|
|
|
auto Fortuna::random_data(unsigned int n_bytes) -> void {
|
|
const auto start{std::chrono::system_clock::now()};
|
|
fmt::print("random_data starting - {}\n", start);
|
|
auto elapsed{std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
std::chrono::steady_clock::now().time_since_epoch() -
|
|
now.time_since_epoch())};
|
|
fmt::print("[i] fortuna: last_reseed: {} ago\n", elapsed);
|
|
now = std::chrono::steady_clock::now();
|
|
std::string s;
|
|
// synchronise reads and writes to the between
|
|
// {generator,accumulator,fortuna} service threads -> in member functions
|
|
const int pools_to_use{ffsll(static_cast<int>(get_reseed_ctr()))};
|
|
|
|
fmt::print("[*] fortuna: current p0 length: {}\n",
|
|
this->R._p_pools->at(0).get_s_byte_count());
|
|
if (R.Gen.time_to_reseed(R._p_pools->at(0).get_s_byte_count(),
|
|
min_pool_size,
|
|
elapsed,
|
|
R.Gen.reseed_interval)) {
|
|
for (int i = 0; i < static_cast<int>(pools_to_use); ++i) {
|
|
if (this->R.reseed_ctr %
|
|
static_cast<int>(pow(2, static_cast<double>(i))) ==
|
|
0) {
|
|
try {
|
|
s.append(
|
|
fortuna::Util::do_sha(this->R._p_pools->at(i).get_s()));
|
|
this->R._p_pools->at(i).clear_pool();
|
|
}
|
|
catch (std::exception& e) {
|
|
fmt::print("{}\n", e.what());
|
|
}
|
|
}
|
|
}
|
|
incr_reseed_ctr();
|
|
R.Gen.reseed(s);
|
|
R.last_reseed = std::chrono::steady_clock::now();
|
|
s.clear();
|
|
}
|
|
|
|
fmt::print("[i] fortuna: reseed ctr {}\n", R.reseed_ctr);
|
|
if (R.reseed_ctr == 0) {
|
|
fmt::print("[!] ERROR: reseed ctr is 0, PRNG not seeded!\n");
|
|
throw std::runtime_error("illegal state, PRNG not seeded");
|
|
}
|
|
else {
|
|
std::string n{R.Gen.generate_random_data(n_bytes)};
|
|
fmt::print("got you {} proper bytes from generate_random_data -> {}\n",
|
|
n_bytes,
|
|
n);
|
|
n.clear();
|
|
}
|
|
|
|
const auto end{std::chrono::system_clock::now()};
|
|
std::chrono::duration<float> diff = end - start;
|
|
fmt::print("random_data done - {}\n", end);
|
|
fmt::print("getting random data took {:.{}f}s\n", diff.count(), 12);
|
|
} // random_data
|
|
|
|
auto Fortuna::generator_service(
|
|
std::shared_ptr<fortuna::generator::Generator> Gen) -> void {
|
|
int i{0};
|
|
std::chrono::milliseconds sleep_time{1000};
|
|
std::chrono::system_clock::time_point time_point;
|
|
std::unique_lock<std::mutex> p_ul(print_mtx);
|
|
fmt::print("[i] fortuna: starting generator service\n");
|
|
p_ul.unlock();
|
|
|
|
while (true) {
|
|
p_ul.lock();
|
|
fmt::print("[*] g: sleeping [{}]\n", i);
|
|
p_ul.unlock();
|
|
++i;
|
|
time_point = fortuna::Util::current_time();
|
|
p_ul.lock();
|
|
fmt::print("[*] g: @{}\n", time_point);
|
|
p_ul.unlock();
|
|
std::this_thread::sleep_until(time_point +
|
|
std::chrono::milliseconds(sleep_time));
|
|
}
|
|
}
|
|
|
|
auto Fortuna::accumulator_service() -> void {
|
|
std::chrono::seconds sleep_time{10};
|
|
std::chrono::system_clock::time_point time_point;
|
|
std::unique_lock<std::mutex> p_ul(print_mtx);
|
|
fmt::print("[i] fortuna: starting accumulator service\n");
|
|
p_ul.unlock();
|
|
|
|
while (true) {
|
|
time_point = fortuna::Util::current_time();
|
|
p_ul.lock();
|
|
fmt::print("[*] accu: @{}\n", time_point);
|
|
p_ul.unlock();
|
|
std::this_thread::sleep_until(time_point +
|
|
std::chrono::seconds(sleep_time));
|
|
}
|
|
}
|
|
|
|
auto Fortuna::seed_file_manager_service() -> void {
|
|
static constexpr const std::chrono::seconds checkup_interval{10};
|
|
std::unique_lock<std::mutex> p_ul(print_mtx);
|
|
fmt::print("[i] fortuna: starting seed file manager service\n");
|
|
fmt::print("[*] sfm: checkup interval {}\n", checkup_interval);
|
|
p_ul.unlock();
|
|
auto right_now{fortuna::Util::current_time()};
|
|
std::unique_lock<std::mutex> mtx_l(mtx);
|
|
std::unique_lock<std::mutex> a_ul(accu_mtx);
|
|
SeedFileManager sfm(this->accumulator);
|
|
a_ul.unlock();
|
|
mtx_l.unlock();
|
|
|
|
while (true) {
|
|
right_now = fortuna::Util::current_time();
|
|
p_ul.lock();
|
|
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");
|
|
}
|
|
p_ul.unlock();
|
|
std::this_thread::sleep_until(right_now +
|
|
std::chrono::seconds(checkup_interval));
|
|
}
|
|
}
|
|
|
|
} // namespace fortuna
|
|
|
|
#endif // FORTUNA_FORTUNA_CPP
|