random.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. //===-------------------------- random.cpp --------------------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is dual licensed under the MIT and the University of Illinois Open
  6. // Source Licenses. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include <__config>
  10. #if !defined(_LIBCPP_SGX_CONFIG)
  11. #if defined(_LIBCPP_USING_WIN32_RANDOM)
  12. // Must be defined before including stdlib.h to enable rand_s().
  13. #define _CRT_RAND_S
  14. #endif // defined(_LIBCPP_USING_WIN32_RANDOM)
  15. #include "random"
  16. #include "system_error"
  17. #if defined(__sun__)
  18. #define rename solaris_headers_are_broken
  19. #endif // defined(__sun__)
  20. #include <errno.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #if defined(_LIBCPP_USING_DEV_RANDOM)
  24. #include <fcntl.h>
  25. #include <unistd.h>
  26. #elif defined(_LIBCPP_USING_NACL_RANDOM)
  27. #include <nacl/nacl_random.h>
  28. #endif
  29. _LIBCPP_BEGIN_NAMESPACE_STD
  30. #if defined(_LIBCPP_USING_ARC4_RANDOM)
  31. random_device::random_device(const string& __token)
  32. {
  33. if (__token != "/dev/urandom")
  34. __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
  35. }
  36. random_device::~random_device()
  37. {
  38. }
  39. unsigned
  40. random_device::operator()()
  41. {
  42. return arc4random();
  43. }
  44. #elif defined(_LIBCPP_USING_DEV_RANDOM)
  45. random_device::random_device(const string& __token)
  46. : __f_(open(__token.c_str(), O_RDONLY))
  47. {
  48. if (__f_ < 0)
  49. __throw_system_error(errno, ("random_device failed to open " + __token).c_str());
  50. }
  51. random_device::~random_device()
  52. {
  53. close(__f_);
  54. }
  55. unsigned
  56. random_device::operator()()
  57. {
  58. unsigned r;
  59. size_t n = sizeof(r);
  60. char* p = reinterpret_cast<char*>(&r);
  61. while (n > 0)
  62. {
  63. ssize_t s = read(__f_, p, n);
  64. if (s == 0)
  65. __throw_system_error(ENODATA, "random_device got EOF");
  66. if (s == -1)
  67. {
  68. if (errno != EINTR)
  69. __throw_system_error(errno, "random_device got an unexpected error");
  70. continue;
  71. }
  72. n -= static_cast<size_t>(s);
  73. p += static_cast<size_t>(s);
  74. }
  75. return r;
  76. }
  77. #elif defined(_LIBCPP_USING_NACL_RANDOM)
  78. random_device::random_device(const string& __token)
  79. {
  80. if (__token != "/dev/urandom")
  81. __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
  82. int error = nacl_secure_random_init();
  83. if (error)
  84. __throw_system_error(error, ("random device failed to open " + __token).c_str());
  85. }
  86. random_device::~random_device()
  87. {
  88. }
  89. unsigned
  90. random_device::operator()()
  91. {
  92. unsigned r;
  93. size_t n = sizeof(r);
  94. size_t bytes_written;
  95. int error = nacl_secure_random(&r, n, &bytes_written);
  96. if (error != 0)
  97. __throw_system_error(error, "random_device failed getting bytes");
  98. else if (bytes_written != n)
  99. __throw_runtime_error("random_device failed to obtain enough bytes");
  100. return r;
  101. }
  102. #elif defined(_LIBCPP_USING_WIN32_RANDOM)
  103. random_device::random_device(const string& __token)
  104. {
  105. if (__token != "/dev/urandom")
  106. __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
  107. }
  108. random_device::~random_device()
  109. {
  110. }
  111. unsigned
  112. random_device::operator()()
  113. {
  114. unsigned r;
  115. errno_t err = rand_s(&r);
  116. if (err)
  117. __throw_system_error(err, "random_device rand_s failed.");
  118. return r;
  119. }
  120. #else
  121. #error "Random device not implemented for this architecture"
  122. #endif
  123. double
  124. random_device::entropy() const _NOEXCEPT
  125. {
  126. return 0;
  127. }
  128. _LIBCPP_END_NAMESPACE_STD
  129. #endif // !defined(_LIBCPP_SGX_CONFIG)