Skip to content

Commit

Permalink
Merge pull request #21333 from Chocobo1/random
Browse files Browse the repository at this point in the history
Improve PRNG functions
  • Loading branch information
Chocobo1 authored Sep 16, 2024
2 parents d2b2afa + 3058158 commit 23f7275
Showing 1 changed file with 59 additions and 22 deletions.
81 changes: 59 additions & 22 deletions src/base/utils/random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,39 +30,37 @@

#include <random>

#include <QtLogging>
#include <QtSystemDetection>

#ifdef Q_OS_WIN
#if defined(Q_OS_WIN)
#include <windows.h>
#include <ntsecapi.h>
#else // Q_OS_WIN
#include "base/global.h"
#include "base/utils/os.h"
#elif defined(Q_OS_LINUX)
#include <cerrno>
#include <cstring>
#include <sys/random.h>
#else
#include <cerrno>
#include <cstdio>
#include <cstring>
#endif

#include <QString>

#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
public:
using result_type = uint32_t;

RandomLayer()
: m_rtlGenRandom {Utils::OS::loadWinAPI<PRTLGENRANDOM>(u"Advapi32.dll"_s, "SystemFunction036")}
: m_processPrng {Utils::OS::loadWinAPI<PPROCESSPRNG>(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()
Expand All @@ -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<PBYTE>(&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
{
// need to satisfy UniformRandomBitGenerator requirements
public:
using result_type = uint32_t;

RandomLayer()
{
}

static constexpr result_type min()
{
return std::numeric_limits<result_type>::min();
}

static constexpr result_type max()
{
return std::numeric_limits<result_type>::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 // Q_OS_WIN
#else
class RandomLayer
{
// need to satisfy UniformRandomBitGenerator requirements
Expand All @@ -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()
Expand All @@ -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;
}
Expand Down

0 comments on commit 23f7275

Please sign in to comment.