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 10 #include <__config> 11 12 #if defined(_LIBCPP_USING_WIN32_RANDOM) 13 // Must be defined before including stdlib.h to enable rand_s(). 14 #define _CRT_RAND_S 15 #endif // defined(_LIBCPP_USING_WIN32_RANDOM) 16 17 #include "random" 18 #include "system_error" 19 20 #if defined(__sun__) 21 #define rename solaris_headers_are_broken 22 #endif // defined(__sun__) 23 24 #include <errno.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 28 #if defined(_LIBCPP_USING_DEV_RANDOM) 29 #include <fcntl.h> 30 #include <unistd.h> 31 #elif defined(_LIBCPP_USING_NACL_RANDOM) 32 #include <nacl/nacl_random.h> 33 #endif 34 35 36 _LIBCPP_BEGIN_NAMESPACE_STD 37 38 #if defined(_LIBCPP_USING_ARC4_RANDOM) 39 40 random_device::random_device(const string& __token) 41 { 42 if (__token != "/dev/urandom") 43 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 44 } 45 46 random_device::~random_device() 47 { 48 } 49 50 unsigned 51 random_device::operator()() 52 { 53 return arc4random(); 54 } 55 56 #elif defined(_LIBCPP_USING_DEV_RANDOM) 57 58 random_device::random_device(const string& __token) 59 : __f_(open(__token.c_str(), O_RDONLY)) 60 { 61 if (__f_ < 0) 62 __throw_system_error(errno, ("random_device failed to open " + __token).c_str()); 63 } 64 65 random_device::~random_device() 66 { 67 close(__f_); 68 } 69 70 unsigned 71 random_device::operator()() 72 { 73 unsigned r; 74 size_t n = sizeof(r); 75 char* p = reinterpret_cast<char*>(&r); 76 while (n > 0) 77 { 78 ssize_t s = read(__f_, p, n); 79 if (s == 0) 80 __throw_system_error(ENODATA, "random_device got EOF"); 81 if (s == -1) 82 { 83 if (errno != EINTR) 84 __throw_system_error(errno, "random_device got an unexpected error"); 85 continue; 86 } 87 n -= static_cast<size_t>(s); 88 p += static_cast<size_t>(s); 89 } 90 return r; 91 } 92 93 #elif defined(_LIBCPP_USING_NACL_RANDOM) 94 95 random_device::random_device(const string& __token) 96 { 97 if (__token != "/dev/urandom") 98 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 99 int error = nacl_secure_random_init(); 100 if (error) 101 __throw_system_error(error, ("random device failed to open " + __token).c_str()); 102 } 103 104 random_device::~random_device() 105 { 106 } 107 108 unsigned 109 random_device::operator()() 110 { 111 unsigned r; 112 size_t n = sizeof(r); 113 size_t bytes_written; 114 int error = nacl_secure_random(&r, n, &bytes_written); 115 if (error != 0) 116 __throw_system_error(error, "random_device failed getting bytes"); 117 else if (bytes_written != n) 118 __throw_runtime_error("random_device failed to obtain enough bytes"); 119 return r; 120 } 121 122 #elif defined(_LIBCPP_USING_WIN32_RANDOM) 123 124 random_device::random_device(const string& __token) 125 { 126 if (__token != "/dev/urandom") 127 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 128 } 129 130 random_device::~random_device() 131 { 132 } 133 134 unsigned 135 random_device::operator()() 136 { 137 unsigned r; 138 errno_t err = rand_s(&r); 139 if (err) 140 __throw_system_error(err, "random_device rand_s failed."); 141 return r; 142 } 143 144 #else 145 #error "Random device not implemented for this architecture" 146 #endif 147 148 double 149 random_device::entropy() const _NOEXCEPT 150 { 151 return 0; 152 } 153 154 _LIBCPP_END_NAMESPACE_STD 155