blob: 8ea080842e0ddfba593b9c66cd595db0aa0845c7 [file] [log] [blame]
Howard Hinnantc51e1022010-05-11 19:42:16 +00001//===-------------------------- random.cpp --------------------------------===//
2//
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)
Marshall Clow653fd202013-10-09 21:49:03 +000012// 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__)
David Chisnall8074c342012-02-29 13:05:08 +000021#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)
29#include <sys/random.h>
30#elif defined(_LIBCPP_USING_DEV_RANDOM)
Howard Hinnantc51e1022010-05-11 19:42:16 +000031#include <fcntl.h>
32#include <unistd.h>
Marek Kurdej66fcf012021-01-21 17:55:19 +010033#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)
JF Bastiend4832032014-12-01 19:19:55 +000038#include <nacl/nacl_random.h>
Ed Schoutendcf37402015-03-10 07:46:06 +000039#endif
40
Howard Hinnantc51e1022010-05-11 19:42:16 +000041
Howard Hinnantc51e1022010-05-11 19:42:16 +000042_LIBCPP_BEGIN_NAMESPACE_STD
43
Petr Hosek02834ef2017-12-01 06:34:33 +000044#if defined(_LIBCPP_USING_GETENTROPY)
45
46random_device::random_device(const string& __token)
47{
48 if (__token != "/dev/urandom")
49 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
50}
51
52random_device::~random_device()
53{
54}
55
56unsigned
57random_device::operator()()
58{
59 unsigned r;
60 size_t n = sizeof(r);
61 int err = getentropy(&r, n);
62 if (err)
63 __throw_system_error(errno, "random_device getentropy failed");
64 return r;
65}
66
67#elif defined(_LIBCPP_USING_ARC4_RANDOM)
JF Bastiend4832032014-12-01 19:19:55 +000068
69random_device::random_device(const string& __token)
70{
71 if (__token != "/dev/urandom")
72 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
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
173#else
174#error "Random device not implemented for this architecture"
175#endif
Howard Hinnantc51e1022010-05-11 19:42:16 +0000176
177double
Louis Dionne65358e12021-03-01 12:09:45 -0500178random_device::entropy() const noexcept
Howard Hinnantc51e1022010-05-11 19:42:16 +0000179{
Marek Kurdej66fcf012021-01-21 17:55:19 +0100180#if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT)
181 int ent;
182 if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0)
Howard Hinnantc51e1022010-05-11 19:42:16 +0000183 return 0;
Marek Kurdej66fcf012021-01-21 17:55:19 +0100184
185 if (ent < 0)
186 return 0;
187
188 if (ent > std::numeric_limits<result_type>::digits)
189 return std::numeric_limits<result_type>::digits;
190
191 return ent;
Brad Smith616b1e12021-01-25 20:55:09 -0500192#elif defined(__OpenBSD__)
193 return std::numeric_limits<result_type>::digits;
Marek Kurdej66fcf012021-01-21 17:55:19 +0100194#else
195 return 0;
196#endif
Howard Hinnantc51e1022010-05-11 19:42:16 +0000197}
198
199_LIBCPP_END_NAMESPACE_STD