2021-11-15 22:13:00 +01:00
|
|
|
#ifndef FORTUNA_GENERATOR_CPP
|
|
|
|
#define FORTUNA_GENERATOR_CPP
|
|
|
|
|
2021-12-06 00:08:32 +01:00
|
|
|
#include "generator.h"
|
2021-12-13 02:18:37 +01:00
|
|
|
#include "util.h"
|
2021-12-06 00:08:32 +01:00
|
|
|
|
2021-11-30 14:09:39 +01:00
|
|
|
#include <cryptopp/filters.h>
|
2022-01-10 04:25:03 +01:00
|
|
|
#include <cryptopp/hex.h>
|
2022-01-26 22:35:45 +01:00
|
|
|
#include <cryptopp/secblock.h>
|
2021-11-18 22:05:05 +01:00
|
|
|
#include <fmt/core.h>
|
2021-11-11 02:35:17 +01:00
|
|
|
|
2022-01-15 13:35:56 +01:00
|
|
|
#include <algorithm>
|
2022-01-27 22:54:53 +01:00
|
|
|
#include <atomic>
|
2022-01-03 06:29:16 +01:00
|
|
|
#include <cassert>
|
2022-01-15 13:35:56 +01:00
|
|
|
#include <chrono>
|
2022-01-10 04:25:03 +01:00
|
|
|
#include <cmath>
|
2022-01-15 13:35:56 +01:00
|
|
|
#include <cstdint>
|
2022-02-03 00:37:20 +01:00
|
|
|
#include <cstdio>
|
2022-01-09 11:58:38 +01:00
|
|
|
#include <mutex>
|
2022-01-03 06:29:16 +01:00
|
|
|
#include <stdexcept>
|
|
|
|
|
2021-11-01 09:23:22 +01:00
|
|
|
namespace fortuna {
|
|
|
|
namespace generator {
|
|
|
|
|
2021-11-19 22:45:29 +01:00
|
|
|
Generator::Generator() /*noexcept*/ {
|
2021-12-05 02:00:25 +01:00
|
|
|
try {
|
|
|
|
initialize_generator();
|
2022-01-10 04:25:03 +01:00
|
|
|
}
|
|
|
|
catch (CryptoPP::Exception& e) {
|
2021-12-05 02:00:25 +01:00
|
|
|
fmt::print(stderr, "{}\n", e.what());
|
2022-01-30 00:00:20 +01:00
|
|
|
throw;
|
2021-12-05 02:00:25 +01:00
|
|
|
}
|
2021-11-19 22:45:29 +01:00
|
|
|
}
|
2022-01-17 04:03:06 +01:00
|
|
|
Generator::~Generator() noexcept {}
|
2021-10-19 15:05:18 +02:00
|
|
|
|
2021-11-30 14:09:39 +01:00
|
|
|
|
2022-01-10 04:25:03 +01:00
|
|
|
void Generator::initialize_generator() {
|
2022-01-20 08:36:02 +01:00
|
|
|
std::lock_guard<std::recursive_mutex> lg(mtx);
|
|
|
|
|
2021-12-05 03:13:47 +01:00
|
|
|
try {
|
|
|
|
std::memset(G.k, 0x00, G.k.size());
|
2022-01-30 22:56:08 +01:00
|
|
|
std::memset(G.ctr.begin(), 0x00, this->ctr_len);
|
2022-02-03 00:37:20 +01:00
|
|
|
fmt::print(stderr, "Generator initialized\n");
|
2022-01-10 04:25:03 +01:00
|
|
|
}
|
|
|
|
catch (CryptoPP::Exception& e) {
|
2021-12-05 03:13:47 +01:00
|
|
|
fmt::print(stderr, "{}\n", e.what());
|
2022-01-30 00:00:20 +01:00
|
|
|
throw;
|
2021-12-05 03:13:47 +01:00
|
|
|
}
|
2022-01-08 06:34:30 +01:00
|
|
|
}
|
2021-11-03 02:57:23 +01:00
|
|
|
|
2022-01-06 16:47:46 +01:00
|
|
|
auto Generator::get_state() const -> G_state {
|
2022-01-20 08:36:02 +01:00
|
|
|
std::lock_guard<std::recursive_mutex> lg(mtx);
|
|
|
|
|
2021-11-19 22:45:29 +01:00
|
|
|
return G;
|
2021-11-03 02:57:23 +01:00
|
|
|
}
|
|
|
|
|
2022-01-15 13:35:56 +01:00
|
|
|
auto Generator::time_to_reseed(
|
|
|
|
const uint64_t& pool0_len,
|
|
|
|
const unsigned int& min_p_size,
|
|
|
|
const std::chrono::duration<int64_t, std::ratio<1, 1000>>& time_elapsed,
|
|
|
|
const std::chrono::milliseconds& gen_reseed_interval) const -> bool {
|
2022-01-20 08:36:02 +01:00
|
|
|
std::lock_guard<std::recursive_mutex> lg(mtx);
|
|
|
|
|
2022-01-20 08:40:42 +01:00
|
|
|
return (pool0_len >= min_p_size && time_elapsed > gen_reseed_interval);
|
2022-01-08 07:24:04 +01:00
|
|
|
}
|
|
|
|
|
2021-11-13 21:58:05 +01:00
|
|
|
auto Generator::reseed(const std::string& s) -> void {
|
2022-01-20 08:36:02 +01:00
|
|
|
std::lock_guard<std::recursive_mutex> lg(mtx);
|
2022-01-09 11:58:38 +01:00
|
|
|
std::unique_lock<std::mutex> ul(reseed_mtx);
|
2022-01-20 08:36:02 +01:00
|
|
|
|
2021-11-30 14:09:39 +01:00
|
|
|
// ref: https://www.cryptopp.com/wiki/SecBlock
|
2021-12-10 20:02:30 +01:00
|
|
|
std::string da_key(reinterpret_cast<const char*>(&G.k[0]),
|
2022-01-10 04:25:03 +01:00
|
|
|
G.k.SizeInBytes() * 8); // we need the size in bits
|
2021-11-30 14:09:39 +01:00
|
|
|
|
2021-12-10 20:02:30 +01:00
|
|
|
try {
|
2022-01-03 05:17:29 +01:00
|
|
|
std::string a{fortuna::Util::do_sha(da_key + s)};
|
2022-01-30 22:40:21 +01:00
|
|
|
std::memmove(G.k, fortuna::Util::de_hex(a).c_str(), G.k_length);
|
2022-01-30 22:56:08 +01:00
|
|
|
Generator::ctr_inc();
|
2022-02-03 00:37:20 +01:00
|
|
|
fmt::print(stderr, "[i] generator: reseeded\n");
|
2022-01-10 04:25:03 +01:00
|
|
|
}
|
|
|
|
catch (std::exception& e) {
|
2022-02-03 00:37:20 +01:00
|
|
|
fmt::print(stderr, "{}\n", e.what());
|
2022-01-30 00:00:20 +01:00
|
|
|
throw;
|
2021-12-10 20:02:30 +01:00
|
|
|
}
|
2021-10-30 21:06:54 +02:00
|
|
|
}
|
|
|
|
|
2021-11-19 22:45:29 +01:00
|
|
|
auto Generator::do_crypto() -> std::string {
|
2021-10-19 15:05:18 +02:00
|
|
|
/* this function calls the block cipher
|
2021-10-27 18:53:53 +02:00
|
|
|
* returns a string of k*(16 bytes);
|
2021-11-03 02:57:23 +01:00
|
|
|
* do whatever atm */
|
2021-11-30 14:09:39 +01:00
|
|
|
|
2022-01-20 08:36:02 +01:00
|
|
|
std::lock_guard<std::recursive_mutex> lg(mtx);
|
|
|
|
|
2021-11-30 14:09:39 +01:00
|
|
|
// for the moment loosely based on
|
|
|
|
// https://www.cryptopp.com/wiki/CTR_Mode
|
|
|
|
|
|
|
|
// William Shakespeare, Romeo and Juliet
|
2022-01-26 22:43:22 +01:00
|
|
|
const std::string plain{"Oh, I am fortune's fool!"};
|
2021-11-30 14:09:39 +01:00
|
|
|
std::string cipher, encoded_c;
|
2022-01-09 11:58:38 +01:00
|
|
|
std::unique_lock<std::mutex> ul(crypt_mtx);
|
2022-01-30 22:56:08 +01:00
|
|
|
CryptoPP::FixedSizeSecBlock<CryptoPP::byte, Generator::ctr_len> ctr;
|
|
|
|
std::memmove(ctr, G.ctr.data(), Generator::ctr_len);
|
2021-11-30 14:09:39 +01:00
|
|
|
|
|
|
|
try {
|
2022-01-26 22:35:45 +01:00
|
|
|
this->enc.SetKeyWithIV(G.k, G.k.size(), ctr);
|
2021-11-30 14:09:39 +01:00
|
|
|
|
|
|
|
// The StreamTransformationFilter adds padding as required. ECB and
|
|
|
|
// CBC Mode must be padded to the block size of the cipher. CTR
|
|
|
|
// mode not.
|
|
|
|
// the "true" param - pump all of the data immediately to its
|
|
|
|
// attached transformation
|
2022-01-10 04:25:03 +01:00
|
|
|
CryptoPP::StringSource str_src1(
|
2022-01-13 06:04:18 +01:00
|
|
|
plain,
|
|
|
|
true,
|
2022-01-10 04:25:03 +01:00
|
|
|
new CryptoPP::StreamTransformationFilter(
|
2022-01-26 22:35:45 +01:00
|
|
|
this->enc,
|
2022-01-10 04:25:03 +01:00
|
|
|
new CryptoPP::StringSink(cipher)) // StreamTransformationFilter
|
2021-11-30 14:09:39 +01:00
|
|
|
); // StringSource
|
|
|
|
}
|
2022-01-10 04:25:03 +01:00
|
|
|
catch (CryptoPP::Exception& e) {
|
2021-11-30 14:09:39 +01:00
|
|
|
fmt::print(stderr, "{}\n", e.what());
|
2022-01-30 00:00:20 +01:00
|
|
|
throw;
|
2021-11-30 14:09:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pretty print cipher text
|
2022-01-10 04:25:03 +01:00
|
|
|
CryptoPP::StringSource str_src2(
|
2022-01-13 06:04:18 +01:00
|
|
|
cipher,
|
|
|
|
true,
|
2022-01-08 07:30:31 +01:00
|
|
|
new CryptoPP::HexEncoder(
|
2022-01-10 04:25:03 +01:00
|
|
|
new CryptoPP::StringSink(encoded_c)) // HexEncoder
|
2021-11-30 14:09:39 +01:00
|
|
|
); // StringSource
|
|
|
|
|
|
|
|
return encoded_c;
|
2021-10-19 15:05:18 +02:00
|
|
|
}
|
|
|
|
|
2021-11-13 21:58:05 +01:00
|
|
|
auto Generator::generate_blocks(unsigned int k_blocks) -> std::string {
|
2022-01-20 08:36:02 +01:00
|
|
|
std::lock_guard<std::recursive_mutex> lg(mtx);
|
|
|
|
|
2022-01-30 22:56:08 +01:00
|
|
|
assert((G.ctr != this->null_blk) &&
|
|
|
|
"Counter is not 0, generator has been seeded");
|
2022-01-26 22:59:37 +01:00
|
|
|
if (!this->is_seeded()) {
|
|
|
|
throw std::logic_error("G.ctr == 0, generator has not been seeded!");
|
|
|
|
}
|
2022-01-14 05:40:22 +01:00
|
|
|
|
2021-11-20 21:20:38 +01:00
|
|
|
std::string r{""};
|
2022-01-14 05:40:22 +01:00
|
|
|
while (k_blocks--) {
|
|
|
|
r += Generator::do_crypto();
|
2022-01-30 22:56:08 +01:00
|
|
|
Generator::ctr_inc();
|
2021-10-19 15:05:18 +02:00
|
|
|
}
|
2021-11-03 02:57:23 +01:00
|
|
|
return r;
|
2021-10-19 15:05:18 +02:00
|
|
|
}
|
|
|
|
|
2022-01-17 07:22:19 +01:00
|
|
|
auto Generator::generate_random_data(const unsigned int& n) -> std::string {
|
2022-01-20 08:36:02 +01:00
|
|
|
std::lock_guard<std::recursive_mutex> lg(mtx);
|
|
|
|
|
2021-12-11 21:33:42 +01:00
|
|
|
if (n == 0) {
|
2022-02-03 00:37:20 +01:00
|
|
|
// const std::string msg{"zero bytes requested, bailing\n"};
|
|
|
|
fmt::print(stderr, "[!] error: zero bytes requested, bailing\n");
|
2022-01-14 05:44:37 +01:00
|
|
|
// throw std::invalid_argument(msg);
|
|
|
|
// TODO(me): throw or not?
|
|
|
|
// perhaps just return prematurely
|
|
|
|
return "";
|
2021-12-11 21:33:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// pre-computed 2^20
|
|
|
|
if (n > 1048576) {
|
2022-02-03 00:37:20 +01:00
|
|
|
throw std::invalid_argument("[!] error: n cannot be > 2^20\n");
|
2021-10-19 15:05:18 +02:00
|
|
|
}
|
2021-11-30 14:09:39 +01:00
|
|
|
|
2021-12-10 20:02:30 +01:00
|
|
|
std::string r;
|
|
|
|
|
|
|
|
try {
|
|
|
|
/* do magic to compute r
|
2022-01-14 01:09:24 +01:00
|
|
|
* r ← first-n-bytes(GenerateBlocks(G, ceil(n/16) )) */
|
|
|
|
|
|
|
|
unsigned int how_many(
|
|
|
|
static_cast<unsigned int>(std::ceil(static_cast<double>(n) / 16)));
|
|
|
|
|
2021-12-10 20:02:30 +01:00
|
|
|
std::string rr{generate_blocks(how_many)};
|
2022-02-03 00:37:20 +01:00
|
|
|
fmt::print(stderr, "rr (output from generate_blocks): {}\n", rr);
|
2021-12-10 20:02:30 +01:00
|
|
|
|
|
|
|
// since we're truncating hex, we need to get twice more characters
|
2022-01-10 04:25:03 +01:00
|
|
|
r = rr.substr(0, n * 0x02ul);
|
2021-12-11 01:10:14 +01:00
|
|
|
rr.clear();
|
2022-01-10 04:25:03 +01:00
|
|
|
}
|
|
|
|
catch (std::exception& e) {
|
2022-02-03 00:37:20 +01:00
|
|
|
fmt::print(stderr, "{}", e.what());
|
2021-12-10 20:02:30 +01:00
|
|
|
}
|
2021-10-26 15:59:22 +02:00
|
|
|
|
|
|
|
/* re-key */
|
2021-12-10 20:02:30 +01:00
|
|
|
try {
|
|
|
|
std::string nu_G_k{generate_blocks(2)};
|
|
|
|
// fmt::print("nu_G_k: {}\n", nu_G_k); // debugging
|
2022-01-30 22:40:21 +01:00
|
|
|
std::string dst{fortuna::Util::de_hex(nu_G_k)};
|
2021-11-30 14:09:39 +01:00
|
|
|
|
2021-12-11 01:10:14 +01:00
|
|
|
nu_G_k.clear();
|
2021-11-30 14:09:39 +01:00
|
|
|
|
2021-12-10 20:02:30 +01:00
|
|
|
/* clear out the old key and set a new one */
|
2022-01-08 07:16:19 +01:00
|
|
|
std::memset(G.k, 0x00, G.k_length);
|
2022-01-08 07:06:31 +01:00
|
|
|
std::memmove(G.k, dst.c_str(), G.k_length);
|
2022-01-10 04:25:03 +01:00
|
|
|
}
|
|
|
|
catch (std::exception& e) {
|
2022-02-03 00:37:20 +01:00
|
|
|
fmt::print(stderr, "{}", e.what());
|
2021-12-10 20:02:30 +01:00
|
|
|
}
|
2021-11-03 02:57:23 +01:00
|
|
|
return r;
|
2022-01-03 01:02:05 +01:00
|
|
|
}
|
2021-10-19 15:05:18 +02:00
|
|
|
|
2022-01-27 22:54:53 +01:00
|
|
|
auto Generator::ctr_inc() -> void {
|
|
|
|
// increment the least-significant-byte-first ctr
|
|
|
|
|
|
|
|
std::atomic<uint8_t> i{0};
|
|
|
|
while (true) {
|
2022-01-30 22:56:08 +01:00
|
|
|
this->G.ctr.at(i) = static_cast<std::byte>(
|
|
|
|
static_cast<uint8_t>(this->G.ctr.at(i)) + 0x01);
|
2022-01-27 22:54:53 +01:00
|
|
|
|
2022-01-30 22:56:08 +01:00
|
|
|
if (this->G.ctr.at(i) == static_cast<std::byte>(0x00) &&
|
|
|
|
++i < this->G.ctr.size()) {
|
2022-01-27 22:54:53 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-03 02:57:23 +01:00
|
|
|
|
2021-11-01 09:23:22 +01:00
|
|
|
} // namespace generator
|
|
|
|
} // namespace fortuna
|
2021-11-03 02:57:23 +01:00
|
|
|
#endif
|