/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: RNGEntropy.cpp Date: 2022-9-17 File: RNG.cpp Date: 2021-6-11 Author: Reece ***/ #include #include "RNG.hpp" #include "RNGEntropy.hpp" #if defined(AURORA_PLATFORM_WIN32) #include #include #include #endif #if defined(AURORA_IS_POSIX_DERIVED) #include #endif #include "WELL.hpp" namespace Aurora::RNG { #if defined(AURORA_IS_POSIX_DERIVED) static int gDevURand; void EntropyInit() { gDevURand = ::open("/dev/urandom", O_RDONLY); if (gDevURand <= 0) { gDevURand = ::open("/dev/random", O_RDONLY); } if (gDevURand <= 0) { gDevURand = -1; } } static AuUInt32 RngUnix(AuUInt8 *buf, AuUInt32 len) { if (gDevURand == -1) { return 0; } return ::read(gDevURand, buf, len); } #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 *buf, AuUInt32 len) { #if defined(USE_OLD_NTCRYPT) if (!gCryptoProv) { return 0; } if (!::CryptGenRandom(gCryptoProv, len, buf)) { return 0; } return len; #else #if !defined(AURORA_DONT_PREFER_WIN32_USERLAND_AES_RNG) if (::BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, reinterpret_cast(buf), len, 0) == 0) { return len; } #endif if (::BCryptGenRandom(NULL, reinterpret_cast(buf), len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0) { return len; } return 0; #endif } #else void EntropyInit() { } #endif static AuUInt32 RngStdC(AuUInt8 *buf, AuUInt32 len) { clock_t t1; int l, acc, bits, a, b; l = len; acc = a = b = 0; bits = 8; while (len--) { 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 } *buf++ = acc; acc = 0; bits = 8; } return l; } AuUInt32 RngGetBytes(AuUInt8 *out, AuUInt32 outlen) { AuUInt32 x; #if defined(AURORA_IS_MODERNNT_DERIVED) x = RngWin32(out, outlen); if (x != 0) { return x; } #elif defined(AURORA_IS_POSIX_DERIVED) x = RngUnix(out, outlen); if (x != 0) { return x; } #endif x = RngStdC(out, outlen); 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 } }