blob: 5590db85e48adca249605c2a5086c8dff5f9fe5a [file] [log] [blame]
Louis Dionne9bd93882021-11-17 16:25:01 -05001//===----------------------------------------------------------------------===//
Howard Hinnantc51e1022010-05-11 19:42:16 +00002//
Chandler Carruthd2012102019-01-19 10:56:40 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Howard Hinnantc51e1022010-05-11 19:42:16 +00006//
7//===----------------------------------------------------------------------===//
8
Saleem Abdulrasoolf46e0492016-12-31 00:00:21 +00009#include <__config>
10
Ed Schoutendcf37402015-03-10 07:46:06 +000011#if defined(_LIBCPP_USING_WIN32_RANDOM)
Louis Dionnef4b7eae2021-12-21 11:27:19 -050012 // Must be defined before including stdlib.h to enable rand_s().
13# define _CRT_RAND_S
Ed Schoutendcf37402015-03-10 07:46:06 +000014#endif // defined(_LIBCPP_USING_WIN32_RANDOM)
Marshall Clow653fd202013-10-09 21:49:03 +000015
Marek Kurdej66fcf012021-01-21 17:55:19 +010016#include "limits"
Howard Hinnantc51e1022010-05-11 19:42:16 +000017#include "random"
18#include "system_error"
19
JF Bastiend4832032014-12-01 19:19:55 +000020#if defined(__sun__)
Louis Dionnef4b7eae2021-12-21 11:27:19 -050021# define rename solaris_headers_are_broken
JF Bastiend4832032014-12-01 19:19:55 +000022#endif // defined(__sun__)
Ed Schoutendcf37402015-03-10 07:46:06 +000023
24#include <errno.h>
25#include <stdio.h>
26#include <stdlib.h>
27
Petr Hosek02834ef2017-12-01 06:34:33 +000028#if defined(_LIBCPP_USING_GETENTROPY)
Louis Dionnef4b7eae2021-12-21 11:27:19 -050029# include <sys/random.h>
Petr Hosek02834ef2017-12-01 06:34:33 +000030#elif defined(_LIBCPP_USING_DEV_RANDOM)
Louis Dionnef4b7eae2021-12-21 11:27:19 -050031# include <fcntl.h>
32# include <unistd.h>
33# if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>)
34# include <sys/ioctl.h>
35# include <linux/random.h>
36# endif
Ed Schoutendcf37402015-03-10 07:46:06 +000037#elif defined(_LIBCPP_USING_NACL_RANDOM)
Louis Dionnef4b7eae2021-12-21 11:27:19 -050038# include <nacl/nacl_random.h>
Roland McGrathdea04482022-01-02 11:53:53 -080039#elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)
40# include <zircon/syscalls.h>
Ed Schoutendcf37402015-03-10 07:46:06 +000041#endif
42
Howard Hinnantc51e1022010-05-11 19:42:16 +000043
Howard Hinnantc51e1022010-05-11 19:42:16 +000044_LIBCPP_BEGIN_NAMESPACE_STD
45
Petr Hosek02834ef2017-12-01 06:34:33 +000046#if defined(_LIBCPP_USING_GETENTROPY)
47
48random_device::random_device(const string& __token)
49{
50 if (__token != "/dev/urandom")
51 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
52}
53
54random_device::~random_device()
55{
56}
57
58unsigned
59random_device::operator()()
60{
61 unsigned r;
62 size_t n = sizeof(r);
63 int err = getentropy(&r, n);
64 if (err)
65 __throw_system_error(errno, "random_device getentropy failed");
66 return r;
67}
68
69#elif defined(_LIBCPP_USING_ARC4_RANDOM)
JF Bastiend4832032014-12-01 19:19:55 +000070
71random_device::random_device(const string& __token)
72{
73 if (__token != "/dev/urandom")
74 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
JF Bastiend4832032014-12-01 19:19:55 +000075}
76
77random_device::~random_device()
78{
79}
80
81unsigned
82random_device::operator()()
83{
Ed Schoutendcf37402015-03-10 07:46:06 +000084 return arc4random();
JF Bastiend4832032014-12-01 19:19:55 +000085}
86
Ed Schoutendcf37402015-03-10 07:46:06 +000087#elif defined(_LIBCPP_USING_DEV_RANDOM)
JF Bastiend4832032014-12-01 19:19:55 +000088
Howard Hinnantc51e1022010-05-11 19:42:16 +000089random_device::random_device(const string& __token)
90 : __f_(open(__token.c_str(), O_RDONLY))
91{
David Majnemer3230e1a2014-06-03 02:21:37 +000092 if (__f_ < 0)
Howard Hinnantc51e1022010-05-11 19:42:16 +000093 __throw_system_error(errno, ("random_device failed to open " + __token).c_str());
94}
95
96random_device::~random_device()
97{
98 close(__f_);
99}
100
101unsigned
102random_device::operator()()
103{
104 unsigned r;
David Majnemer89874f72014-06-03 02:40:39 +0000105 size_t n = sizeof(r);
106 char* p = reinterpret_cast<char*>(&r);
107 while (n > 0)
108 {
109 ssize_t s = read(__f_, p, n);
110 if (s == 0)
111 __throw_system_error(ENODATA, "random_device got EOF");
112 if (s == -1)
113 {
114 if (errno != EINTR)
115 __throw_system_error(errno, "random_device got an unexpected error");
116 continue;
117 }
118 n -= static_cast<size_t>(s);
119 p += static_cast<size_t>(s);
120 }
Howard Hinnantc51e1022010-05-11 19:42:16 +0000121 return r;
122}
JF Bastiend4832032014-12-01 19:19:55 +0000123
Ed Schoutendcf37402015-03-10 07:46:06 +0000124#elif defined(_LIBCPP_USING_NACL_RANDOM)
125
126random_device::random_device(const string& __token)
127{
128 if (__token != "/dev/urandom")
129 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
130 int error = nacl_secure_random_init();
131 if (error)
132 __throw_system_error(error, ("random device failed to open " + __token).c_str());
133}
134
135random_device::~random_device()
136{
137}
138
139unsigned
140random_device::operator()()
141{
142 unsigned r;
143 size_t n = sizeof(r);
144 size_t bytes_written;
145 int error = nacl_secure_random(&r, n, &bytes_written);
146 if (error != 0)
147 __throw_system_error(error, "random_device failed getting bytes");
148 else if (bytes_written != n)
149 __throw_runtime_error("random_device failed to obtain enough bytes");
150 return r;
151}
152
153#elif defined(_LIBCPP_USING_WIN32_RANDOM)
154
155random_device::random_device(const string& __token)
156{
157 if (__token != "/dev/urandom")
158 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
159}
160
161random_device::~random_device()
162{
163}
164
165unsigned
166random_device::operator()()
167{
168 unsigned r;
169 errno_t err = rand_s(&r);
170 if (err)
171 __throw_system_error(err, "random_device rand_s failed.");
172 return r;
173}
174
Roland McGrathdea04482022-01-02 11:53:53 -0800175#elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)
176
177random_device::random_device(const string& __token) {
178 if (__token != "/dev/urandom")
179 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
180}
181
182random_device::~random_device() {}
183
184unsigned random_device::operator()() {
185 // Implicitly link against the vDSO system call ABI without
186 // requiring the final link to specify -lzircon explicitly when
187 // statically linking libc++.
188# pragma comment(lib, "zircon")
189
190 // The system call cannot fail. It returns only when the bits are ready.
191 unsigned r;
192 _zx_cprng_draw(&r, sizeof(r));
193 return r;
194}
195
Ed Schoutendcf37402015-03-10 07:46:06 +0000196#else
197#error "Random device not implemented for this architecture"
198#endif
Howard Hinnantc51e1022010-05-11 19:42:16 +0000199
200double
Louis Dionne65358e12021-03-01 12:09:45 -0500201random_device::entropy() const noexcept
Howard Hinnantc51e1022010-05-11 19:42:16 +0000202{
Marek Kurdej66fcf012021-01-21 17:55:19 +0100203#if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT)
204 int ent;
205 if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0)
Howard Hinnantc51e1022010-05-11 19:42:16 +0000206 return 0;
Marek Kurdej66fcf012021-01-21 17:55:19 +0100207
208 if (ent < 0)
209 return 0;
210
211 if (ent > std::numeric_limits<result_type>::digits)
212 return std::numeric_limits<result_type>::digits;
213
214 return ent;
Roland McGrathdea04482022-01-02 11:53:53 -0800215#elif defined(__OpenBSD__) || defined(_LIBCPP_USING_FUCHSIA_CPRNG)
Brad Smith616b1e12021-01-25 20:55:09 -0500216 return std::numeric_limits<result_type>::digits;
Marek Kurdej66fcf012021-01-21 17:55:19 +0100217#else
218 return 0;
219#endif
Howard Hinnantc51e1022010-05-11 19:42:16 +0000220}
221
222_LIBCPP_END_NAMESPACE_STD