/* Copyright (c) 2020 tevador All rights reserved. */ #include "secure_random.hpp" #include #include #if defined(_WIN32) || defined(__CYGWIN__) #define WINAPI #include #include #elif defined __linux__ && defined __GLIBC__ #define STRINGIFY(x) #x #define STR(x) STRINGIFY(x) #if __GLIBC__ > 2 || __GLIBC_MINOR__ > 24 #define LINUX_GETENTROPY #include #else #pragma message("Warning: getentropy is not available in GLIBC " \ STR(__GLIBC__) "." STR(__GLIBC_MINOR__)) #define UNIX_FALLBACK #include #if defined(SYS_getrandom) #define LINUX_TRY_SYSCALL #include #include #else #pragma message("Warning: Kernel doesn't support SYS_getrandom") #endif #endif #else #define UNIX_FALLBACK #endif #if defined(UNIX_FALLBACK) #include #include #include #include #define RANDOM_FILE "/dev/urandom" #endif void secure_random::gen_bytes(void* output, size_t size) { #if defined(WINAPI) if (!RtlGenRandom(output, size)) { throw std::runtime_error("RtlGenRandom failed"); } #elif defined(LINUX_GETENTROPY) if (-1 == getentropy(output, size)) { throw std::runtime_error("getentropy failed"); } #else #if defined(LINUX_TRY_SYSCALL) if (size <= 256) { if (0 == syscall(SYS_getrandom, output, size, 0)) { return; } } #endif int fd = open(RANDOM_FILE, O_RDONLY); if (fd == -1) { throw std::runtime_error("Unable to open " RANDOM_FILE); } char* outptr = (char*)output; while (size) { ssize_t len = read(fd, outptr, size); if (len < 0) { if (errno != EINTR && errno != EAGAIN) { break; } continue; } outptr += len; size -= len; } close(fd); if (size) { throw std::runtime_error("Unable to read " RANDOM_FILE); } #endif }