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-10-19 15:25:20 +02:00
|
|
|
#include <cmath>
|
|
|
|
#include <cassert>
|
2021-10-19 15:05:18 +02:00
|
|
|
#include <stdexcept>
|
2021-11-11 02:35:17 +01:00
|
|
|
|
2021-11-30 14:09:39 +01:00
|
|
|
#include <cryptopp/osrng.h>
|
|
|
|
#include <cryptopp/hex.h>
|
|
|
|
#include <cryptopp/filters.h>
|
|
|
|
#include <cryptopp/serpent.h>
|
|
|
|
#include <cryptopp/ccm.h>
|
2021-11-18 22:05:05 +01:00
|
|
|
#include <fmt/core.h>
|
2021-11-11 02:35:17 +01:00
|
|
|
|
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();
|
|
|
|
} catch(CryptoPP::Exception& e) {
|
|
|
|
fmt::print(stderr, "{}\n", e.what());
|
|
|
|
exit(1);
|
|
|
|
}
|
2021-11-19 22:45:29 +01:00
|
|
|
}
|
2021-12-11 20:43:48 +01:00
|
|
|
Generator::~Generator() noexcept {};
|
2021-10-19 15:05:18 +02:00
|
|
|
|
2021-11-30 14:09:39 +01:00
|
|
|
|
2021-11-03 02:57:23 +01:00
|
|
|
void Generator::initialize_generator(){
|
2021-12-05 03:13:47 +01:00
|
|
|
try {
|
|
|
|
std::memset(G.k, 0x00, G.k.size());
|
|
|
|
G.ctr = 0;
|
|
|
|
fmt::print("Generator initialized\n");
|
|
|
|
} catch(CryptoPP::Exception& e) {
|
|
|
|
fmt::print(stderr, "{}\n", e.what());
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
// FIXME: hardcoded seed for the time being
|
|
|
|
reseed("fortuna");
|
|
|
|
} catch(CryptoPP::Exception& e) {
|
|
|
|
fmt::print(stderr, "{}\n", e.what());
|
|
|
|
exit(1);
|
|
|
|
}
|
2021-11-03 02:57:23 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
auto Generator::get_state() -> G_state {
|
2021-11-19 22:45:29 +01:00
|
|
|
return G;
|
2021-11-03 02:57:23 +01:00
|
|
|
}
|
|
|
|
|
2021-11-13 21:58:05 +01:00
|
|
|
auto Generator::reseed(const std::string& s) -> void {
|
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]),
|
|
|
|
G.k.SizeInBytes() * 8); // we need the size in bits
|
2021-11-30 14:09:39 +01:00
|
|
|
std::string to_be_hashed{da_key+s};
|
|
|
|
// fmt::print("s -> {}\n", s); // debugging
|
|
|
|
// fmt::print("da_key -> {}\n", da_key); // debugging
|
|
|
|
// fmt::print("concat \"da_key + s\" -> {}\n", to_be_hashed); // debugging
|
|
|
|
|
2021-12-10 20:02:30 +01:00
|
|
|
try {
|
2021-12-13 02:18:37 +01:00
|
|
|
std::string a{fortuna::Util::do_sha(to_be_hashed)};
|
2021-12-11 01:04:57 +01:00
|
|
|
std::memmove(&G.k[0], &a[0], G.k.SizeInBytes());
|
2021-12-10 20:02:30 +01:00
|
|
|
++G.ctr;
|
|
|
|
} catch(std::exception& e) {
|
|
|
|
fmt::print("{}", e.what());
|
|
|
|
}
|
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
|
|
|
|
|
|
|
// for the moment loosely based on
|
|
|
|
// https://www.cryptopp.com/wiki/CTR_Mode
|
|
|
|
using CryptoPP::StringSource;
|
|
|
|
using CryptoPP::StringSink;
|
|
|
|
using CryptoPP::HexEncoder;
|
|
|
|
using CryptoPP::StreamTransformationFilter;
|
|
|
|
using CryptoPP::Serpent;
|
|
|
|
using CryptoPP::CTR_Mode;
|
|
|
|
|
|
|
|
CryptoPP::AutoSeededRandomPool prng;
|
|
|
|
// use 256bit key
|
|
|
|
CryptoPP::SecByteBlock key(CryptoPP::Serpent::MAX_KEYLENGTH);
|
|
|
|
|
|
|
|
prng.GenerateBlock(key,key.size());
|
|
|
|
|
|
|
|
// William Shakespeare, Romeo and Juliet
|
|
|
|
std::string plain{"Oh, I am fortune's fool!"};
|
|
|
|
std::string cipher, encoded_c;
|
|
|
|
// in case we need to convert counter to string
|
|
|
|
// std::string str_ctr{reinterpret_cast<const char*>(&G.k[0]), G.k.size()};
|
|
|
|
// std::string str_ctr{(G.ctr)};
|
|
|
|
// 16 bytes --> 128bit
|
|
|
|
static constexpr const std::size_t ctr_length{16};
|
|
|
|
CryptoPP::FixedSizeSecBlock<CryptoPP::byte, ctr_length> ctr;
|
2021-12-11 01:04:57 +01:00
|
|
|
std::memmove(&ctr, &G.ctr, ctr_length);
|
2021-11-30 14:09:39 +01:00
|
|
|
|
|
|
|
try {
|
|
|
|
// fmt::print("plain text: {}\n", plain);
|
|
|
|
|
|
|
|
CTR_Mode<Serpent>::Encryption e;
|
|
|
|
e.SetKeyWithIV(G.k,G.k.size(),ctr);
|
|
|
|
|
|
|
|
// 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
|
|
|
|
StringSource str_src1(plain,true,
|
|
|
|
new StreamTransformationFilter(e,
|
|
|
|
new StringSink(cipher)
|
|
|
|
) // StreamTransformationFilter
|
|
|
|
); // StringSource
|
|
|
|
}
|
|
|
|
catch(CryptoPP::Exception& e) {
|
|
|
|
fmt::print(stderr, "{}\n", e.what());
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pretty print cipher text
|
|
|
|
StringSource str_src2(cipher,true,
|
|
|
|
new HexEncoder(
|
|
|
|
new StringSink(encoded_c)
|
|
|
|
) // HexEncoder
|
|
|
|
); // StringSource
|
|
|
|
// fmt::print("cipher text: {}\n", encoded_c);
|
|
|
|
|
|
|
|
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 {
|
2021-11-16 00:17:16 +01:00
|
|
|
assert ((G.ctr!=0) && "Counter is not 0, generator has been seeded");
|
2021-11-30 14:09:39 +01:00
|
|
|
// fmt::print("k_blocks -> {}\n", k_blocks); // debugging
|
2021-11-20 21:20:38 +01:00
|
|
|
std::string r{""};
|
2021-10-19 15:05:18 +02:00
|
|
|
for (int i = 0; i < k_blocks; ++i) {
|
2021-11-19 22:45:29 +01:00
|
|
|
r += do_crypto();
|
2021-11-20 20:57:06 +01:00
|
|
|
++G.ctr;
|
2021-10-19 15:05:18 +02:00
|
|
|
}
|
2021-12-10 20:02:30 +01:00
|
|
|
try {
|
|
|
|
std::string da_key{""};
|
|
|
|
da_key.resize(G.k.size());
|
2021-12-11 01:04:57 +01:00
|
|
|
std::memmove(&da_key[0], &G.k[0], G.k_length);
|
2021-12-13 02:18:37 +01:00
|
|
|
da_key.clear();
|
2021-12-10 20:02:30 +01:00
|
|
|
} catch(std::exception& e) {
|
|
|
|
fmt::print("{}", e.what());
|
|
|
|
}
|
2021-11-30 14:09:39 +01:00
|
|
|
// fmt::print("r from generate_blocks -> {}\n", r); // debugging
|
2021-11-03 02:57:23 +01:00
|
|
|
return r;
|
2021-10-19 15:05:18 +02:00
|
|
|
}
|
|
|
|
|
2021-11-13 21:58:05 +01:00
|
|
|
auto Generator::generate_random_data(uint n) -> std::string {
|
2021-11-30 14:09:39 +01:00
|
|
|
// fmt::print("n -> {}\n", n); // debugging
|
2021-12-11 21:33:42 +01:00
|
|
|
if (n == 0) {
|
|
|
|
// do not do this..?
|
|
|
|
const std::string msg{"zero bytes requested, bailing\n"};
|
|
|
|
fmt::print("[*] error: {}", msg);
|
|
|
|
throw std::invalid_argument(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// pre-computed 2^20
|
|
|
|
if (n > 1048576) {
|
|
|
|
const std::string msg{"n cannot be > 2^20\n"};
|
|
|
|
fmt::print("[*] error: {}", msg);
|
|
|
|
throw std::invalid_argument(msg);
|
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
|
|
|
|
* r ← first-n-bytes(GenerateBlocks(G, ceil(n/16) )) */
|
|
|
|
// n is number of bytes, i.e. pass n*8 to get number of bits
|
|
|
|
unsigned int how_many(static_cast<unsigned int>(ceil((n*8)/16)));
|
|
|
|
// fmt::print("how_many: {}\n", how_many); // debugging
|
|
|
|
std::string rr{generate_blocks(how_many)};
|
|
|
|
fmt::print("rr (output from generate_blocks): {}\n", rr);
|
|
|
|
|
|
|
|
// since we're truncating hex, we need to get twice more characters
|
2021-12-11 01:13:01 +01:00
|
|
|
r = rr.substr(0,n*0x02ul);
|
2021-12-11 01:10:14 +01:00
|
|
|
rr.clear();
|
2021-12-10 20:02:30 +01:00
|
|
|
} catch(std::exception& e) {
|
|
|
|
fmt::print("{}", e.what());
|
|
|
|
}
|
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
|
|
|
|
std::string dst;
|
|
|
|
CryptoPP::StringSource str_s(
|
|
|
|
nu_G_k,true,new CryptoPP::HexDecoder(new CryptoPP::StringSink(dst))
|
|
|
|
);
|
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 */
|
|
|
|
std::memset(G.k, 0x00, G.k.size());
|
2021-12-11 01:04:57 +01:00
|
|
|
std::memmove(&G.k[0], &dst[0], dst.size());
|
2021-12-10 20:02:30 +01:00
|
|
|
} catch(std::exception& e) {
|
|
|
|
fmt::print("{}", e.what());
|
|
|
|
}
|
2021-11-03 02:57:23 +01:00
|
|
|
return r;
|
2021-10-19 15:05:18 +02:00
|
|
|
};
|
|
|
|
|
2021-11-03 02:57:23 +01:00
|
|
|
|
2021-11-11 02:25:41 +01:00
|
|
|
|
2021-11-01 09:23:22 +01:00
|
|
|
} // namespace generator
|
|
|
|
} // namespace fortuna
|
2021-11-03 02:57:23 +01:00
|
|
|
#endif
|