fortuna/pool.cpp

156 lines
3.8 KiB
C++

#ifndef FORTUNA_POOL_CPP
#define FORTUNA_POOL_CPP
#include "pool.h"
#include <fmt/core.h>
#include <fmt/ranges.h>
#include <atomic>
#include <climits>
#include <cstddef>
#include <mutex>
#include <stdexcept>
#include <utility>
namespace fortuna {
namespace accumulator {
auto Pool::set_id(const unsigned int& id) noexcept -> void {
std::lock_guard<std::mutex> lg(mtx);
this->pool_id = id;
}
auto Pool::get_id() const noexcept -> unsigned int {
return this->pool_id;
}
auto Pool::initialize_pool(const unsigned int& id) -> void {
// ref: https://stackoverflow.com/a/23204682
std::call_once(init, [this, id] { this->set_id(id); });
}
auto Pool::add_entropy(const unsigned int& source,
const std::vector<char>& event) -> int {
std::unique_lock<std::recursive_mutex> ul(ro_mtx_s);
const size_t event_size{sizeof(char) * event.size()};
const size_t max_event_size{32};
std::atomic<bool> all_ok{false};
fmt::print(stderr, "\tevent_size (bytes): {}\n", event_size);
try {
if (source > 255) {
throw std::invalid_argument(
"source number outside of interval <0,255>\n");
}
fmt::print(stderr, "\tsource_id: {}\n", source);
if (event_size < 1 || event_size > max_event_size) {
const std::string msg{
"[!] add_entropy: the length of the event needs to "
"be from the interval <1,32>"};
fmt::print(stderr,
"\tsource: {}\n{}\nevent size: {}\n\tpool_id: {}",
source,
msg,
event_size,
this->pool_id);
throw std::invalid_argument(msg);
}
else {
all_ok = true;
}
}
catch (const std::exception& e) {
fmt::print(stderr, "{}\n", e.what());
throw;
}
if (all_ok) {
try {
{
// as per Cryptography Engineering, p. 148 (180/385)
std::vector<char> fullevent{static_cast<char>(source)};
fullevent.push_back(static_cast<char>(event_size));
fullevent.insert(
std::end(fullevent), std::begin(event), std::end(event));
fmt::print(
stderr, "\t[i] add_entropy(fullevent): {}\n", fullevent);
// FIXME: check size for overflow
// also, atm this counts event size but actually what gets
// appended are digests of 64 characters (hex-encoded 32 bytes)
size += event_size;
{
const std::string digest(fortuna::Util::do_sha(fullevent));
fmt::print(
stderr, "\t[i] add_entropy(digest): {}\n", digest);
append_s(digest);
}
}
fmt::print(stderr,
"\t[i] s.length() (simple char count): {}\n"
"\t[i] get_s_byte_count() (byte count): {}\n"
"\t[i] pool_id: {}\n"
"\t[i] s: {}\n",
this->s.length(),
this->get_s_byte_count(),
this->pool_id,
// "");
this->s);
}
catch (const std::exception& e) {
fmt::print(stderr, "[!] pool(add_entropy): {}\n", e.what());
// FIXME: handle this (as all the other unhandled exceptions)
throw;
}
return 0;
}
else {
// everything not ok
return 1;
}
} // add_entropy
auto Pool::get_s_byte_count() const -> uint64_t {
// returns total byte count of (hex-encoded) entropy string contained in
// the pool. since the string is hex-encoded, we divide its char count by 2
// to get proper byte count. we need this since we actually don't care about
// the length of the hex string as it is, rather we care about what it came
// from (the raw entropy event)
std::lock_guard<std::recursive_mutex> lg(ro_mtx_s);
return this->s.length() / 2;
}
auto Pool::get_s() const -> std::string {
std::lock_guard<std::recursive_mutex> lg(ro_mtx_s);
return this->s;
}
auto Pool::clear_pool() -> void {
std::lock_guard<std::mutex> lg(mtx);
this->s.clear();
}
auto Pool::append_s(const std::string& entropy_s) -> void {
std::lock_guard<std::mutex> lg(mtx);
try {
this->s.append(entropy_s);
}
catch (const std::exception& e) {
fmt::print(stderr, "{}\n", e.what());
}
}
} // namespace accumulator
} // namespace fortuna
#endif // FORTUNA_POOL_CPP