/******************************************************************************/ /* SlunkCrypt, by LoRd_MuldeR */ /* This work has been released under the CC0 1.0 Universal license! */ /******************************************************************************/ /* Internal */ #include "../include/slunkcrypt.h" /* CRT */ #include #include #include /* Platform compatibility */ #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN 1 # include #else # include # include #endif /* Compiler compatibility */ #if defined(__GNUC__) || defined(__clang__) # define HAVE_DESTRUCTOR 1 #else # define HAVE_DESTRUCTOR 0 #endif // ========================================================================== // Call once support // ========================================================================== #ifdef _WIN32 # define CALL_ONCE win32_call_once # define CALL_ONCE_TYPE volatile LONG # define CALL_ONCE_INIT 0L #else # define CALL_ONCE pthread_once # define CALL_ONCE_TYPE pthread_once_t # define CALL_ONCE_INIT PTHREAD_ONCE_INIT #endif #ifdef _WIN32 static void win32_call_once(CALL_ONCE_TYPE *const control, void (*init_routine)(void)) { LONG status; while ((status = InterlockedCompareExchange(control, -1L, 0L)) != 0L) { if(status > 0L) { return; /*already initialized*/ } SwitchToThread(); } init_routine(); InterlockedExchange(control, 1L); } #endif // ========================================================================== // Random bytes // ========================================================================== #ifdef _WIN32 # define HAVE_GETRANDOM 0 #else # if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25) # define HAVE_GETRANDOM 1 # elif defined(__FreeBSD__) && (__FreeBSD__ >= 12) # define HAVE_GETRANDOM 1 # else # define HAVE_GETRANDOM 0 # endif #endif #if HAVE_GETRANDOM # include #endif /* Global state */ static CALL_ONCE_TYPE s_random_is_initialized = CALL_ONCE_INIT; #if defined(_WIN32) typedef BOOLEAN(WINAPI *rtl_genrandom_t)(void *buffer, ULONG buff_size); static HMODULE s_dll_advapi32 = NULL; static rtl_genrandom_t s_rtl_genrandom = NULL; #elif !HAVE_GETRANDOM static const char *const DEV_RANDOM[] = { "/dev/urandom", "/dev/arandom", "/dev/random", NULL }; static int s_random_fd = -1; #endif /* De-initialize CSRNG */ static void exit_random_source(void) { #if defined(_WIN32) s_rtl_genrandom = NULL; if (s_dll_advapi32) { FreeLibrary(s_dll_advapi32); s_dll_advapi32 = NULL; } #elif !HAVE_GETRANDOM if (s_random_fd >= 0) { close(s_random_fd); s_random_fd = -1; } #endif } /* Initialize CSRNG */ static void init_random_source(void) { #if defined(_WIN32) if ((s_dll_advapi32 = LoadLibraryW(L"advapi32.dll"))) { s_rtl_genrandom = (rtl_genrandom_t)GetProcAddress(s_dll_advapi32, "SystemFunction036"); } #elif !HAVE_GETRANDOM for (size_t i = 0U; DEV_RANDOM[i]; ++i) { if ((s_random_fd = open(DEV_RANDOM[i], O_RDONLY)) >= 0) { break; /*success*/ } } #endif #if !HAVE_DESTRUCTOR atexit(exit_random_source); #endif } /* Generate random bytes */ size_t slunkcrypt_random_bytes(uint8_t* const buffer, const size_t length) { CALL_ONCE(&s_random_is_initialized, init_random_source); #if defined(_WIN32) if (s_rtl_genrandom) { const ULONG buff_size = (ULONG)length; return s_rtl_genrandom(buffer, buff_size) ? buff_size : 0U; } #elif HAVE_GETRANDOM const ssize_t result = getrandom(buffer, length, 0U); return (result < 0) ? 0U : ((size_t)result); #else if (s_random_fd >= 0) { const ssize_t result = read(s_random_fd, buffer, length); return (result < 0) ? 0U : ((size_t)result); } #endif return 0U; } // ========================================================================== // Zero memory // ========================================================================== #ifdef _WIN32 # ifdef SecureZeroMemory # define HAVE_EXPLICIT_BZERO 1 # define explicit_bzero SecureZeroMemory # else # define HAVE_EXPLICIT_BZERO 0 # endif #else # if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25) # define HAVE_EXPLICIT_BZERO 1 # elif defined(__FreeBSD__) && (__FreeBSD__ >= 11) # define HAVE_EXPLICIT_BZERO 1 # else # define HAVE_EXPLICIT_BZERO 0 # endif #endif void slunkcrypt_bzero(void* const buffer, const size_t length) { if ((buffer) && (length > 0U)) { #if HAVE_EXPLICIT_BZERO explicit_bzero(buffer, length); #else volatile uint8_t* ptr = (volatile uint8_t*) buffer; for (size_t i = 0U; i < length; ++i) { ptr[i] = 0U; } #endif } } // ========================================================================== // Destructor // ========================================================================== #if HAVE_DESTRUCTOR __attribute__((destructor)) void slunkcrypt_destructor() { exit_random_source(); } #endif