1eb8650a7SLouis Dionne //===----------------------------------------------------------------------===//
23e519524SHoward Hinnant //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63e519524SHoward Hinnant //
73e519524SHoward Hinnant //===----------------------------------------------------------------------===//
83e519524SHoward Hinnant
94a12eab8SSaleem Abdulrasool #include <__config>
104a12eab8SSaleem Abdulrasool
1117f5dbefSEd Schouten #if defined(_LIBCPP_USING_WIN32_RANDOM)
120354b929SMarshall Clow // Must be defined before including stdlib.h to enable rand_s().
130354b929SMarshall Clow # define _CRT_RAND_S
1417f5dbefSEd Schouten #endif // defined(_LIBCPP_USING_WIN32_RANDOM)
150354b929SMarshall Clow
16bbb0f2c7SArthur O'Dwyer #include <limits>
17bbb0f2c7SArthur O'Dwyer #include <random>
18bbb0f2c7SArthur O'Dwyer #include <system_error>
193e519524SHoward Hinnant
2057148cbcSJF Bastien #if defined(__sun__)
2114c25b80SDavid Chisnall # define rename solaris_headers_are_broken
2257148cbcSJF Bastien #endif // defined(__sun__)
2317f5dbefSEd Schouten
2417f5dbefSEd Schouten #include <errno.h>
2517f5dbefSEd Schouten #include <stdio.h>
2617f5dbefSEd Schouten #include <stdlib.h>
2717f5dbefSEd Schouten
285c704281SPetr Hosek #if defined(_LIBCPP_USING_GETENTROPY)
295c704281SPetr Hosek # include <sys/random.h>
305c704281SPetr Hosek #elif defined(_LIBCPP_USING_DEV_RANDOM)
313e519524SHoward Hinnant # include <fcntl.h>
323e519524SHoward Hinnant # include <unistd.h>
33f3b979b6SMarek Kurdej # if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>)
34f3b979b6SMarek Kurdej # include <sys/ioctl.h>
35f3b979b6SMarek Kurdej # include <linux/random.h>
36f3b979b6SMarek Kurdej # endif
3717f5dbefSEd Schouten #elif defined(_LIBCPP_USING_NACL_RANDOM)
3857148cbcSJF Bastien # include <nacl/nacl_random.h>
393064dd8cSRoland McGrath #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)
403064dd8cSRoland McGrath # include <zircon/syscalls.h>
4117f5dbefSEd Schouten #endif
4217f5dbefSEd Schouten
433e519524SHoward Hinnant
443e519524SHoward Hinnant _LIBCPP_BEGIN_NAMESPACE_STD
453e519524SHoward Hinnant
465c704281SPetr Hosek #if defined(_LIBCPP_USING_GETENTROPY)
475c704281SPetr Hosek
random_device(const string & __token)485c704281SPetr Hosek random_device::random_device(const string& __token)
495c704281SPetr Hosek {
505c704281SPetr Hosek if (__token != "/dev/urandom")
515c704281SPetr Hosek __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
525c704281SPetr Hosek }
535c704281SPetr Hosek
~random_device()545c704281SPetr Hosek random_device::~random_device()
555c704281SPetr Hosek {
565c704281SPetr Hosek }
575c704281SPetr Hosek
585c704281SPetr Hosek unsigned
operator ()()595c704281SPetr Hosek random_device::operator()()
605c704281SPetr Hosek {
615c704281SPetr Hosek unsigned r;
625c704281SPetr Hosek size_t n = sizeof(r);
635c704281SPetr Hosek int err = getentropy(&r, n);
645c704281SPetr Hosek if (err)
655c704281SPetr Hosek __throw_system_error(errno, "random_device getentropy failed");
665c704281SPetr Hosek return r;
675c704281SPetr Hosek }
685c704281SPetr Hosek
695c704281SPetr Hosek #elif defined(_LIBCPP_USING_ARC4_RANDOM)
7057148cbcSJF Bastien
71d202c764SLouis Dionne random_device::random_device(const string&)
7257148cbcSJF Bastien {
7357148cbcSJF Bastien }
7457148cbcSJF Bastien
7557148cbcSJF Bastien random_device::~random_device()
7657148cbcSJF Bastien {
7757148cbcSJF Bastien }
7857148cbcSJF Bastien
7957148cbcSJF Bastien unsigned
8057148cbcSJF Bastien random_device::operator()()
8157148cbcSJF Bastien {
8217f5dbefSEd Schouten return arc4random();
8357148cbcSJF Bastien }
8457148cbcSJF Bastien
8517f5dbefSEd Schouten #elif defined(_LIBCPP_USING_DEV_RANDOM)
8657148cbcSJF Bastien
873e519524SHoward Hinnant random_device::random_device(const string& __token)
883e519524SHoward Hinnant : __f_(open(__token.c_str(), O_RDONLY))
893e519524SHoward Hinnant {
901e9592a9SDavid Majnemer if (__f_ < 0)
913e519524SHoward Hinnant __throw_system_error(errno, ("random_device failed to open " + __token).c_str());
923e519524SHoward Hinnant }
933e519524SHoward Hinnant
943e519524SHoward Hinnant random_device::~random_device()
953e519524SHoward Hinnant {
963e519524SHoward Hinnant close(__f_);
973e519524SHoward Hinnant }
983e519524SHoward Hinnant
993e519524SHoward Hinnant unsigned
1003e519524SHoward Hinnant random_device::operator()()
1013e519524SHoward Hinnant {
1023e519524SHoward Hinnant unsigned r;
1032dfdfdf4SDavid Majnemer size_t n = sizeof(r);
1042dfdfdf4SDavid Majnemer char* p = reinterpret_cast<char*>(&r);
1052dfdfdf4SDavid Majnemer while (n > 0)
1062dfdfdf4SDavid Majnemer {
1072dfdfdf4SDavid Majnemer ssize_t s = read(__f_, p, n);
1082dfdfdf4SDavid Majnemer if (s == 0)
1092dfdfdf4SDavid Majnemer __throw_system_error(ENODATA, "random_device got EOF");
1102dfdfdf4SDavid Majnemer if (s == -1)
1112dfdfdf4SDavid Majnemer {
1122dfdfdf4SDavid Majnemer if (errno != EINTR)
1132dfdfdf4SDavid Majnemer __throw_system_error(errno, "random_device got an unexpected error");
1142dfdfdf4SDavid Majnemer continue;
1152dfdfdf4SDavid Majnemer }
1162dfdfdf4SDavid Majnemer n -= static_cast<size_t>(s);
1172dfdfdf4SDavid Majnemer p += static_cast<size_t>(s);
1182dfdfdf4SDavid Majnemer }
1193e519524SHoward Hinnant return r;
1203e519524SHoward Hinnant }
12157148cbcSJF Bastien
12217f5dbefSEd Schouten #elif defined(_LIBCPP_USING_NACL_RANDOM)
12317f5dbefSEd Schouten
12417f5dbefSEd Schouten random_device::random_device(const string& __token)
12517f5dbefSEd Schouten {
12617f5dbefSEd Schouten if (__token != "/dev/urandom")
12717f5dbefSEd Schouten __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
12817f5dbefSEd Schouten int error = nacl_secure_random_init();
12917f5dbefSEd Schouten if (error)
13017f5dbefSEd Schouten __throw_system_error(error, ("random device failed to open " + __token).c_str());
13117f5dbefSEd Schouten }
13217f5dbefSEd Schouten
13317f5dbefSEd Schouten random_device::~random_device()
13417f5dbefSEd Schouten {
13517f5dbefSEd Schouten }
13617f5dbefSEd Schouten
13717f5dbefSEd Schouten unsigned
13817f5dbefSEd Schouten random_device::operator()()
13917f5dbefSEd Schouten {
14017f5dbefSEd Schouten unsigned r;
14117f5dbefSEd Schouten size_t n = sizeof(r);
14217f5dbefSEd Schouten size_t bytes_written;
14317f5dbefSEd Schouten int error = nacl_secure_random(&r, n, &bytes_written);
14417f5dbefSEd Schouten if (error != 0)
14517f5dbefSEd Schouten __throw_system_error(error, "random_device failed getting bytes");
14617f5dbefSEd Schouten else if (bytes_written != n)
14717f5dbefSEd Schouten __throw_runtime_error("random_device failed to obtain enough bytes");
14817f5dbefSEd Schouten return r;
14917f5dbefSEd Schouten }
15017f5dbefSEd Schouten
15117f5dbefSEd Schouten #elif defined(_LIBCPP_USING_WIN32_RANDOM)
15217f5dbefSEd Schouten
15317f5dbefSEd Schouten random_device::random_device(const string& __token)
15417f5dbefSEd Schouten {
15517f5dbefSEd Schouten if (__token != "/dev/urandom")
15617f5dbefSEd Schouten __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
15717f5dbefSEd Schouten }
15817f5dbefSEd Schouten
15917f5dbefSEd Schouten random_device::~random_device()
16017f5dbefSEd Schouten {
16117f5dbefSEd Schouten }
16217f5dbefSEd Schouten
16317f5dbefSEd Schouten unsigned
16417f5dbefSEd Schouten random_device::operator()()
16517f5dbefSEd Schouten {
16617f5dbefSEd Schouten unsigned r;
16717f5dbefSEd Schouten errno_t err = rand_s(&r);
16817f5dbefSEd Schouten if (err)
16917f5dbefSEd Schouten __throw_system_error(err, "random_device rand_s failed.");
17017f5dbefSEd Schouten return r;
17117f5dbefSEd Schouten }
17217f5dbefSEd Schouten
1733064dd8cSRoland McGrath #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)
1743064dd8cSRoland McGrath
1753064dd8cSRoland McGrath random_device::random_device(const string& __token) {
1763064dd8cSRoland McGrath if (__token != "/dev/urandom")
1773064dd8cSRoland McGrath __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
1783064dd8cSRoland McGrath }
1793064dd8cSRoland McGrath
1803064dd8cSRoland McGrath random_device::~random_device() {}
1813064dd8cSRoland McGrath
1823064dd8cSRoland McGrath unsigned random_device::operator()() {
1833064dd8cSRoland McGrath // Implicitly link against the vDSO system call ABI without
1843064dd8cSRoland McGrath // requiring the final link to specify -lzircon explicitly when
1853064dd8cSRoland McGrath // statically linking libc++.
1863064dd8cSRoland McGrath # pragma comment(lib, "zircon")
1873064dd8cSRoland McGrath
1883064dd8cSRoland McGrath // The system call cannot fail. It returns only when the bits are ready.
1893064dd8cSRoland McGrath unsigned r;
1903064dd8cSRoland McGrath _zx_cprng_draw(&r, sizeof(r));
1913064dd8cSRoland McGrath return r;
1923064dd8cSRoland McGrath }
1933064dd8cSRoland McGrath
19417f5dbefSEd Schouten #else
19517f5dbefSEd Schouten #error "Random device not implemented for this architecture"
19617f5dbefSEd Schouten #endif
1973e519524SHoward Hinnant
1983e519524SHoward Hinnant double
entropy() const1995601305fSLouis Dionne random_device::entropy() const noexcept
2003e519524SHoward Hinnant {
201f3b979b6SMarek Kurdej #if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT)
202f3b979b6SMarek Kurdej int ent;
203f3b979b6SMarek Kurdej if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0)
2043e519524SHoward Hinnant return 0;
205f3b979b6SMarek Kurdej
206f3b979b6SMarek Kurdej if (ent < 0)
207f3b979b6SMarek Kurdej return 0;
208f3b979b6SMarek Kurdej
209f3b979b6SMarek Kurdej if (ent > std::numeric_limits<result_type>::digits)
210f3b979b6SMarek Kurdej return std::numeric_limits<result_type>::digits;
211f3b979b6SMarek Kurdej
212f3b979b6SMarek Kurdej return ent;
213*6e2c6c9dSBrad Smith #elif defined(_LIBCPP_USING_ARC4_RANDOM) || defined(_LIBCPP_USING_FUCHSIA_CPRNG)
2144b6d7fddSBrad Smith return std::numeric_limits<result_type>::digits;
215f3b979b6SMarek Kurdej #else
216f3b979b6SMarek Kurdej return 0;
217f3b979b6SMarek Kurdej #endif
2183e519524SHoward Hinnant }
2193e519524SHoward Hinnant
2203e519524SHoward Hinnant _LIBCPP_END_NAMESPACE_STD
221