From dbef6da54414d5d5dd345bbc41f307ef33b76be7 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Thu, 12 Sep 2024 14:58:18 +0800 Subject: [PATCH 1/2] Use modern function for getting random numbers on Linux Now we don't need a file handle anymore and there is no initialization involved in this new implementation. --- src/base/utils/random.cpp | 52 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/base/utils/random.cpp b/src/base/utils/random.cpp index 99343f0e1..f08f439f5 100644 --- a/src/base/utils/random.cpp +++ b/src/base/utils/random.cpp @@ -30,12 +30,17 @@ #include +#include #include #ifdef Q_OS_WIN #include #include -#else // Q_OS_WIN +#elif defined(Q_OS_LINUX) +#include +#include +#include +#else #include #include #include @@ -89,7 +94,46 @@ namespace using PRTLGENRANDOM = BOOLEAN (WINAPI *)(PVOID, ULONG); const PRTLGENRANDOM m_rtlGenRandom; }; -#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 +144,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 +166,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; } From 3058158b69a80da13292c80ce46d95299b2fa609 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Thu, 12 Sep 2024 16:56:15 +0800 Subject: [PATCH 2/2] Use modern function for getting random numbers on Windows The previous `RtlGenRandom()` just redirects to `ProcessPrng()` according to "The Windows 10 random number generation infrastructure" whitepaper from MS. `ProcessPrng()` is also the de facto PRNG for Rust lang: https://github.com/rust-random/getrandom/blob/aa13fa58821180248507b81c967d3c731a2ca1d5/src/windows.rs#L3C1-L22C81 And for golang: https://go-review.googlesource.com/c/go/+/536235 --- src/base/utils/random.cpp | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/base/utils/random.cpp b/src/base/utils/random.cpp index f08f439f5..eb81aed2a 100644 --- a/src/base/utils/random.cpp +++ b/src/base/utils/random.cpp @@ -33,9 +33,10 @@ #include #include -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) #include -#include +#include "base/global.h" +#include "base/utils/os.h" #elif defined(Q_OS_LINUX) #include #include @@ -46,17 +47,9 @@ #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 @@ -64,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() @@ -83,16 +76,16 @@ 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; }; #elif defined(Q_OS_LINUX) class RandomLayer