1 //===----------------------------------------------------------------------===//
3 // 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
7 //===----------------------------------------------------------------------===//
11 #if defined(_LIBCPP_USING_WIN32_RANDOM)
12 // Must be defined before including stdlib.h to enable rand_s().
14 #endif // defined(_LIBCPP_USING_WIN32_RANDOM)
16 #include <__system_error/system_error.h>
24 #if defined(_LIBCPP_USING_GETENTROPY)
25 # include <sys/random.h>
26 #elif defined(_LIBCPP_USING_DEV_RANDOM)
29 # if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>)
30 # include <sys/ioctl.h>
31 # include <linux/random.h>
33 #elif defined(_LIBCPP_USING_NACL_RANDOM)
34 # include <nacl/nacl_random.h>
35 #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)
36 # include <zircon/syscalls.h>
40 _LIBCPP_BEGIN_NAMESPACE_STD
42 #if defined(_LIBCPP_USING_GETENTROPY)
44 random_device::random_device(const string
& __token
)
46 if (__token
!= "/dev/urandom")
47 __throw_system_error(ENOENT
, ("random device not supported " + __token
).c_str());
50 random_device::~random_device()
55 random_device::operator()()
59 int err
= getentropy(&r
, n
);
61 __throw_system_error(errno
, "random_device getentropy failed");
65 #elif defined(_LIBCPP_USING_ARC4_RANDOM)
67 random_device::random_device(const string
&)
71 random_device::~random_device()
76 random_device::operator()()
81 #elif defined(_LIBCPP_USING_DEV_RANDOM)
83 random_device::random_device(const string
& __token
)
84 : __f_(open(__token
.c_str(), O_RDONLY
))
87 __throw_system_error(errno
, ("random_device failed to open " + __token
).c_str());
90 random_device::~random_device()
96 random_device::operator()()
100 char* p
= reinterpret_cast<char*>(&r
);
103 ssize_t s
= read(__f_
, p
, n
);
105 __throw_system_error(ENODATA
, "random_device got EOF");
109 __throw_system_error(errno
, "random_device got an unexpected error");
112 n
-= static_cast<size_t>(s
);
113 p
+= static_cast<size_t>(s
);
118 #elif defined(_LIBCPP_USING_NACL_RANDOM)
120 random_device::random_device(const string
& __token
)
122 if (__token
!= "/dev/urandom")
123 __throw_system_error(ENOENT
, ("random device not supported " + __token
).c_str());
124 int error
= nacl_secure_random_init();
126 __throw_system_error(error
, ("random device failed to open " + __token
).c_str());
129 random_device::~random_device()
134 random_device::operator()()
137 size_t n
= sizeof(r
);
138 size_t bytes_written
;
139 int error
= nacl_secure_random(&r
, n
, &bytes_written
);
141 __throw_system_error(error
, "random_device failed getting bytes");
142 else if (bytes_written
!= n
)
143 __throw_runtime_error("random_device failed to obtain enough bytes");
147 #elif defined(_LIBCPP_USING_WIN32_RANDOM)
149 random_device::random_device(const string
& __token
)
151 if (__token
!= "/dev/urandom")
152 __throw_system_error(ENOENT
, ("random device not supported " + __token
).c_str());
155 random_device::~random_device()
160 random_device::operator()()
163 errno_t err
= rand_s(&r
);
165 __throw_system_error(err
, "random_device rand_s failed.");
169 #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)
171 random_device::random_device(const string
& __token
) {
172 if (__token
!= "/dev/urandom")
173 __throw_system_error(ENOENT
, ("random device not supported " + __token
).c_str());
176 random_device::~random_device() {}
178 unsigned random_device::operator()() {
179 // Implicitly link against the vDSO system call ABI without
180 // requiring the final link to specify -lzircon explicitly when
181 // statically linking libc++.
182 # pragma comment(lib, "zircon")
184 // The system call cannot fail. It returns only when the bits are ready.
186 _zx_cprng_draw(&r
, sizeof(r
));
191 #error "Random device not implemented for this architecture"
195 random_device::entropy() const noexcept
197 #if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT)
199 if (::ioctl(__f_
, RNDGETENTCNT
, &ent
) < 0)
205 if (ent
> std::numeric_limits
<result_type
>::digits
)
206 return std::numeric_limits
<result_type
>::digits
;
209 #elif defined(_LIBCPP_USING_ARC4_RANDOM) || defined(_LIBCPP_USING_FUCHSIA_CPRNG)
210 return std::numeric_limits
<result_type
>::digits
;
216 _LIBCPP_END_NAMESPACE_STD