From 651ee7601bdaec35d1d3d4dc8c87976c9646c694 Mon Sep 17 00:00:00 2001 From: Dmitriy Suponitskiy Date: Tue, 29 Oct 2024 23:38:30 -0400 Subject: [PATCH 1/4] Additional support for external PRNGs: make source of entropy configurable --- src/core/include/math/distributiongenerator.h | 6 +- src/core/include/utils/prng/blake2engine.h | 24 ++- src/core/include/utils/prng/prng.h | 37 ++--- src/core/lib/math/distributiongenerator.cpp | 149 ++++-------------- src/core/lib/utils/prng/blake2engine.cpp | 104 +++++++++++- 5 files changed, 164 insertions(+), 156 deletions(-) diff --git a/src/core/include/math/distributiongenerator.h b/src/core/include/math/distributiongenerator.h index 70cbbebe..3678b30f 100644 --- a/src/core/include/math/distributiongenerator.h +++ b/src/core/include/math/distributiongenerator.h @@ -43,10 +43,6 @@ #include namespace lbcrypto { -// if FIXED_SEED is defined, then PRNG uses a fixed seed number for reproducible results during debug. -// Use only one OMP thread to ensure reproducibility -// #define FIXED_SEED - /** * @brief PseudoRandomNumberGenerator provides the PRNG capability to all random distribution generators in OpenFHE. @@ -69,7 +65,7 @@ class PseudoRandomNumberGenerator { static PRNG& GetPRNG(); private: - using GenPRNGEngineFuncPtr = PRNG* (*)(const PRNG::seed_array_t&, uint64_t counter); + using GenPRNGEngineFuncPtr = PRNG* (*)(); // shared pointer to a thread-specific PRNG engine static std::shared_ptr m_prng; diff --git a/src/core/include/utils/prng/blake2engine.h b/src/core/include/utils/prng/blake2engine.h index 4ac7fa48..abc7b166 100644 --- a/src/core/include/utils/prng/blake2engine.h +++ b/src/core/include/utils/prng/blake2engine.h @@ -39,6 +39,7 @@ #include "utils/prng/prng.h" #include +#include namespace default_prng { /** @@ -47,17 +48,24 @@ namespace default_prng { */ class Blake2Engine : public PRNG { public: + enum { + MAX_SEED_GENS = 16, + // the buffer stores 1024 samples of 32-bit integers + PRNG_BUFFER_SIZE = 1024 + }; + using blake2_seed_array_t = std::array; + /** * @brief Main constructor taking a vector of MAX_SEED_GENS integers as a seed and a counter. * If there is no value for the counter, then pass zero as the counter value */ - explicit Blake2Engine(const PRNG::seed_array_t& seed, uint64_t counter) : PRNG(seed, counter) {} + explicit Blake2Engine(const blake2_seed_array_t& seed, uint64_t counter) : m_seed(seed), m_counter(counter) {} /** * @brief main call to the PRNG */ PRNG::result_type operator()() override { - if (m_bufferIndex == static_cast(PRNG::PRNG_BUFFER_SIZE)) + if (m_bufferIndex == static_cast(PRNG_BUFFER_SIZE)) m_bufferIndex = 0; // makes a call to the BLAKE2 generator only when the currently buffered values are all consumed precomputations and @@ -78,19 +86,25 @@ class Blake2Engine : public PRNG { void Generate(); // The vector that stores random samples generated using the hash function - std::array m_buffer{}; + std::array m_buffer{}; // Index in m_buffer corresponding to the current PRNG sample size_t m_bufferIndex = 0; + + // the seed for the hash function + blake2_seed_array_t m_seed{}; + + // counter used as input to the hash function; gets incremented after each call + uint64_t m_counter = 0; }; /** * @brief createEngineInstance() generates a Blake2Engine object which is dynamically allocated * @return pointer to the generated Blake2Engine object - * @attention the caller is responsible for freeing the memory allocated by this function + * @attention the caller is responsible for freeing the memory allocated by this function **/ extern "C" { - PRNG* createEngineInstance(const PRNG::seed_array_t& seed, uint64_t counter); + PRNG* createEngineInstance(); } } // namespace default_prng diff --git a/src/core/include/utils/prng/prng.h b/src/core/include/utils/prng/prng.h index c6483013..8860e363 100644 --- a/src/core/include/utils/prng/prng.h +++ b/src/core/include/utils/prng/prng.h @@ -31,12 +31,12 @@ /** * DISCLAIMER: IMPORTANT NOTICE ABOUT FILE MODIFICATIONS - * - * This file is used in OpenFHE's built-in PRNG and ANY EXTERNAL PRNG. + * + * This file is used in OpenFHE's built-in PRNG and ANY EXTERNAL PRNG. * The file is critical to the functionality and the security of the library. - * + * * Modifications should only be performed by personnel who understand the potential impacts. - * + * * By proceeding with changes to this file, you acknowledge that you understand the risks involved and * accept full responsibility for any resulting issues. */ @@ -50,31 +50,22 @@ #include #include -#include - // ATTENTION (VERY IMPORTANT): // for any engine class derived from the PRNG class there must be a C function named "createEngineInstance" -// returning a dynamically allocated object of that derived class (see how it is done in blake2engine.h) +// returning a dynamically allocated object of that derived class (see how it is done in blake2engine.h) class PRNG { public: - enum { - MAX_SEED_GENS = 16, - // the buffer stores 1024 samples of 32-bit integers - PRNG_BUFFER_SIZE = 1024 - }; - // all C++11 distributions used in OpenFHE work with uint32_t by default. // a different data type can be specified if needed for a particular architecture - using result_type = uint32_t; - using seed_array_t = std::array; + using result_type = uint32_t; /** * @brief minimum value used by C++11 distribution generators when no lower * bound is explicitly specified by the user */ static constexpr result_type min() { - return std::numeric_limits::min(); + return std::numeric_limits::min(); } /** @@ -82,21 +73,13 @@ class PRNG { * bound is explicitly specified by the user */ static constexpr result_type max() { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } virtual result_type operator()() = 0; - virtual ~PRNG() = default; + virtual ~PRNG() = default; protected: PRNG() = default; - PRNG(const seed_array_t &seed, uint64_t counter) : m_counter(counter), m_seed(seed) {} - - // counter used as input to the hash function; gets incremented after each call - uint64_t m_counter = 0; - - // the seed for the hash function - seed_array_t m_seed{}; }; -#endif // __PRNG_H__ - +#endif // __PRNG_H__ diff --git a/src/core/lib/math/distributiongenerator.cpp b/src/core/lib/math/distributiongenerator.cpp index 29461fed..570f6e89 100644 --- a/src/core/lib/math/distributiongenerator.cpp +++ b/src/core/lib/math/distributiongenerator.cpp @@ -36,13 +36,8 @@ #include "math/distributiongenerator.h" #include "utils/prng/blake2engine.h" -#include "utils/memory.h" #include "utils/exception.h" -#include -#include -#include -#include #include #if (defined(__linux__) || defined(__unix__)) && !defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__) #include @@ -50,142 +45,62 @@ namespace lbcrypto { -std::shared_ptr PseudoRandomNumberGenerator::m_prng = nullptr; +std::shared_ptr PseudoRandomNumberGenerator::m_prng = nullptr; PseudoRandomNumberGenerator::GenPRNGEngineFuncPtr PseudoRandomNumberGenerator::genPRNGEngine = nullptr; void PseudoRandomNumberGenerator::InitPRNGEngine(const std::string& libPath) { - if(genPRNGEngine) // if genPRNGEngine has already been initialized - return; + if (genPRNGEngine) // if genPRNGEngine has already been initialized + return; - if(libPath.empty()) { - // use the default OpenFHE PRNG that comes with the library + if (libPath.empty()) { + // use the default OpenFHE PRNG that comes with the library genPRNGEngine = default_prng::createEngineInstance; if (!genPRNGEngine) OPENFHE_THROW("Cannot find symbol: default_prng::createEngineInstance"); // std::cerr << "InitPRNGEngine: using local PRNG" << std::endl; } else { - #if (defined(__linux__) || defined(__unix__)) && !defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__) - // enable this code for g++ on Linux only - // do not close libraryHandle, your application will crash if you do - void* libraryHandle = dlopen(libPath.c_str(), RTLD_LAZY); - if (!libraryHandle) { - std::string errMsg{std::string("Cannot open ") + libPath + ": "}; - const char* dlsym_error = dlerror(); - errMsg += dlsym_error; - OPENFHE_THROW(errMsg); - } - genPRNGEngine = (GenPRNGEngineFuncPtr)dlsym(libraryHandle, "createEngineInstance"); - if (!genPRNGEngine) { - std::string errMsg{std::string("Cannot load symbol createEngineInstance() from ") + libPath}; - const char* dlsym_error = dlerror(); - errMsg += ": "; - errMsg += dlsym_error; - dlclose(libraryHandle); - OPENFHE_THROW(errMsg); - } - std::cerr << __FUNCTION__ << ": using external PRNG" << std::endl; - #else - OPENFHE_THROW("OpenFHE may use an external PRNG library linked with g++ on Linux only"); - #endif +#if (defined(__linux__) || defined(__unix__)) && !defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__) + // enable this code for g++ on Linux only + // do not close libraryHandle, your application will crash if you do + void* libraryHandle = dlopen(libPath.c_str(), RTLD_LAZY); + if (!libraryHandle) { + std::string errMsg{std::string("Cannot open ") + libPath + ": "}; + const char* dlsym_error = dlerror(); + errMsg += dlsym_error; + OPENFHE_THROW(errMsg); + } + genPRNGEngine = (GenPRNGEngineFuncPtr)dlsym(libraryHandle, "createEngineInstance"); + if (!genPRNGEngine) { + std::string errMsg{std::string("Cannot load symbol createEngineInstance() from ") + libPath}; + const char* dlsym_error = dlerror(); + errMsg += ": "; + errMsg += dlsym_error; + dlclose(libraryHandle); + OPENFHE_THROW(errMsg); + } + std::cerr << __FUNCTION__ << ": using external PRNG" << std::endl; +#else + OPENFHE_THROW("OpenFHE may use an external PRNG library linked with g++ on Linux only"); +#endif } -} +} PRNG& PseudoRandomNumberGenerator::GetPRNG() { // initialization of PRNGs if (m_prng == nullptr) { #pragma omp critical { - // we would like to believe that the block of code below is a good defense line + // we would like to believe that the block of code below is a good defense line if (!genPRNGEngine) InitPRNGEngine(); if (!genPRNGEngine) OPENFHE_THROW("Failure to initialize the PRNG engine"); - PRNG::seed_array_t seed{}; - #if defined(FIXED_SEED) - // Only used for debugging in the single-threaded mode. - std::cerr << "**FOR DEBUGGING ONLY!!!! Using fixed initializer for PRNG. " - "Use a single thread only, e.g., OMP_NUM_THREADS=1!" - << std::endl; - - seed[0] = 1; - #else - // A 512-bit seed is generated for each thread (this roughly corresponds - // to 256 bits of security). The seed is the sum of a random sample - // generated using std::random_device (typically works correctly in - // Linux, MacOS X, and MinGW starting with GCC 9.2) and a PRNG sample - // seeded from current time stamp, a hash of the current thread, and a - // memory location of a heap variable. The PRNG sample is added in - // case random_device is deterministic (happens on MinGW with GCC - // below 9.2). All future calls to PRNG use the seed generated here. - - // The code below derives randomness from time, thread id, and a memory - // location of a heap variable. This seed is relevant only if the - // implementation of random_device is deterministic (as in older - // versions of GCC in MinGW) - PRNG::seed_array_t initKey{}; - // high-resolution clock typically has a nanosecond tick period - // Arguably this may give up to 32 bits of entropy as the clock gets - // recycled every 4.3 seconds - initKey[0] = std::chrono::high_resolution_clock::now().time_since_epoch().count(); - // A thread id is often close to being random (on most systems) - initKey[1] = std::hash{}(std::this_thread::get_id()); - // On a 64-bit machine, the thread id is 64 bits long - // skip on 32-bit arm architectures - #if !defined(__arm__) && !defined(__EMSCRIPTEN__) - if (sizeof(size_t) == 8) - initKey[2] = (std::hash{}(std::this_thread::get_id()) >> 32); - #endif - // heap variable; we are going to use the least 32 bits of its memory - // location as the counter. This will increase the entropy of the PRNG sample - void* mem = malloc(1); - uint64_t counter = reinterpret_cast(mem); - free(mem); - - std::uniform_int_distribution distribution(0); - // the code below is wrapped in to {} as we want to get rid of gen immediately after the loop - { - // "PRNG* gen" points at a dynamically allocated (using c++'s new()) memory!!! - std::unique_ptr gen(genPRNGEngine(initKey, counter)); - for (auto& s : seed) - s = distribution(*gen); - } - - PRNG::seed_array_t rdseed{}; - size_t attempts = 3; - bool rdGenPassed = false; - for (size_t i = 0; i < attempts && !rdGenPassed; ++i) { - try { - std::random_device genR; - for (auto& rds : rdseed) { - // we use the fact that there is no overflow for unsigned integers - // (from C++ standard) i.e., arithmetic mod 2^32 is performed. For - // the seed to be random, it is sufficient for one of the two - // samples below to be random. In almost all practical cases, - // distribution(genR) is random. We add distribution(gen) just in - // case there is an implementation issue with random_device (as in - // older MinGW systems). - rds = distribution(genR); - } - rdGenPassed = true; - } - catch (std::exception& e) { - } - } - for (uint32_t i = 0; i < PRNG::MAX_SEED_GENS; ++i) - seed[i] += rdseed[i]; - - // re-init rdseed for security reasons - const size_t bytes_to_clear = (rdseed.size()*sizeof(rdseed[0])); - secure_memset(rdseed.data(), 0, bytes_to_clear); - #endif // FIXED_SEED - m_prng = std::shared_ptr(genPRNGEngine(seed, 0)); - // re-init seed for security reasons - secure_memset(seed.data(), 0, bytes_to_clear); + m_prng = std::shared_ptr(genPRNGEngine()); if (!m_prng) OPENFHE_THROW("Cannot create a PRNG engine"); - } // pragma omp critical + } // pragma omp critical } return *m_prng; } diff --git a/src/core/lib/utils/prng/blake2engine.cpp b/src/core/lib/utils/prng/blake2engine.cpp index 745be30e..810adf87 100644 --- a/src/core/lib/utils/prng/blake2engine.cpp +++ b/src/core/lib/utils/prng/blake2engine.cpp @@ -31,6 +31,12 @@ #include "utils/prng/blake2engine.h" #include "utils/prng/blake2.h" #include "utils/exception.h" +#include "utils/memory.h" + +#include +// #include +#include +#include namespace default_prng { @@ -44,8 +50,102 @@ void Blake2Engine::Generate() { m_counter++; } -PRNG* createEngineInstance(const PRNG::seed_array_t& seed, uint64_t counter) { - return new Blake2Engine(seed, counter); +extern "C" { +// if FIXED_SEED is defined, then PRNG uses a fixed seed number for reproducible results during debug. +// Use only one OMP thread to ensure reproducibility +// #define FIXED_SEED + +/** + * @brief Blake2SeedGenerator generates the seed array for the Blake2 PRNG engine used by OpenFHE. + * This function should be declared as static to make it local to this source file. + */ +static void Blake2SeedGenerator(Blake2Engine::blake2_seed_array_t& seed) { +#if defined(FIXED_SEED) + // Only used for debugging in the single-threaded mode. + std::cerr << "**FOR DEBUGGING ONLY!!!! Using fixed initializer for PRNG. " + "Use a single thread only, e.g., OMP_NUM_THREADS=1!" + << std::endl; + + seed[0] = 1; +#else + // A 512-bit seed is generated for each thread (this roughly corresponds + // to 256 bits of security). The seed is the sum of a random sample + // generated using std::random_device (typically works correctly in + // Linux, MacOS X, and MinGW starting with GCC 9.2) and a PRNG sample + // seeded from current time stamp, a hash of the current thread, and a + // memory location of a heap variable. The PRNG sample is added in + // case random_device is deterministic (happens on MinGW with GCC + // below 9.2). All future calls to PRNG use the seed generated here. + + // The code below derives randomness from time, thread id, and a memory + // location of a heap variable. This seed is relevant only if the + // implementation of random_device is deterministic (as in older + // versions of GCC in MinGW) + Blake2Engine::blake2_seed_array_t initKey{}; + // high-resolution clock typically has a nanosecond tick period + // Arguably this may give up to 32 bits of entropy as the clock gets + // recycled every 4.3 seconds + initKey[0] = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + // A thread id is often close to being random (on most systems) + initKey[1] = std::hash{}(std::this_thread::get_id()); + // On a 64-bit machine, the thread id is 64 bits long + // skip on 32-bit arm architectures + #if !defined(__arm__) && !defined(__EMSCRIPTEN__) + if (sizeof(size_t) == 8) + initKey[2] = (std::hash{}(std::this_thread::get_id()) >> 32); + #endif + // heap variable; we are going to use the least 32 bits of its memory + // location as the counter. This will increase the entropy of the PRNG sample + void* mem = malloc(1); + uint64_t counter = reinterpret_cast(mem); + free(mem); + + std::uniform_int_distribution distribution(0); + Blake2Engine gen(initKey, counter); + for (auto& s : seed) + s = distribution(gen); + + Blake2Engine::blake2_seed_array_t rdseed{}; + size_t attempts = 3; + bool rdGenPassed = false; + for (size_t i = 0; i < attempts && !rdGenPassed; ++i) { + try { + std::random_device genR; + for (auto& rds : rdseed) { + // we use the fact that there is no overflow for unsigned integers + // (from C++ standard) i.e., arithmetic mod 2^32 is performed. For + // the seed to be random, it is sufficient for one of the two + // samples below to be random. In almost all practical cases, + // distribution(genR) is random. We add distribution(gen) just in + // case there is an implementation issue with random_device (as in + // older MinGW systems). + rds = distribution(genR); + } + rdGenPassed = true; + } + catch (std::exception& e) { + } + } + for (uint32_t i = 0; i < Blake2Engine::MAX_SEED_GENS; ++i) + seed[i] += rdseed[i]; + + // re-init rdseed for security reasons + const size_t bytes_to_clear = (rdseed.size() * sizeof(rdseed[0])); + lbcrypto::secure_memset(rdseed.data(), 0, bytes_to_clear); +#endif // FIXED_SEED +} +} + +PRNG* createEngineInstance() { + Blake2Engine::blake2_seed_array_t seed{}; + Blake2SeedGenerator(seed); + PRNG* ptr = new Blake2Engine(seed, 0); + + // re-init seed for security reasons + const size_t bytes_to_clear = (seed.size() * sizeof(seed[0])); + lbcrypto::secure_memset(seed.data(), 0, bytes_to_clear); + + return ptr; } } // namespace default_prng From 093b3d639ab9fc9593b5d830dc2ccb77f6fbe3c3 Mon Sep 17 00:00:00 2001 From: Dmitriy Suponitskiy Date: Wed, 30 Oct 2024 00:44:59 -0400 Subject: [PATCH 2/4] Code corrections --- src/core/include/utils/memory.h | 2 +- src/core/lib/utils/memory.cpp | 8 ++++---- src/core/lib/utils/prng/blake2engine.cpp | 3 +++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/core/include/utils/memory.h b/src/core/include/utils/memory.h index 99ebf962..562c18fb 100644 --- a/src/core/include/utils/memory.h +++ b/src/core/include/utils/memory.h @@ -80,7 +80,7 @@ void MoveAppend(std::vector& dst, std::vector& src) { } } -void secure_memset(void* mem, uint8_t c, size_t len); +void secure_memset(volatile void* mem, uint8_t c, size_t len); } // namespace lbcrypto diff --git a/src/core/lib/utils/memory.cpp b/src/core/lib/utils/memory.cpp index 9c4b6b44..89b0083f 100644 --- a/src/core/lib/utils/memory.cpp +++ b/src/core/lib/utils/memory.cpp @@ -32,10 +32,10 @@ namespace lbcrypto { -void secure_memset(void* mem, uint8_t c, size_t len) { - volatile uint8_t* volatile ptr = (volatile uint8_t* volatile)mem; - for(size_t i = 0; i< len; ++i) - *(ptr+i) = c; +void secure_memset(volatile void* mem, uint8_t c, size_t len) { + volatile uint8_t* ptr = (volatile uint8_t*)mem; + for (size_t i = 0; i < len; ++i) + *(ptr + i) = c; } } // namespace lbcrypto diff --git a/src/core/lib/utils/prng/blake2engine.cpp b/src/core/lib/utils/prng/blake2engine.cpp index 810adf87..3bf36814 100644 --- a/src/core/lib/utils/prng/blake2engine.cpp +++ b/src/core/lib/utils/prng/blake2engine.cpp @@ -126,6 +126,9 @@ static void Blake2SeedGenerator(Blake2Engine::blake2_seed_array_t& seed) { catch (std::exception& e) { } } + if (!rdGenPassed) + OPENFHE_THROW("std::random_device failed"); + for (uint32_t i = 0; i < Blake2Engine::MAX_SEED_GENS; ++i) seed[i] += rdseed[i]; From 98f14bc5b423956cc8c50db26b9a3dcaa0aff74d Mon Sep 17 00:00:00 2001 From: Dmitriy Suponitskiy Date: Wed, 30 Oct 2024 10:33:37 -0400 Subject: [PATCH 3/4] Minor changes to in-code comments --- src/core/include/math/distributiongenerator.h | 3 ++- src/core/include/utils/memory.h | 5 +++++ src/core/include/utils/prng/blake2engine.h | 4 ++-- src/core/lib/utils/prng/blake2engine.cpp | 5 ++--- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/core/include/math/distributiongenerator.h b/src/core/include/math/distributiongenerator.h index 3678b30f..0990b0cf 100644 --- a/src/core/include/math/distributiongenerator.h +++ b/src/core/include/math/distributiongenerator.h @@ -55,7 +55,8 @@ class PseudoRandomNumberGenerator { * @brief InitPRNGEngine() initializes the PRNG generator * @param libPath a string with the absolute path to an external PRNG library ("/path/to/libprng.so"). * If the string is empty, then the default (OpenFHE's built-in PRNG) library will be used. - * @note this function should be called at the beginning of main() if an external library to be used + * @note this function should be called at the beginning of main() if an external library to be used and + * prints a trace in this case. There is no trace for the built-in PRNG */ static void InitPRNGEngine(const std::string& libPath = std::string()); diff --git a/src/core/include/utils/memory.h b/src/core/include/utils/memory.h index 562c18fb..d8c08164 100644 --- a/src/core/include/utils/memory.h +++ b/src/core/include/utils/memory.h @@ -80,6 +80,11 @@ void MoveAppend(std::vector& dst, std::vector& src) { } } +/** + * @brief secure_memset() is a function with the same functionality which is provided by std::memset. + * Usually, the compiler optimizes a call to std::memset out if it is called for a memory which goes out of scope. + * This function is never optimized out and used to re-initialize a memory for security reasons. + */ void secure_memset(volatile void* mem, uint8_t c, size_t len); } // namespace lbcrypto diff --git a/src/core/include/utils/prng/blake2engine.h b/src/core/include/utils/prng/blake2engine.h index abc7b166..f2bdb5b7 100644 --- a/src/core/include/utils/prng/blake2engine.h +++ b/src/core/include/utils/prng/blake2engine.h @@ -56,7 +56,7 @@ class Blake2Engine : public PRNG { using blake2_seed_array_t = std::array; /** - * @brief Main constructor taking a vector of MAX_SEED_GENS integers as a seed and a counter. + * @brief Main constructor taking an array of integers as a seed and a counter. * If there is no value for the counter, then pass zero as the counter value */ explicit Blake2Engine(const blake2_seed_array_t& seed, uint64_t counter) : m_seed(seed), m_counter(counter) {} @@ -85,7 +85,7 @@ class Blake2Engine : public PRNG { */ void Generate(); - // The vector that stores random samples generated using the hash function + // The vector to store random samples generated using the hash function std::array m_buffer{}; // Index in m_buffer corresponding to the current PRNG sample diff --git a/src/core/lib/utils/prng/blake2engine.cpp b/src/core/lib/utils/prng/blake2engine.cpp index 3bf36814..a44c2cac 100644 --- a/src/core/lib/utils/prng/blake2engine.cpp +++ b/src/core/lib/utils/prng/blake2engine.cpp @@ -34,7 +34,6 @@ #include "utils/memory.h" #include -// #include #include #include @@ -132,7 +131,7 @@ static void Blake2SeedGenerator(Blake2Engine::blake2_seed_array_t& seed) { for (uint32_t i = 0; i < Blake2Engine::MAX_SEED_GENS; ++i) seed[i] += rdseed[i]; - // re-init rdseed for security reasons + // IMPORTANT: re-init rdseed for security reasons const size_t bytes_to_clear = (rdseed.size() * sizeof(rdseed[0])); lbcrypto::secure_memset(rdseed.data(), 0, bytes_to_clear); #endif // FIXED_SEED @@ -144,7 +143,7 @@ PRNG* createEngineInstance() { Blake2SeedGenerator(seed); PRNG* ptr = new Blake2Engine(seed, 0); - // re-init seed for security reasons + // IMPORTANT: re-init seed for security reasons const size_t bytes_to_clear = (seed.size() * sizeof(seed[0])); lbcrypto::secure_memset(seed.data(), 0, bytes_to_clear); From 9becdbcb1958fa2a61f9f03058152797906f9b52 Mon Sep 17 00:00:00 2001 From: Dmitriy Suponitskiy Date: Wed, 30 Oct 2024 16:30:05 -0400 Subject: [PATCH 4/4] Added destructor to Blake2Engine --- src/core/include/utils/prng/blake2engine.h | 48 +++++++++++----------- src/core/lib/utils/prng/blake2engine.cpp | 10 ++++- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/core/include/utils/prng/blake2engine.h b/src/core/include/utils/prng/blake2engine.h index f2bdb5b7..25dcf8a7 100644 --- a/src/core/include/utils/prng/blake2engine.h +++ b/src/core/include/utils/prng/blake2engine.h @@ -55,29 +55,31 @@ class Blake2Engine : public PRNG { }; using blake2_seed_array_t = std::array; - /** - * @brief Main constructor taking an array of integers as a seed and a counter. - * If there is no value for the counter, then pass zero as the counter value - */ - explicit Blake2Engine(const blake2_seed_array_t& seed, uint64_t counter) : m_seed(seed), m_counter(counter) {} - - /** - * @brief main call to the PRNG - */ - PRNG::result_type operator()() override { - if (m_bufferIndex == static_cast(PRNG_BUFFER_SIZE)) - m_bufferIndex = 0; - - // makes a call to the BLAKE2 generator only when the currently buffered values are all consumed precomputations and - // done only once for the current buffer - if (m_bufferIndex == 0) - Generate(); - - PRNG::result_type result = m_buffer[m_bufferIndex]; - m_bufferIndex++; - - return result; - } + /** + * @brief Main constructor taking an array of integers as a seed and a counter. + * If there is no value for the counter, then pass zero as the counter value + */ + explicit Blake2Engine(const blake2_seed_array_t& seed, uint64_t counter) : m_seed(seed), m_counter(counter) {} + + ~Blake2Engine(); + + /** + * @brief main call to the PRNG + */ + PRNG::result_type operator()() override { + if (m_bufferIndex == static_cast(PRNG_BUFFER_SIZE)) + m_bufferIndex = 0; + + // makes a call to the BLAKE2 generator only when the currently buffered values are all consumed precomputations and + // done only once for the current buffer + if (m_bufferIndex == 0) + Generate(); + + PRNG::result_type result = m_buffer[m_bufferIndex]; + m_bufferIndex++; + + return result; + } private: /** diff --git a/src/core/lib/utils/prng/blake2engine.cpp b/src/core/lib/utils/prng/blake2engine.cpp index a44c2cac..8b24f611 100644 --- a/src/core/lib/utils/prng/blake2engine.cpp +++ b/src/core/lib/utils/prng/blake2engine.cpp @@ -39,6 +39,12 @@ namespace default_prng { +Blake2Engine::~Blake2Engine() { + // IMPORTANT: re-init seed for security reasons + const size_t bytes_to_clear = (m_seed.size() * sizeof(m_seed[0])); + lbcrypto::secure_memset(m_seed.data(), 0, bytes_to_clear); +} + void Blake2Engine::Generate() { // m_counter is the input to the hash function // m_buffer is the output @@ -93,8 +99,8 @@ static void Blake2SeedGenerator(Blake2Engine::blake2_seed_array_t& seed) { if (sizeof(size_t) == 8) initKey[2] = (std::hash{}(std::this_thread::get_id()) >> 32); #endif - // heap variable; we are going to use the least 32 bits of its memory - // location as the counter. This will increase the entropy of the PRNG sample + // heap variable; we are going to use up to 64 bits of its memory location as the counter. + // This will increase the entropy of the PRNG sample void* mem = malloc(1); uint64_t counter = reinterpret_cast(mem); free(mem);