examples_util.h (4479B)
1 /************************************************************************* 2 * Copyright (c) 2020-2021 Elichai Turkel * 3 * Distributed under the CC0 software license, see the accompanying file * 4 * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * 5 *************************************************************************/ 6 7 /* 8 * This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems. 9 * It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below. 10 * 11 * Platform randomness sources: 12 * Linux -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom 13 * macOS -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html 14 * FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4 15 * OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom 16 * Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom 17 */ 18 19 #if defined(_WIN32) 20 /* 21 * The defined WIN32_NO_STATUS macro disables return code definitions in 22 * windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h. 23 */ 24 #define WIN32_NO_STATUS 25 #include <windows.h> 26 #undef WIN32_NO_STATUS 27 #include <ntstatus.h> 28 #include <bcrypt.h> 29 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) 30 #include <sys/random.h> 31 #elif defined(__OpenBSD__) 32 #include <unistd.h> 33 #else 34 #error "Couldn't identify the OS" 35 #endif 36 37 #include <stddef.h> 38 #include <limits.h> 39 #include <stdio.h> 40 41 42 /* Returns 1 on success, and 0 on failure. */ 43 static int fill_random(unsigned char* data, size_t size) { 44 #if defined(_WIN32) 45 NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG); 46 if (res != STATUS_SUCCESS || size > ULONG_MAX) { 47 return 0; 48 } else { 49 return 1; 50 } 51 #elif defined(__linux__) || defined(__FreeBSD__) 52 /* If `getrandom(2)` is not available you should fallback to /dev/urandom */ 53 ssize_t res = getrandom(data, size, 0); 54 if (res < 0 || (size_t)res != size ) { 55 return 0; 56 } else { 57 return 1; 58 } 59 #elif defined(__APPLE__) || defined(__OpenBSD__) 60 /* If `getentropy(2)` is not available you should fallback to either 61 * `SecRandomCopyBytes` or /dev/urandom */ 62 int res = getentropy(data, size); 63 if (res == 0) { 64 return 1; 65 } else { 66 return 0; 67 } 68 #endif 69 return 0; 70 } 71 72 static void print_hex(unsigned char* data, size_t size) { 73 size_t i; 74 printf("0x"); 75 for (i = 0; i < size; i++) { 76 printf("%02x", data[i]); 77 } 78 printf("\n"); 79 } 80 81 #if defined(_MSC_VER) 82 // For SecureZeroMemory 83 #include <Windows.h> 84 #endif 85 /* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ 86 static void secure_erase(void *ptr, size_t len) { 87 #if defined(_MSC_VER) 88 /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ 89 SecureZeroMemory(ptr, len); 90 #elif defined(__GNUC__) 91 /* We use a memory barrier that scares the compiler away from optimizing out the memset. 92 * 93 * Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f 94 * in BoringSSL (ISC License): 95 * As best as we can tell, this is sufficient to break any optimisations that 96 * might try to eliminate "superfluous" memsets. 97 * This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is 98 * pretty efficient, because the compiler can still implement the memset() efficiently, 99 * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by 100 * Yang et al. (USENIX Security 2017) for more background. 101 */ 102 memset(ptr, 0, len); 103 __asm__ __volatile__("" : : "r"(ptr) : "memory"); 104 #else 105 void *(*volatile const volatile_memset)(void *, int, size_t) = memset; 106 volatile_memset(ptr, 0, len); 107 #endif 108 }