1 //===-------------------------- random.cpp --------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <__config> 10 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 16 #include "limits" 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_GETENTROPY) 29 #include <sys/random.h> 30 #elif defined(_LIBCPP_USING_DEV_RANDOM) 31 #include <fcntl.h> 32 #include <unistd.h> 33 #if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>) 34 #include <sys/ioctl.h> 35 #include <linux/random.h> 36 #endif 37 #elif defined(_LIBCPP_USING_NACL_RANDOM) 38 #include <nacl/nacl_random.h> 39 #endif 40 41 42 _LIBCPP_BEGIN_NAMESPACE_STD 43 44 #if defined(_LIBCPP_USING_GETENTROPY) 45 46 random_device::random_device(const string& __token) 47 { 48 if (__token != "/dev/urandom") 49 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 50 } 51 52 random_device::~random_device() 53 { 54 } 55 56 unsigned 57 random_device::operator()() 58 { 59 unsigned r; 60 size_t n = sizeof(r); 61 int err = getentropy(&r, n); 62 if (err) 63 __throw_system_error(errno, "random_device getentropy failed"); 64 return r; 65 } 66 67 #elif defined(_LIBCPP_USING_ARC4_RANDOM) 68 69 random_device::random_device(const string& __token) 70 { 71 if (__token != "/dev/urandom") 72 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 73 } 74 75 random_device::~random_device() 76 { 77 } 78 79 unsigned 80 random_device::operator()() 81 { 82 return arc4random(); 83 } 84 85 #elif defined(_LIBCPP_USING_DEV_RANDOM) 86 87 random_device::random_device(const string& __token) 88 : __f_(open(__token.c_str(), O_RDONLY)) 89 { 90 if (__f_ < 0) 91 __throw_system_error(errno, ("random_device failed to open " + __token).c_str()); 92 } 93 94 random_device::~random_device() 95 { 96 close(__f_); 97 } 98 99 unsigned 100 random_device::operator()() 101 { 102 unsigned r; 103 size_t n = sizeof(r); 104 char* p = reinterpret_cast<char*>(&r); 105 while (n > 0) 106 { 107 ssize_t s = read(__f_, p, n); 108 if (s == 0) 109 __throw_system_error(ENODATA, "random_device got EOF"); 110 if (s == -1) 111 { 112 if (errno != EINTR) 113 __throw_system_error(errno, "random_device got an unexpected error"); 114 continue; 115 } 116 n -= static_cast<size_t>(s); 117 p += static_cast<size_t>(s); 118 } 119 return r; 120 } 121 122 #elif defined(_LIBCPP_USING_NACL_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 int error = nacl_secure_random_init(); 129 if (error) 130 __throw_system_error(error, ("random device failed to open " + __token).c_str()); 131 } 132 133 random_device::~random_device() 134 { 135 } 136 137 unsigned 138 random_device::operator()() 139 { 140 unsigned r; 141 size_t n = sizeof(r); 142 size_t bytes_written; 143 int error = nacl_secure_random(&r, n, &bytes_written); 144 if (error != 0) 145 __throw_system_error(error, "random_device failed getting bytes"); 146 else if (bytes_written != n) 147 __throw_runtime_error("random_device failed to obtain enough bytes"); 148 return r; 149 } 150 151 #elif defined(_LIBCPP_USING_WIN32_RANDOM) 152 153 random_device::random_device(const string& __token) 154 { 155 if (__token != "/dev/urandom") 156 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 157 } 158 159 random_device::~random_device() 160 { 161 } 162 163 unsigned 164 random_device::operator()() 165 { 166 unsigned r; 167 errno_t err = rand_s(&r); 168 if (err) 169 __throw_system_error(err, "random_device rand_s failed."); 170 return r; 171 } 172 173 #else 174 #error "Random device not implemented for this architecture" 175 #endif 176 177 double 178 random_device::entropy() const _NOEXCEPT 179 { 180 #if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT) 181 int ent; 182 if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0) 183 return 0; 184 185 if (ent < 0) 186 return 0; 187 188 if (ent > std::numeric_limits<result_type>::digits) 189 return std::numeric_limits<result_type>::digits; 190 191 return ent; 192 #elif defined(__OpenBSD__) 193 return std::numeric_limits<result_type>::digits; 194 #else 195 return 0; 196 #endif 197 } 198 199 _LIBCPP_END_NAMESPACE_STD 200