1*349cc55cSDimitry 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 16e8d8bef9SDimitry Andric #include "limits" 170b57cec5SDimitry Andric #include "random" 180b57cec5SDimitry Andric #include "system_error" 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #if defined(__sun__) 210b57cec5SDimitry Andric #define rename solaris_headers_are_broken 220b57cec5SDimitry Andric #endif // defined(__sun__) 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric #include <errno.h> 250b57cec5SDimitry Andric #include <stdio.h> 260b57cec5SDimitry Andric #include <stdlib.h> 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #if defined(_LIBCPP_USING_GETENTROPY) 290b57cec5SDimitry Andric #include <sys/random.h> 300b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_DEV_RANDOM) 310b57cec5SDimitry Andric #include <fcntl.h> 320b57cec5SDimitry Andric #include <unistd.h> 33e8d8bef9SDimitry Andric #if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>) 34e8d8bef9SDimitry Andric #include <sys/ioctl.h> 35e8d8bef9SDimitry Andric #include <linux/random.h> 36e8d8bef9SDimitry Andric #endif 370b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_NACL_RANDOM) 380b57cec5SDimitry Andric #include <nacl/nacl_random.h> 390b57cec5SDimitry Andric #endif 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric #if defined(_LIBCPP_USING_GETENTROPY) 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric random_device::random_device(const string& __token) 470b57cec5SDimitry Andric { 480b57cec5SDimitry Andric if (__token != "/dev/urandom") 490b57cec5SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric random_device::~random_device() 530b57cec5SDimitry Andric { 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric unsigned 570b57cec5SDimitry Andric random_device::operator()() 580b57cec5SDimitry Andric { 590b57cec5SDimitry Andric unsigned r; 600b57cec5SDimitry Andric size_t n = sizeof(r); 610b57cec5SDimitry Andric int err = getentropy(&r, n); 620b57cec5SDimitry Andric if (err) 630b57cec5SDimitry Andric __throw_system_error(errno, "random_device getentropy failed"); 640b57cec5SDimitry Andric return r; 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_ARC4_RANDOM) 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric random_device::random_device(const string& __token) 700b57cec5SDimitry Andric { 710b57cec5SDimitry Andric if (__token != "/dev/urandom") 720b57cec5SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric random_device::~random_device() 760b57cec5SDimitry Andric { 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric unsigned 800b57cec5SDimitry Andric random_device::operator()() 810b57cec5SDimitry Andric { 820b57cec5SDimitry Andric return arc4random(); 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_DEV_RANDOM) 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric random_device::random_device(const string& __token) 880b57cec5SDimitry Andric : __f_(open(__token.c_str(), O_RDONLY)) 890b57cec5SDimitry Andric { 900b57cec5SDimitry Andric if (__f_ < 0) 910b57cec5SDimitry Andric __throw_system_error(errno, ("random_device failed to open " + __token).c_str()); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric random_device::~random_device() 950b57cec5SDimitry Andric { 960b57cec5SDimitry Andric close(__f_); 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric unsigned 1000b57cec5SDimitry Andric random_device::operator()() 1010b57cec5SDimitry Andric { 1020b57cec5SDimitry Andric unsigned r; 1030b57cec5SDimitry Andric size_t n = sizeof(r); 1040b57cec5SDimitry Andric char* p = reinterpret_cast<char*>(&r); 1050b57cec5SDimitry Andric while (n > 0) 1060b57cec5SDimitry Andric { 1070b57cec5SDimitry Andric ssize_t s = read(__f_, p, n); 1080b57cec5SDimitry Andric if (s == 0) 1090b57cec5SDimitry Andric __throw_system_error(ENODATA, "random_device got EOF"); 1100b57cec5SDimitry Andric if (s == -1) 1110b57cec5SDimitry Andric { 1120b57cec5SDimitry Andric if (errno != EINTR) 1130b57cec5SDimitry Andric __throw_system_error(errno, "random_device got an unexpected error"); 1140b57cec5SDimitry Andric continue; 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric n -= static_cast<size_t>(s); 1170b57cec5SDimitry Andric p += static_cast<size_t>(s); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric return r; 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_NACL_RANDOM) 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric random_device::random_device(const string& __token) 1250b57cec5SDimitry Andric { 1260b57cec5SDimitry Andric if (__token != "/dev/urandom") 1270b57cec5SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 1280b57cec5SDimitry Andric int error = nacl_secure_random_init(); 1290b57cec5SDimitry Andric if (error) 1300b57cec5SDimitry Andric __throw_system_error(error, ("random device failed to open " + __token).c_str()); 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric random_device::~random_device() 1340b57cec5SDimitry Andric { 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric unsigned 1380b57cec5SDimitry Andric random_device::operator()() 1390b57cec5SDimitry Andric { 1400b57cec5SDimitry Andric unsigned r; 1410b57cec5SDimitry Andric size_t n = sizeof(r); 1420b57cec5SDimitry Andric size_t bytes_written; 1430b57cec5SDimitry Andric int error = nacl_secure_random(&r, n, &bytes_written); 1440b57cec5SDimitry Andric if (error != 0) 1450b57cec5SDimitry Andric __throw_system_error(error, "random_device failed getting bytes"); 1460b57cec5SDimitry Andric else if (bytes_written != n) 1470b57cec5SDimitry Andric __throw_runtime_error("random_device failed to obtain enough bytes"); 1480b57cec5SDimitry Andric return r; 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric #elif defined(_LIBCPP_USING_WIN32_RANDOM) 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric random_device::random_device(const string& __token) 1540b57cec5SDimitry Andric { 1550b57cec5SDimitry Andric if (__token != "/dev/urandom") 1560b57cec5SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric random_device::~random_device() 1600b57cec5SDimitry Andric { 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric unsigned 1640b57cec5SDimitry Andric random_device::operator()() 1650b57cec5SDimitry Andric { 1660b57cec5SDimitry Andric unsigned r; 1670b57cec5SDimitry Andric errno_t err = rand_s(&r); 1680b57cec5SDimitry Andric if (err) 1690b57cec5SDimitry Andric __throw_system_error(err, "random_device rand_s failed."); 1700b57cec5SDimitry Andric return r; 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric #else 1740b57cec5SDimitry Andric #error "Random device not implemented for this architecture" 1750b57cec5SDimitry Andric #endif 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric double 178fe6060f1SDimitry Andric random_device::entropy() const noexcept 1790b57cec5SDimitry Andric { 180e8d8bef9SDimitry Andric #if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT) 181e8d8bef9SDimitry Andric int ent; 182e8d8bef9SDimitry Andric if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0) 1830b57cec5SDimitry Andric return 0; 184e8d8bef9SDimitry Andric 185e8d8bef9SDimitry Andric if (ent < 0) 186e8d8bef9SDimitry Andric return 0; 187e8d8bef9SDimitry Andric 188e8d8bef9SDimitry Andric if (ent > std::numeric_limits<result_type>::digits) 189e8d8bef9SDimitry Andric return std::numeric_limits<result_type>::digits; 190e8d8bef9SDimitry Andric 191e8d8bef9SDimitry Andric return ent; 192e8d8bef9SDimitry Andric #elif defined(__OpenBSD__) 193e8d8bef9SDimitry Andric return std::numeric_limits<result_type>::digits; 194e8d8bef9SDimitry Andric #else 195e8d8bef9SDimitry Andric return 0; 196e8d8bef9SDimitry Andric #endif 1970b57cec5SDimitry Andric } 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 200