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