diff --git a/src/base/utils/random.cpp b/src/base/utils/random.cpp index 99343f0e1..eb81aed2a 100644 --- a/src/base/utils/random.cpp +++ b/src/base/utils/random.cpp @@ -30,28 +30,26 @@ #include +#include #include -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) #include -#include -#else // Q_OS_WIN +#include "base/global.h" +#include "base/utils/os.h" +#elif defined(Q_OS_LINUX) +#include +#include +#include +#else #include #include #include #endif -#include - -#include "base/global.h" - -#ifdef Q_OS_WIN -#include "base/utils/os.h" -#endif - namespace { -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) class RandomLayer { // need to satisfy UniformRandomBitGenerator requirements @@ -59,10 +57,10 @@ namespace using result_type = uint32_t; RandomLayer() - : m_rtlGenRandom {Utils::OS::loadWinAPI(u"Advapi32.dll"_s, "SystemFunction036")} + : m_processPrng {Utils::OS::loadWinAPI(u"BCryptPrimitives.dll"_s, "ProcessPrng")} { - if (!m_rtlGenRandom) - qFatal("Failed to load RtlGenRandom()"); + if (!m_processPrng) + qFatal("Failed to load ProcessPrng()."); } static constexpr result_type min() @@ -78,18 +76,57 @@ namespace result_type operator()() { result_type buf = 0; - const bool result = m_rtlGenRandom(&buf, sizeof(buf)); + const bool result = m_processPrng(reinterpret_cast(&buf), sizeof(buf)); if (!result) - qFatal("RtlGenRandom() failed"); + qFatal("ProcessPrng() failed."); return buf; } private: - using PRTLGENRANDOM = BOOLEAN (WINAPI *)(PVOID, ULONG); - const PRTLGENRANDOM m_rtlGenRandom; + using PPROCESSPRNG = BOOL (WINAPI *)(PBYTE, SIZE_T); + const PPROCESSPRNG m_processPrng; }; -#else // Q_OS_WIN +#elif defined(Q_OS_LINUX) + class RandomLayer + { + // need to satisfy UniformRandomBitGenerator requirements + public: + using result_type = uint32_t; + + RandomLayer() + { + } + + static constexpr result_type min() + { + return std::numeric_limits::min(); + } + + static constexpr result_type max() + { + return std::numeric_limits::max(); + } + + result_type operator()() + { + const int RETRY_MAX = 3; + + for (int i = 0; i < RETRY_MAX; ++i) + { + result_type buf = 0; + const ssize_t result = ::getrandom(&buf, sizeof(buf), 0); + if (result == sizeof(buf)) // success + return buf; + + if (result < 0) + qFatal("getrandom() error. Reason: %s. Error code: %d.", std::strerror(errno), errno); + } + + qFatal("getrandom() failed. Reason: too many retries."); + } + }; +#else class RandomLayer { // need to satisfy UniformRandomBitGenerator requirements @@ -100,7 +137,7 @@ namespace : m_randDev {fopen("/dev/urandom", "rb")} { if (!m_randDev) - qFatal("Failed to open /dev/urandom. Reason: %s. Error code: %d.\n", std::strerror(errno), errno); + qFatal("Failed to open /dev/urandom. Reason: %s. Error code: %d.", std::strerror(errno), errno); } ~RandomLayer() @@ -122,7 +159,7 @@ namespace { result_type buf = 0; if (fread(&buf, sizeof(buf), 1, m_randDev) != 1) - qFatal("Read /dev/urandom error. Reason: %s. Error code: %d.\n", std::strerror(errno), errno); + qFatal("Read /dev/urandom error. Reason: %s. Error code: %d.", std::strerror(errno), errno); return buf; }