/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuRNGEntropy.cpp Date: 2022-9-17 File: RNG.cpp Date: 2021-6-11 Author: Reece ***/ #include #include "AuRNG.hpp" #include "AuRNGEntropy.hpp" #if defined(AURORA_PLATFORM_WIN32) #include #include #include #endif #if defined(AURORA_IS_POSIX_DERIVED) #include #include #endif #include "AuWELL.hpp" namespace Aurora::RNG { #if defined(AURORA_IS_POSIX_DERIVED) static int gDevURand; void EntropyInit() { gDevURand = ::open("/dev/urandom", O_RDONLY | O_CLOEXEC); if (gDevURand <= 0) { gDevURand = ::open("/dev/random", O_RDONLY | O_CLOEXEC); } if (gDevURand <= 0) { gDevURand = -1; } } static AuUInt32 RngUnix(AuUInt8 *pBuf, AuUInt32 uLen) { if (gDevURand == -1) { return 0; } return ::read(gDevURand, pBuf, uLen); } #elif defined(AURORA_IS_MODERNNT_DERIVED) #if defined(USE_OLD_NTCRYPT) static HCRYPTPROV gCryptoProv; #endif void EntropyInit() { #if defined(USE_OLD_NTCRYPT) if (!CryptAcquireContext(&gCryptoProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET))) { if (!CryptAcquireContext(&gCryptoProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) { gCryptoProv = 0; } } #endif } static AuUInt32 RngWin32(AuUInt8 *pBuf, AuUInt32 uLen) { #if defined(USE_OLD_NTCRYPT) if (!gCryptoProv) { return 0; } if (!::CryptGenRandom(gCryptoProv, uLen, pBuf)) { return 0; } return uLen; #else #if !defined(AURORA_DONT_PREFER_WIN32_USERLAND_AES_RNG) #if !defined(BCRYPT_RNG_ALG_HANDLE) #define BCRYPT_RNG_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000081) #endif if (AuSwInfo::IsWindows10OrGreater() && ::BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, reinterpret_cast(pBuf), uLen, 0) == 0) { return uLen; } #endif if (::BCryptGenRandom(NULL, reinterpret_cast(pBuf), uLen, BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0) { return uLen; } return 0; #endif } #else void EntropyInit() { } #endif static AuUInt32 RngStdC(AuUInt8 *pBuf, AuUInt32 uLen) { clock_t t1; int l, acc, bits, a, b; l = uLen; acc = a = b = 0; bits = 8; while (uLen--) { while (bits--) // for each bit in byte { do { t1 = clock(); while (t1 == clock()) // spin within the resolution of 1 C clock() tick { a ^= 1; // flip } t1 = clock(); while (t1 == clock()) { b ^= 1; // flip } } while (a == b); // ensure theres enough entropy for a deviation to occur acc = (acc << 1) | a; // push the first bit state } *pBuf++ = acc; acc = 0; bits = 8; } return l; } AuUInt32 RngGetBytes(AuUInt8 *pBuffer, AuUInt32 uBytes) { AuUInt32 x; #if defined(AURORA_IS_MODERNNT_DERIVED) x = RngWin32(pBuffer, uBytes); if (x != 0) { return x; } #elif defined(AURORA_IS_POSIX_DERIVED) x = RngUnix(pBuffer, uBytes); if (x != 0) { return x; } #endif x = RngStdC(pBuffer, uBytes); if (x != 0) { return x; } return 0; } void EntropyDeinit() { #if defined(AURORA_IS_POSIX_DERIVED) if (gDevURand > 0) { ::close(gDevURand); } #elif defined(AURORA_IS_MODERNNT_DERIVED) && defined(USE_OLD_NTCRYPT) CryptReleaseContext(gCryptoProv, 0); #endif } }