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