blob: 6472a8dbcba3e5629543f049c37b86030310bfed [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
Louis Dionne1eb0c9d2021-12-21 11:49:04 -050071random_device::random_device(const string&)
JF Bastiend4832032014-12-01 19:19:55 +000072{
JF Bastiend4832032014-12-01 19:19:55 +000073}
74
75random_device::~random_device()
76{
77}
78
79unsigned
80random_device::operator()()
81{
Ed Schoutendcf37402015-03-10 07:46:06 +000082 return arc4random();
JF Bastiend4832032014-12-01 19:19:55 +000083}
84
Ed Schoutendcf37402015-03-10 07:46:06 +000085#elif defined(_LIBCPP_USING_DEV_RANDOM)
JF Bastiend4832032014-12-01 19:19:55 +000086
Howard Hinnantc51e1022010-05-11 19:42:16 +000087random_device::random_device(const string& __token)
88 : __f_(open(__token.c_str(), O_RDONLY))
89{
David Majnemer3230e1a2014-06-03 02:21:37 +000090 if (__f_ < 0)
Howard Hinnantc51e1022010-05-11 19:42:16 +000091 __throw_system_error(errno, ("random_device failed to open " + __token).c_str());
92}
93
94random_device::~random_device()
95{
96 close(__f_);
97}
98
99unsigned
100random_device::operator()()
101{
102 unsigned r;
David Majnemer89874f72014-06-03 02:40:39 +0000103 size_t n = sizeof(r);
104 char* p = reinterpret_cast<char*>(&r);
105 while (n > 0)
106 {
107 ssize_t s = read(__f_, p, n);
108 if (s == 0)
109 __throw_system_error(ENODATA, "random_device got EOF");
110 if (s == -1)
111 {
112 if (errno != EINTR)
113 __throw_system_error(errno, "random_device got an unexpected error");
114 continue;
115 }
116 n -= static_cast<size_t>(s);
117 p += static_cast<size_t>(s);
118 }
Howard Hinnantc51e1022010-05-11 19:42:16 +0000119 return r;
120}
JF Bastiend4832032014-12-01 19:19:55 +0000121
Ed Schoutendcf37402015-03-10 07:46:06 +0000122#elif defined(_LIBCPP_USING_NACL_RANDOM)
123
124random_device::random_device(const string& __token)
125{
126 if (__token != "/dev/urandom")
127 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
128 int error = nacl_secure_random_init();
129 if (error)
130 __throw_system_error(error, ("random device failed to open " + __token).c_str());
131}
132
133random_device::~random_device()
134{
135}
136
137unsigned
138random_device::operator()()
139{
140 unsigned r;
141 size_t n = sizeof(r);
142 size_t bytes_written;
143 int error = nacl_secure_random(&r, n, &bytes_written);
144 if (error != 0)
145 __throw_system_error(error, "random_device failed getting bytes");
146 else if (bytes_written != n)
147 __throw_runtime_error("random_device failed to obtain enough bytes");
148 return r;
149}
150
151#elif defined(_LIBCPP_USING_WIN32_RANDOM)
152
153random_device::random_device(const string& __token)
154{
155 if (__token != "/dev/urandom")
156 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
157}
158
159random_device::~random_device()
160{
161}
162
163unsigned
164random_device::operator()()
165{
166 unsigned r;
167 errno_t err = rand_s(&r);
168 if (err)
169 __throw_system_error(err, "random_device rand_s failed.");
170 return r;
171}
172
Roland McGrathdea04482022-01-02 11:53:53 -0800173#elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)
174
175random_device::random_device(const string& __token) {
176 if (__token != "/dev/urandom")
177 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
178}
179
180random_device::~random_device() {}
181
182unsigned random_device::operator()() {
183 // Implicitly link against the vDSO system call ABI without
184 // requiring the final link to specify -lzircon explicitly when
185 // statically linking libc++.
186# pragma comment(lib, "zircon")
187
188 // The system call cannot fail. It returns only when the bits are ready.
189 unsigned r;
190 _zx_cprng_draw(&r, sizeof(r));
191 return r;
192}
193
Ed Schoutendcf37402015-03-10 07:46:06 +0000194#else
195#error "Random device not implemented for this architecture"
196#endif
Howard Hinnantc51e1022010-05-11 19:42:16 +0000197
198double
Louis Dionne65358e12021-03-01 12:09:45 -0500199random_device::entropy() const noexcept
Howard Hinnantc51e1022010-05-11 19:42:16 +0000200{
Marek Kurdej66fcf012021-01-21 17:55:19 +0100201#if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT)
202 int ent;
203 if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0)
Howard Hinnantc51e1022010-05-11 19:42:16 +0000204 return 0;
Marek Kurdej66fcf012021-01-21 17:55:19 +0100205
206 if (ent < 0)
207 return 0;
208
209 if (ent > std::numeric_limits<result_type>::digits)
210 return std::numeric_limits<result_type>::digits;
211
212 return ent;
Roland McGrathdea04482022-01-02 11:53:53 -0800213#elif defined(__OpenBSD__) || defined(_LIBCPP_USING_FUCHSIA_CPRNG)
Brad Smith616b1e12021-01-25 20:55:09 -0500214 return std::numeric_limits<result_type>::digits;
Marek Kurdej66fcf012021-01-21 17:55:19 +0100215#else
216 return 0;
217#endif
Howard Hinnantc51e1022010-05-11 19:42:16 +0000218}
219
220_LIBCPP_END_NAMESPACE_STD