forked from ak-fortuna/fortuna
add proper SeedFileManager implementation
a couple of fixes/necessary additions were made along the way, namely: * add a default constructor for DoTask * rework of the mutex/lock_guard/unique_lock logic in generator/fortuna * add .fortuna.seed to the list of the ignored (.gitignore) * add helper function to util for convertin bytes to blocks (16b==block) * add a wrapper for around the SeedFileManager instance and a way to see if it's dead or alive (so that it can be restarted if needed) * the timeout for saving of the seed file has been decreased to a more reasonable value than 10 minutes (I wouldn't want to lose potentially up to 10 minutes worth of entropy)
This commit is contained in:
parent
8827582f90
commit
795b9ffe54
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
*.swp
|
*.swp
|
||||||
|
.fortuna.seed
|
||||||
*cmake-build*
|
*cmake-build*
|
||||||
.cache
|
.cache
|
||||||
.idea
|
.idea
|
||||||
|
|
|
@ -224,7 +224,8 @@ set(FORTUNA_SOURCES
|
||||||
generator.cpp
|
generator.cpp
|
||||||
accumulator.cpp
|
accumulator.cpp
|
||||||
pool.cpp
|
pool.cpp
|
||||||
do_task.cpp)
|
do_task.cpp
|
||||||
|
seed_file_management.cpp)
|
||||||
set(FORTUNA_HEADERS
|
set(FORTUNA_HEADERS
|
||||||
fortuna.h
|
fortuna.h
|
||||||
generator.h
|
generator.h
|
||||||
|
|
|
@ -13,7 +13,7 @@ private:
|
||||||
std::timed_mutex do_sleep;
|
std::timed_mutex do_sleep;
|
||||||
std::thread th;
|
std::thread th;
|
||||||
public:
|
public:
|
||||||
DoTask() noexcept;
|
DoTask() noexcept = default;
|
||||||
~DoTask() noexcept;
|
~DoTask() noexcept;
|
||||||
|
|
||||||
auto thread_pls(const std::chrono::seconds& interval,
|
auto thread_pls(const std::chrono::seconds& interval,
|
||||||
|
|
38
fortuna.cpp
38
fortuna.cpp
|
@ -2,12 +2,16 @@
|
||||||
#define FORTUNA_FORTUNA_CPP
|
#define FORTUNA_FORTUNA_CPP
|
||||||
|
|
||||||
#include "fortuna.h"
|
#include "fortuna.h"
|
||||||
|
#include "seed_file_management.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <cryptopp/cryptlib.h>
|
#include <cryptopp/cryptlib.h>
|
||||||
#include <fmt/chrono.h>
|
#include <fmt/chrono.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <exception>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace fortuna {
|
namespace fortuna {
|
||||||
static constexpr const unsigned int min_pool_size{64};
|
static constexpr const unsigned int min_pool_size{64};
|
||||||
auto now{std::chrono::steady_clock::now()};
|
auto now{std::chrono::steady_clock::now()};
|
||||||
|
@ -20,7 +24,7 @@ Fortuna::Fortuna() {
|
||||||
fmt::print(stderr, "{}\n", e.what());
|
fmt::print(stderr, "{}\n", e.what());
|
||||||
}
|
}
|
||||||
th_gen = std::thread(generator_service, &R.Gen);
|
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 {
|
Fortuna::~Fortuna() noexcept {
|
||||||
th_gen.join();
|
th_gen.join();
|
||||||
|
@ -41,8 +45,7 @@ auto Fortuna::random_data(unsigned int n_bytes) -> void {
|
||||||
now = std::chrono::steady_clock::now();
|
now = std::chrono::steady_clock::now();
|
||||||
std::string s;
|
std::string s;
|
||||||
// synchronise reads and writes to the between
|
// synchronise reads and writes to the between
|
||||||
// {generator,accumulator,fortuna} service threads
|
// {generator,accumulator,fortuna} service threads -> in member functions
|
||||||
std::unique_lock<std::mutex> uq_lock(mtx);
|
|
||||||
const int pools_to_use{ffsll(static_cast<int>(get_reseed_ctr()))};
|
const int pools_to_use{ffsll(static_cast<int>(get_reseed_ctr()))};
|
||||||
|
|
||||||
if (R.pools[0].get_s_length() >= min_pool_size && elapsed > R.Gen.reseed_interval) {
|
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_bytes, n);
|
||||||
n.clear();
|
n.clear();
|
||||||
}
|
}
|
||||||
uq_lock.unlock();
|
|
||||||
|
|
||||||
const auto end{std::chrono::system_clock::now()};
|
const auto end{std::chrono::system_clock::now()};
|
||||||
std::chrono::duration<float> diff = end-start;
|
std::chrono::duration<float> diff = end-start;
|
||||||
|
@ -97,16 +99,28 @@ auto Fortuna::generator_service(fortuna::generator::Generator* Gen) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Fortuna::seed_file_manager_service() -> void {
|
auto Fortuna::seed_file_manager_service() -> void {
|
||||||
// TODO(me): implement proper logic, i.e. include SeedFileManager
|
std::lock_guard<std::mutex> lg(mtx);
|
||||||
fmt::print("[i] fortuna: starting seed file manager service\n");
|
fmt::print("[i] fortuna: starting seed file manager service\n");
|
||||||
// FIXME: proper interval is 10 minutes
|
static constexpr const std::chrono::seconds checkup_interval{10};
|
||||||
uint interval{1}; // in seconds
|
fmt::print("[*] sfm: checkup interval {}\n", checkup_interval);
|
||||||
auto now{fortuna::Util::current_time()};
|
auto right_now{fortuna::Util::current_time()};
|
||||||
|
SeedFileManager sfm(this->accumulator);
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
now = fortuna::Util::current_time();
|
right_now = fortuna::Util::current_time();
|
||||||
fmt::print("[*] sfm: hello now @{}\n", now);
|
fmt::print("[*] sfm: checkup time @{}\n", right_now);
|
||||||
std::this_thread::sleep_until(now + std::chrono::seconds(interval));
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ public:
|
||||||
|
|
||||||
static auto generator_service(fortuna::generator::Generator*) -> void;
|
static auto generator_service(fortuna::generator::Generator*) -> void;
|
||||||
|
|
||||||
static auto seed_file_manager_service() -> void;
|
auto seed_file_manager_service() -> void;
|
||||||
|
|
||||||
// PRNG state
|
// PRNG state
|
||||||
class R_state {
|
class R_state {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <mutex>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace fortuna {
|
namespace fortuna {
|
||||||
|
@ -53,12 +54,12 @@ auto Generator::time_to_reseed() const -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Generator::reseed(const std::string& s) -> void {
|
auto Generator::reseed(const std::string& s) -> void {
|
||||||
|
std::unique_lock<std::mutex> ul(reseed_mtx);
|
||||||
// ref: https://www.cryptopp.com/wiki/SecBlock
|
// ref: https://www.cryptopp.com/wiki/SecBlock
|
||||||
std::string da_key(reinterpret_cast<const char*>(&G.k[0]),
|
std::string da_key(reinterpret_cast<const char*>(&G.k[0]),
|
||||||
G.k.SizeInBytes() * 8); // we need the size in bits
|
G.k.SizeInBytes() * 8); // we need the size in bits
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::lock_guard<std::mutex> lg(mtx);
|
|
||||||
std::string a{fortuna::Util::do_sha(da_key + s)};
|
std::string a{fortuna::Util::do_sha(da_key + s)};
|
||||||
std::memmove(G.k, a.c_str(), G.k_length);
|
std::memmove(G.k, a.c_str(), G.k_length);
|
||||||
++G.ctr;
|
++G.ctr;
|
||||||
|
@ -79,6 +80,7 @@ auto Generator::do_crypto() -> std::string {
|
||||||
// William Shakespeare, Romeo and Juliet
|
// William Shakespeare, Romeo and Juliet
|
||||||
std::string plain{"Oh, I am fortune's fool!"};
|
std::string plain{"Oh, I am fortune's fool!"};
|
||||||
std::string cipher, encoded_c;
|
std::string cipher, encoded_c;
|
||||||
|
std::unique_lock<std::mutex> ul(crypt_mtx);
|
||||||
// in case we need to convert counter to string
|
// in case we need to convert counter to string
|
||||||
std::string str_ctr{reinterpret_cast<const char*>(&G.ctr)};
|
std::string str_ctr{reinterpret_cast<const char*>(&G.ctr)};
|
||||||
// 16 bytes --> 128bit
|
// 16 bytes --> 128bit
|
||||||
|
@ -89,6 +91,7 @@ auto Generator::do_crypto() -> std::string {
|
||||||
try {
|
try {
|
||||||
CryptoPP::CTR_Mode<CryptoPP::Serpent>::Encryption e;
|
CryptoPP::CTR_Mode<CryptoPP::Serpent>::Encryption e;
|
||||||
e.SetKeyWithIV(G.k,G.k.size(),ctr);
|
e.SetKeyWithIV(G.k,G.k.size(),ctr);
|
||||||
|
ul.unlock();
|
||||||
|
|
||||||
// The StreamTransformationFilter adds padding as required. ECB and
|
// The StreamTransformationFilter adds padding as required. ECB and
|
||||||
// CBC Mode must be padded to the block size of the cipher. CTR
|
// CBC Mode must be padded to the block size of the cipher. CTR
|
||||||
|
|
|
@ -15,6 +15,8 @@ class Generator {
|
||||||
public:
|
public:
|
||||||
std::chrono::milliseconds reseed_interval{100};
|
std::chrono::milliseconds reseed_interval{100};
|
||||||
std::mutex mtx;
|
std::mutex mtx;
|
||||||
|
std::mutex crypt_mtx;
|
||||||
|
std::mutex reseed_mtx;
|
||||||
|
|
||||||
Generator(); // ad noexcept: perhaps _do_ throw*
|
Generator(); // ad noexcept: perhaps _do_ throw*
|
||||||
Generator(const Generator& Gen) = delete; // no
|
Generator(const Generator& Gen) = delete; // no
|
||||||
|
|
|
@ -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 <cryptopp/secblock.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
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<char*>(buff.BytePtr()), config.seed_f_length);
|
||||||
|
if (static_cast<std::size_t>(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<const char*>(&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<const char*>(buff.BytePtr()), config.seed_f_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace fortuna
|
||||||
|
|
||||||
|
#endif//FORTUNA_SEED_FILE_MANAGER_CPP
|
|
@ -1,30 +1,39 @@
|
||||||
#ifndef FORTUNA_SEED_FILE_MANAGER_H
|
#ifndef FORTUNA_SEED_FILE_MANAGER_H
|
||||||
#define FORTUNA_SEED_FILE_MANAGER_H
|
#define FORTUNA_SEED_FILE_MANAGER_H
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "accumulator.h"
|
#include "accumulator.h"
|
||||||
#include "do_task.h"
|
#include "do_task.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace fortuna {
|
namespace fortuna {
|
||||||
|
|
||||||
class SeedFileManager {
|
class SeedFileManager {
|
||||||
public:
|
public:
|
||||||
struct conf
|
struct conf
|
||||||
{
|
{
|
||||||
std::chrono::minutes write_interval{10};
|
// std::chrono::minutes write_interval{10};
|
||||||
std::string seed_f_path = "./fortuna.seed";
|
// 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;
|
std::size_t seed_f_length = 64;
|
||||||
|
|
||||||
conf(){};
|
conf(){};
|
||||||
};
|
};
|
||||||
|
|
||||||
SeedFileManager(fortuna::accumulator::Accumulator& accumulator);
|
auto is_job_running() -> bool;
|
||||||
~SeedFileManager();
|
auto do_stuff() -> void;
|
||||||
|
|
||||||
|
SeedFileManager(const fortuna::accumulator::Accumulator& accumulator) noexcept;
|
||||||
|
~SeedFileManager() noexcept;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
auto set_job_running(bool) -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const conf config;
|
const conf config;
|
||||||
|
bool running = false;
|
||||||
DoTask do_task;
|
DoTask do_task;
|
||||||
fortuna::accumulator::Accumulator accumulator;
|
fortuna::accumulator::Accumulator accumulator;
|
||||||
|
|
||||||
|
|
6
util.h
6
util.h
|
@ -34,6 +34,12 @@ static auto current_time() -> std::chrono::time_point<std::chrono::system_clock,
|
||||||
return std::chrono::system_clock::now();
|
return std::chrono::system_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns number of blocks for a given number of bytes
|
||||||
|
static constexpr std::size_t b2b(std::size_t bytes) noexcept {
|
||||||
|
// returns number of blocks
|
||||||
|
return bytes == 0 ? 0 : ((bytes - 1) / gen_block_size) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
Util() = delete;
|
Util() = delete;
|
||||||
~Util() noexcept;
|
~Util() noexcept;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue