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 16*06c3fb27SDimitry 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 <sys/ioctl.h> 31e8d8bef9SDimitry Andric # include <linux/random.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 400b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric #if defined(_LIBCPP_USING_GETENTROPY) 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric random_device::random_device(const string& __token) 450b57cec5SDimitry Andric { 460b57cec5SDimitry Andric if (__token != "/dev/urandom") 470b57cec5SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric random_device::~random_device() 510b57cec5SDimitry Andric { 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric unsigned 550b57cec5SDimitry Andric random_device::operator()() 560b57cec5SDimitry Andric { 570b57cec5SDimitry Andric unsigned r; 580b57cec5SDimitry Andric size_t n = sizeof(r); 590b57cec5SDimitry Andric int err = getentropy(&r, n); 600b57cec5SDimitry Andric if (err) 610b57cec5SDimitry Andric __throw_system_error(errno, "random_device getentropy failed"); 620b57cec5SDimitry Andric return r; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_ARC4_RANDOM) 660b57cec5SDimitry Andric 6704eeddc0SDimitry Andric random_device::random_device(const string&) 680b57cec5SDimitry Andric { 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric random_device::~random_device() 720b57cec5SDimitry Andric { 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric unsigned 760b57cec5SDimitry Andric random_device::operator()() 770b57cec5SDimitry Andric { 780b57cec5SDimitry Andric return arc4random(); 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_DEV_RANDOM) 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric random_device::random_device(const string& __token) 840b57cec5SDimitry Andric : __f_(open(__token.c_str(), O_RDONLY)) 850b57cec5SDimitry Andric { 860b57cec5SDimitry Andric if (__f_ < 0) 870b57cec5SDimitry Andric __throw_system_error(errno, ("random_device failed to open " + __token).c_str()); 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric random_device::~random_device() 910b57cec5SDimitry Andric { 920b57cec5SDimitry Andric close(__f_); 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric unsigned 960b57cec5SDimitry Andric random_device::operator()() 970b57cec5SDimitry Andric { 980b57cec5SDimitry Andric unsigned r; 990b57cec5SDimitry Andric size_t n = sizeof(r); 1000b57cec5SDimitry Andric char* p = reinterpret_cast<char*>(&r); 1010b57cec5SDimitry Andric while (n > 0) 1020b57cec5SDimitry Andric { 1030b57cec5SDimitry Andric ssize_t s = read(__f_, p, n); 1040b57cec5SDimitry Andric if (s == 0) 1050b57cec5SDimitry Andric __throw_system_error(ENODATA, "random_device got EOF"); 1060b57cec5SDimitry Andric if (s == -1) 1070b57cec5SDimitry Andric { 1080b57cec5SDimitry Andric if (errno != EINTR) 1090b57cec5SDimitry Andric __throw_system_error(errno, "random_device got an unexpected error"); 1100b57cec5SDimitry Andric continue; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric n -= static_cast<size_t>(s); 1130b57cec5SDimitry Andric p += static_cast<size_t>(s); 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric return r; 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_NACL_RANDOM) 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric random_device::random_device(const string& __token) 1210b57cec5SDimitry Andric { 1220b57cec5SDimitry Andric if (__token != "/dev/urandom") 1230b57cec5SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 1240b57cec5SDimitry Andric int error = nacl_secure_random_init(); 1250b57cec5SDimitry Andric if (error) 1260b57cec5SDimitry Andric __throw_system_error(error, ("random device failed to open " + __token).c_str()); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric random_device::~random_device() 1300b57cec5SDimitry Andric { 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric unsigned 1340b57cec5SDimitry Andric random_device::operator()() 1350b57cec5SDimitry Andric { 1360b57cec5SDimitry Andric unsigned r; 1370b57cec5SDimitry Andric size_t n = sizeof(r); 1380b57cec5SDimitry Andric size_t bytes_written; 1390b57cec5SDimitry Andric int error = nacl_secure_random(&r, n, &bytes_written); 1400b57cec5SDimitry Andric if (error != 0) 1410b57cec5SDimitry Andric __throw_system_error(error, "random_device failed getting bytes"); 1420b57cec5SDimitry Andric else if (bytes_written != n) 1430b57cec5SDimitry Andric __throw_runtime_error("random_device failed to obtain enough bytes"); 1440b57cec5SDimitry Andric return r; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_WIN32_RANDOM) 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric random_device::random_device(const string& __token) 1500b57cec5SDimitry Andric { 1510b57cec5SDimitry Andric if (__token != "/dev/urandom") 1520b57cec5SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric random_device::~random_device() 1560b57cec5SDimitry Andric { 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric unsigned 1600b57cec5SDimitry Andric random_device::operator()() 1610b57cec5SDimitry Andric { 1620b57cec5SDimitry Andric unsigned r; 1630b57cec5SDimitry Andric errno_t err = rand_s(&r); 1640b57cec5SDimitry Andric if (err) 1650b57cec5SDimitry Andric __throw_system_error(err, "random_device rand_s failed."); 1660b57cec5SDimitry Andric return r; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric 16904eeddc0SDimitry Andric #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG) 17004eeddc0SDimitry Andric 17104eeddc0SDimitry Andric random_device::random_device(const string& __token) { 17204eeddc0SDimitry Andric if (__token != "/dev/urandom") 17304eeddc0SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 17404eeddc0SDimitry Andric } 17504eeddc0SDimitry Andric 17604eeddc0SDimitry Andric random_device::~random_device() {} 17704eeddc0SDimitry Andric 17804eeddc0SDimitry Andric unsigned random_device::operator()() { 17904eeddc0SDimitry Andric // Implicitly link against the vDSO system call ABI without 18004eeddc0SDimitry Andric // requiring the final link to specify -lzircon explicitly when 18104eeddc0SDimitry Andric // statically linking libc++. 18204eeddc0SDimitry Andric # pragma comment(lib, "zircon") 18304eeddc0SDimitry Andric 18404eeddc0SDimitry Andric // The system call cannot fail. It returns only when the bits are ready. 18504eeddc0SDimitry Andric unsigned r; 18604eeddc0SDimitry Andric _zx_cprng_draw(&r, sizeof(r)); 18704eeddc0SDimitry Andric return r; 18804eeddc0SDimitry Andric } 18904eeddc0SDimitry Andric 1900b57cec5SDimitry Andric #else 1910b57cec5SDimitry Andric #error "Random device not implemented for this architecture" 1920b57cec5SDimitry Andric #endif 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric double 195fe6060f1SDimitry Andric random_device::entropy() const noexcept 1960b57cec5SDimitry Andric { 197e8d8bef9SDimitry Andric #if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT) 198e8d8bef9SDimitry Andric int ent; 199e8d8bef9SDimitry Andric if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0) 2000b57cec5SDimitry Andric return 0; 201e8d8bef9SDimitry Andric 202e8d8bef9SDimitry Andric if (ent < 0) 203e8d8bef9SDimitry Andric return 0; 204e8d8bef9SDimitry Andric 205e8d8bef9SDimitry Andric if (ent > std::numeric_limits<result_type>::digits) 206e8d8bef9SDimitry Andric return std::numeric_limits<result_type>::digits; 207e8d8bef9SDimitry Andric 208e8d8bef9SDimitry Andric return ent; 2093a9a9c0cSDimitry Andric #elif defined(_LIBCPP_USING_ARC4_RANDOM) || defined(_LIBCPP_USING_FUCHSIA_CPRNG) 210e8d8bef9SDimitry Andric return std::numeric_limits<result_type>::digits; 211e8d8bef9SDimitry Andric #else 212e8d8bef9SDimitry Andric return 0; 213e8d8bef9SDimitry Andric #endif 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 217