random.h 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. /*
  2. * Source: secp256k1/examples/examples_util.h
  3. */
  4. /*************************************************************************
  5. * Copyright (c) 2020-2021 Elichai Turkel *
  6. * Distributed under the CC0 software license, see the accompanying file *
  7. * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
  8. *************************************************************************/
  9. /*
  10. * This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems.
  11. * It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below.
  12. *
  13. * Platform randomness sources:
  14. * 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
  15. * 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
  16. * 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
  17. * OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom
  18. * Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
  19. */
  20. #if defined(_WIN32)
  21. /*
  22. * The defined WIN32_NO_STATUS macro disables return code definitions in
  23. * windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h.
  24. */
  25. #define WIN32_NO_STATUS
  26. #include <windows.h>
  27. #undef WIN32_NO_STATUS
  28. #include <ntstatus.h>
  29. #include <bcrypt.h>
  30. #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
  31. #include <sys/random.h>
  32. #elif defined(__OpenBSD__)
  33. #include <unistd.h>
  34. #else
  35. #error "Couldn't identify the OS"
  36. #endif
  37. #include <stddef.h>
  38. #include <limits.h>
  39. #include <stdio.h>
  40. /* Returns 1 on success, and 0 on failure. */
  41. static int fill_random(unsigned char* data, size_t size) {
  42. #if defined(_WIN32)
  43. NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
  44. if (res != STATUS_SUCCESS || size > ULONG_MAX) {
  45. return 0;
  46. } else {
  47. return 1;
  48. }
  49. #elif defined(__linux__) || defined(__FreeBSD__)
  50. /* If `getrandom(2)` is not available you should fallback to /dev/urandom */
  51. ssize_t res = getrandom(data, size, 0);
  52. if (res < 0 || (size_t)res != size ) {
  53. return 0;
  54. } else {
  55. return 1;
  56. }
  57. #elif defined(__APPLE__) || defined(__OpenBSD__)
  58. /* If `getentropy(2)` is not available you should fallback to either
  59. * `SecRandomCopyBytes` or /dev/urandom */
  60. int res = getentropy(data, size);
  61. if (res == 0) {
  62. return 1;
  63. } else {
  64. return 0;
  65. }
  66. #endif
  67. return 0;
  68. }