[*] Harden time based RNG

[*] RNG needs specific optimal paths for Win10 and older oses
[+] Internal RtlGenRandom
This commit is contained in:
Reece Wilson 2023-07-11 17:58:20 +01:00
parent 655f1839c5
commit adefbbe16b
3 changed files with 72 additions and 18 deletions

View File

@ -49,6 +49,12 @@ namespace Aurora
} \
}
#define ADD_GET_PROC_INTERNAL_MAP(name, proc, symbol) \
if (h ## name) \
{ \
p ## proc = AuReinterpretCast<decltype(p ## proc)>(GetProcAddress(h ## name, #symbol)); \
}
if (pRtlGetVersion)
{
return;
@ -84,6 +90,8 @@ namespace Aurora
ADD_GET_PROC(AdvancedApi, CryptReleaseContext)
ADD_GET_PROC(AdvancedApi, CryptGenRandom)
ADD_GET_PROC_INTERNAL_MAP(AdvancedApi, RtlGenRandom, SystemFunction036)
ADD_GET_PROC(BCrypt, BCryptGenRandom)
#else

View File

@ -196,6 +196,11 @@ namespace Aurora
PULONG ActualResolution
);
inline BOOLEAN(__stdcall *pRtlGenRandom)(
PVOID RandomBuffer,
ULONG RandomBufferLength
);
inline bool gUseNativeWaitMutex {};
inline bool gUseNativeWaitCondvar {};
inline bool gUseNativeWaitSemapahore {};

View File

@ -79,6 +79,11 @@ namespace Aurora::RNG
return;
}
if (pRtlGenRandom)
{
return;
}
if (pCryptAcquireContextW)
{
if (!pCryptAcquireContextW(&gCryptoProv, NULL,
@ -100,15 +105,32 @@ namespace Aurora::RNG
{
if (pBCryptGenRandom)
{
#if !defined(AURORA_DONT_PREFER_WIN32_USERLAND_AES_RNG)
if (AuSwInfo::IsWindows10OrGreater() &&
pBCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, reinterpret_cast<PUCHAR>(pBuf), uLen, 0) == 0)
if (AuSwInfo::IsWindows10OrGreater() ||
AuBuild::kCurrentPlatform != AuBuild::EPlatform::ePlatformWin32)
{
if (pRtlGenRandom)
{
if (pRtlGenRandom(pBuf, uLen))
{
return uLen;
}
}
if (pBCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, reinterpret_cast<PUCHAR>(pBuf), uLen, 0) == 0)
{
return uLen;
}
}
if (pBCryptGenRandom(NULL, reinterpret_cast<PUCHAR>(pBuf), uLen, BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0)
{
return uLen;
}
#endif
}
if (pBCryptGenRandom(NULL, reinterpret_cast<PUCHAR>(pBuf), uLen, BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0)
if (pRtlGenRandom)
{
if (pRtlGenRandom(pBuf, uLen))
{
return uLen;
}
@ -136,44 +158,58 @@ namespace Aurora::RNG
#endif
static AuUInt32 RngStdC(AuUInt8 *pBuf, AuUInt32 uLen)
static AuUInt64 RngTimeClock()
{
clock_t t1;
int l, acc, bits, a, b;
#if 0
return clock(); // [...] resolution of 1 posix clock() tick (this is usually 1,000,000 == CLOCKS_PER_SEC per posix, but it can be 1k)
#else
return AuTime::SteadyClockNS() / 1000ull;
#endif
}
static AuUInt32 RngTimeBased(AuUInt8 *pBuf, AuUInt32 uLen)
{
AuUInt64 t1;
int l, acc, bits, a, b, c;
l = uLen;
acc = a = b = 0;
acc = a = b = c = 0;
bits = 8;
void *pASLRSeed = &RngTimeBased;
while (uLen--)
{
while (bits--) // for each bit in byte
{
do
{
t1 = clock();
while (t1 == clock()) // spin within the resolution of 1 posix clock() tick (this is usually 1,000,000 == CLOCKS_PER_SEC per posix, but it can be 1k)
t1 = RngTimeClock();
while (t1 == RngTimeClock()) // spin within 1 microseconds
{
a ^= 1; // flip
}
t1 = clock();
while (t1 == clock())
t1 = RngTimeClock();
while (t1 == RngTimeClock()) // spin within 1 microseconds
{
b ^= 1; // flip
}
} while (a == b); // ensure theres enough entropy for a deviation to occur
}
while (a == b); // ensure theres enough entropy for a deviation to occur
acc = (acc << 1) | a; // push the first bit state
}
*pBuf++ = acc;
*pBuf = AuFnv1a32Runtime(&acc, sizeof(acc)) ^
AuFnv1a32Runtime(&c, sizeof(c)) ^
AuFnv1a32Runtime(&pASLRSeed, sizeof(pASLRSeed));
c = *pBuf++;
acc = 0;
bits = 8;
}
// TODO: Is that whitening algorithm enough or should we work towards a continuous hash stream?
return l;
}
@ -193,7 +229,7 @@ namespace Aurora::RNG
return x;
}
#endif
x = RngStdC(pBuffer, uBytes);
x = RngTimeBased(pBuffer, uBytes);
if (x != 0)
{
return x;
@ -215,6 +251,11 @@ namespace Aurora::RNG
return;
}
if (pRtlGenRandom)
{
return;
}
if (pCryptReleaseContext)
{
pCryptReleaseContext(gCryptoProv, 0);