/******************************************************************************/ /* 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 # define SCHED_YIELD() Sleep(1U) # define COMPARE_AND_SWAP(PTR,OLD,NEW) InterlockedCompareExchange((PTR),(NEW),(OLD)) # define ATOMIC_STORE(PTR,VAL) InterlockedExchange((PTR),(VAL)) # if defined(SecureZeroMemory) # define HAVE_SECURE_ZERO_MEMORY 1 # else # define HAVE_SECURE_ZERO_MEMORY 0 # endif # define HAVE_GETRANDOM 0 # define HAVE_EXPLICIT_BZERO 0 #else # include # include # define SCHED_YIELD() sched_yield() # if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER) # define COMPARE_AND_SWAP(PTR,OLD,NEW) __sync_val_compare_and_swap((PTR),(OLD),(NEW)) # define ATOMIC_STORE(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELEASE) # else # define COMPARE_AND_SWAP(PTR,OLD,NEW) ((OLD)) # define ATOMIC_STORE(PTR,VAL) do { *(PTR) = (VAL); } while(0) # endif # if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25) # define HAVE_GETRANDOM 1 # define HAVE_EXPLICIT_BZERO 1 # elif defined(__FreeBSD__) && (__FreeBSD__ >= 12) # define HAVE_GETRANDOM 1 # define HAVE_EXPLICIT_BZERO 1 # elif defined(__FreeBSD__) && (__FreeBSD__ >= 11) # define HAVE_GETRANDOM 0 # define HAVE_EXPLICIT_BZERO 1 # else # define HAVE_GETRANDOM 0 # define HAVE_EXPLICIT_BZERO 0 # endif # if HAVE_GETRANDOM # include # endif #endif // ========================================================================== // Critical sections // ========================================================================== static int enter_critsec(volatile long *const lock, const int flag) { const long expected = flag ? 0L : 1L; long status; while ((status = COMPARE_AND_SWAP(lock, expected, -1L)) < 0L) { SCHED_YIELD(); } return (status == expected); } static void leave_critsec(volatile long *const lock, const int flag) { ATOMIC_STORE(lock, flag ? 1L : 0L); } // ========================================================================== // (De)Initialization // ========================================================================== static volatile long s_initialized = 0L; #if defined(_WIN32) typedef BOOLEAN(WINAPI *genrandom_t)(void*, ULONG); static HMODULE s_advapi32 = NULL; static genrandom_t s_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 void slunkcrypt_startup(void) { if (enter_critsec(&s_initialized, 1)) { #if defined(_WIN32) if ((s_advapi32 = LoadLibraryW(L"advapi32.dll"))) { s_genrandom = (genrandom_t)GetProcAddress(s_advapi32, "SystemFunction036"); } #elif !HAVE_GETRANDOM for (size_t i = 0U; (s_random_fd < 0) && DEV_RANDOM[i]; ++i) { s_random_fd = open(DEV_RANDOM[i], O_RDONLY); } #endif leave_critsec(&s_initialized, 1); } } void slunkcrypt_cleanup(void) { if (enter_critsec(&s_initialized, 0)) { #if defined(_WIN32) s_genrandom = NULL; if (s_advapi32) { FreeLibrary(s_advapi32); s_advapi32 = NULL; } #elif !HAVE_GETRANDOM if (s_random_fd >= 0) { close(s_random_fd); s_random_fd = -1; } #endif leave_critsec(&s_initialized, 0); } } // ========================================================================== // Auxiliary functions // ========================================================================== int slunkcrypt_random_bytes(uint8_t* const buffer, const size_t length) { #if defined(_WIN32) if ((length <= ((size_t)ULONG_MAX))) { if (s_genrandom) { return s_genrandom(buffer, (ULONG)length) ? 0 : (-1); } } return -1; #elif HAVE_GETRANDOM if (getrandom(buffer, length, 0U) >= length) { return 0; } return -1; #else if (s_random_fd >= 0) { if (read(s_random_fd, buffer, length) >= length) { return 0; } } return -1; #endif } void slunkcrypt_bzero(void* const ptr, const size_t length) { if ((ptr) && (length > 0U)) { #if HAVE_SECURE_ZERO_MEMORY SecureZeroMemory(ptr, length); #elif HAVE_EXPLICIT_BZERO explicit_bzero(ptr, length); #else volatile uint8_t *buffer = (volatile uint8_t*)ptr; for (size_t i = 0U; i < length; ++i) { buffer[i] = 0U; } #endif } }