1349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include <__config> 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #if defined(_LIBCPP_USING_WIN32_RANDOM) 120b57cec5SDimitry Andric // Must be defined before including stdlib.h to enable rand_s(). 130b57cec5SDimitry Andric # define _CRT_RAND_S 140b57cec5SDimitry Andric #endif // defined(_LIBCPP_USING_WIN32_RANDOM) 150b57cec5SDimitry Andric 1606c3fb27SDimitry Andric #include <__system_error/system_error.h> 1781ad6265SDimitry Andric #include <limits> 1881ad6265SDimitry Andric #include <random> 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #include <errno.h> 210b57cec5SDimitry Andric #include <stdio.h> 220b57cec5SDimitry Andric #include <stdlib.h> 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric #if defined(_LIBCPP_USING_GETENTROPY) 250b57cec5SDimitry Andric # include <sys/random.h> 260b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_DEV_RANDOM) 270b57cec5SDimitry Andric # include <fcntl.h> 280b57cec5SDimitry Andric # include <unistd.h> 29e8d8bef9SDimitry Andric # if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>) 30e8d8bef9SDimitry Andric # include <linux/random.h> 31*cb14a3feSDimitry Andric # include <sys/ioctl.h> 32e8d8bef9SDimitry Andric # endif 330b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_NACL_RANDOM) 340b57cec5SDimitry Andric # include <nacl/nacl_random.h> 3504eeddc0SDimitry Andric #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG) 3604eeddc0SDimitry Andric # include <zircon/syscalls.h> 370b57cec5SDimitry Andric #endif 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric #if defined(_LIBCPP_USING_GETENTROPY) 420b57cec5SDimitry Andric 43*cb14a3feSDimitry Andric random_device::random_device(const string& __token) { 440b57cec5SDimitry Andric if (__token != "/dev/urandom") 450b57cec5SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 460b57cec5SDimitry Andric } 470b57cec5SDimitry Andric 48*cb14a3feSDimitry Andric random_device::~random_device() {} 490b57cec5SDimitry Andric 50*cb14a3feSDimitry Andric unsigned random_device::operator()() { 510b57cec5SDimitry Andric unsigned r; 520b57cec5SDimitry Andric size_t n = sizeof(r); 530b57cec5SDimitry Andric int err = getentropy(&r, n); 540b57cec5SDimitry Andric if (err) 550b57cec5SDimitry Andric __throw_system_error(errno, "random_device getentropy failed"); 560b57cec5SDimitry Andric return r; 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_ARC4_RANDOM) 600b57cec5SDimitry Andric 61*cb14a3feSDimitry Andric random_device::random_device(const string&) {} 620b57cec5SDimitry Andric 63*cb14a3feSDimitry Andric random_device::~random_device() {} 640b57cec5SDimitry Andric 65*cb14a3feSDimitry Andric unsigned random_device::operator()() { return arc4random(); } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_DEV_RANDOM) 680b57cec5SDimitry Andric 69*cb14a3feSDimitry Andric random_device::random_device(const string& __token) : __f_(open(__token.c_str(), O_RDONLY)) { 700b57cec5SDimitry Andric if (__f_ < 0) 710b57cec5SDimitry Andric __throw_system_error(errno, ("random_device failed to open " + __token).c_str()); 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric 74*cb14a3feSDimitry Andric random_device::~random_device() { close(__f_); } 750b57cec5SDimitry Andric 76*cb14a3feSDimitry Andric unsigned random_device::operator()() { 770b57cec5SDimitry Andric unsigned r; 780b57cec5SDimitry Andric size_t n = sizeof(r); 790b57cec5SDimitry Andric char* p = reinterpret_cast<char*>(&r); 80*cb14a3feSDimitry Andric while (n > 0) { 810b57cec5SDimitry Andric ssize_t s = read(__f_, p, n); 820b57cec5SDimitry Andric if (s == 0) 830b57cec5SDimitry Andric __throw_system_error(ENODATA, "random_device got EOF"); 84*cb14a3feSDimitry Andric if (s == -1) { 850b57cec5SDimitry Andric if (errno != EINTR) 860b57cec5SDimitry Andric __throw_system_error(errno, "random_device got an unexpected error"); 870b57cec5SDimitry Andric continue; 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric n -= static_cast<size_t>(s); 900b57cec5SDimitry Andric p += static_cast<size_t>(s); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric return r; 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_NACL_RANDOM) 960b57cec5SDimitry Andric 97*cb14a3feSDimitry Andric random_device::random_device(const string& __token) { 980b57cec5SDimitry Andric if (__token != "/dev/urandom") 990b57cec5SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 1000b57cec5SDimitry Andric int error = nacl_secure_random_init(); 1010b57cec5SDimitry Andric if (error) 1020b57cec5SDimitry Andric __throw_system_error(error, ("random device failed to open " + __token).c_str()); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 105*cb14a3feSDimitry Andric random_device::~random_device() {} 1060b57cec5SDimitry Andric 107*cb14a3feSDimitry Andric unsigned random_device::operator()() { 1080b57cec5SDimitry Andric unsigned r; 1090b57cec5SDimitry Andric size_t n = sizeof(r); 1100b57cec5SDimitry Andric size_t bytes_written; 1110b57cec5SDimitry Andric int error = nacl_secure_random(&r, n, &bytes_written); 1120b57cec5SDimitry Andric if (error != 0) 1130b57cec5SDimitry Andric __throw_system_error(error, "random_device failed getting bytes"); 1140b57cec5SDimitry Andric else if (bytes_written != n) 1150b57cec5SDimitry Andric __throw_runtime_error("random_device failed to obtain enough bytes"); 1160b57cec5SDimitry Andric return r; 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_WIN32_RANDOM) 1200b57cec5SDimitry Andric 121*cb14a3feSDimitry Andric random_device::random_device(const string& __token) { 1220b57cec5SDimitry Andric if (__token != "/dev/urandom") 1230b57cec5SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 126*cb14a3feSDimitry Andric random_device::~random_device() {} 1270b57cec5SDimitry Andric 128*cb14a3feSDimitry Andric unsigned random_device::operator()() { 1290b57cec5SDimitry Andric unsigned r; 1300b57cec5SDimitry Andric errno_t err = rand_s(&r); 1310b57cec5SDimitry Andric if (err) 1320b57cec5SDimitry Andric __throw_system_error(err, "random_device rand_s failed."); 1330b57cec5SDimitry Andric return r; 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric 13604eeddc0SDimitry Andric #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG) 13704eeddc0SDimitry Andric 13804eeddc0SDimitry Andric random_device::random_device(const string& __token) { 13904eeddc0SDimitry Andric if (__token != "/dev/urandom") 14004eeddc0SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 14104eeddc0SDimitry Andric } 14204eeddc0SDimitry Andric 14304eeddc0SDimitry Andric random_device::~random_device() {} 14404eeddc0SDimitry Andric 14504eeddc0SDimitry Andric unsigned random_device::operator()() { 14604eeddc0SDimitry Andric // Implicitly link against the vDSO system call ABI without 14704eeddc0SDimitry Andric // requiring the final link to specify -lzircon explicitly when 14804eeddc0SDimitry Andric // statically linking libc++. 14904eeddc0SDimitry Andric # pragma comment(lib, "zircon") 15004eeddc0SDimitry Andric 15104eeddc0SDimitry Andric // The system call cannot fail. It returns only when the bits are ready. 15204eeddc0SDimitry Andric unsigned r; 15304eeddc0SDimitry Andric _zx_cprng_draw(&r, sizeof(r)); 15404eeddc0SDimitry Andric return r; 15504eeddc0SDimitry Andric } 15604eeddc0SDimitry Andric 1570b57cec5SDimitry Andric #else 1580b57cec5SDimitry Andric # error "Random device not implemented for this architecture" 1590b57cec5SDimitry Andric #endif 1600b57cec5SDimitry Andric 161*cb14a3feSDimitry Andric double random_device::entropy() const noexcept { 162e8d8bef9SDimitry Andric #if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT) 163e8d8bef9SDimitry Andric int ent; 164e8d8bef9SDimitry Andric if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0) 1650b57cec5SDimitry Andric return 0; 166e8d8bef9SDimitry Andric 167e8d8bef9SDimitry Andric if (ent < 0) 168e8d8bef9SDimitry Andric return 0; 169e8d8bef9SDimitry Andric 170e8d8bef9SDimitry Andric if (ent > std::numeric_limits<result_type>::digits) 171e8d8bef9SDimitry Andric return std::numeric_limits<result_type>::digits; 172e8d8bef9SDimitry Andric 173e8d8bef9SDimitry Andric return ent; 1743a9a9c0cSDimitry Andric #elif defined(_LIBCPP_USING_ARC4_RANDOM) || defined(_LIBCPP_USING_FUCHSIA_CPRNG) 175e8d8bef9SDimitry Andric return std::numeric_limits<result_type>::digits; 176e8d8bef9SDimitry Andric #else 177e8d8bef9SDimitry Andric return 0; 178e8d8bef9SDimitry Andric #endif 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 182