xref: /netbsd-src/external/apache2/llvm/dist/libcxx/src/random.cpp (revision 4d6fc14bc9b0c5bf3e30be318c143ee82cadd108)
1*4d6fc14bSjoerg //===-------------------------- random.cpp --------------------------------===//
2*4d6fc14bSjoerg //
3*4d6fc14bSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*4d6fc14bSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*4d6fc14bSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*4d6fc14bSjoerg //
7*4d6fc14bSjoerg //===----------------------------------------------------------------------===//
8*4d6fc14bSjoerg 
9*4d6fc14bSjoerg #include <__config>
10*4d6fc14bSjoerg 
11*4d6fc14bSjoerg #if defined(_LIBCPP_USING_WIN32_RANDOM)
12*4d6fc14bSjoerg // Must be defined before including stdlib.h to enable rand_s().
13*4d6fc14bSjoerg #define _CRT_RAND_S
14*4d6fc14bSjoerg #endif // defined(_LIBCPP_USING_WIN32_RANDOM)
15*4d6fc14bSjoerg 
16*4d6fc14bSjoerg #include "limits"
17*4d6fc14bSjoerg #include "random"
18*4d6fc14bSjoerg #include "system_error"
19*4d6fc14bSjoerg 
20*4d6fc14bSjoerg #if defined(__sun__)
21*4d6fc14bSjoerg #define rename solaris_headers_are_broken
22*4d6fc14bSjoerg #endif // defined(__sun__)
23*4d6fc14bSjoerg 
24*4d6fc14bSjoerg #include <errno.h>
25*4d6fc14bSjoerg #include <stdio.h>
26*4d6fc14bSjoerg #include <stdlib.h>
27*4d6fc14bSjoerg 
28*4d6fc14bSjoerg #if defined(_LIBCPP_USING_GETENTROPY)
29*4d6fc14bSjoerg #include <sys/random.h>
30*4d6fc14bSjoerg #elif defined(_LIBCPP_USING_DEV_RANDOM)
31*4d6fc14bSjoerg #include <fcntl.h>
32*4d6fc14bSjoerg #include <unistd.h>
33*4d6fc14bSjoerg #if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>)
34*4d6fc14bSjoerg #include <sys/ioctl.h>
35*4d6fc14bSjoerg #include <linux/random.h>
36*4d6fc14bSjoerg #endif
37*4d6fc14bSjoerg #elif defined(_LIBCPP_USING_NACL_RANDOM)
38*4d6fc14bSjoerg #include <nacl/nacl_random.h>
39*4d6fc14bSjoerg #endif
40*4d6fc14bSjoerg 
41*4d6fc14bSjoerg 
42*4d6fc14bSjoerg _LIBCPP_BEGIN_NAMESPACE_STD
43*4d6fc14bSjoerg 
44*4d6fc14bSjoerg #if defined(_LIBCPP_USING_GETENTROPY)
45*4d6fc14bSjoerg 
random_device(const string & __token)46*4d6fc14bSjoerg random_device::random_device(const string& __token)
47*4d6fc14bSjoerg {
48*4d6fc14bSjoerg     if (__token != "/dev/urandom")
49*4d6fc14bSjoerg         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
50*4d6fc14bSjoerg }
51*4d6fc14bSjoerg 
~random_device()52*4d6fc14bSjoerg random_device::~random_device()
53*4d6fc14bSjoerg {
54*4d6fc14bSjoerg }
55*4d6fc14bSjoerg 
56*4d6fc14bSjoerg unsigned
operator ()()57*4d6fc14bSjoerg random_device::operator()()
58*4d6fc14bSjoerg {
59*4d6fc14bSjoerg     unsigned r;
60*4d6fc14bSjoerg     size_t n = sizeof(r);
61*4d6fc14bSjoerg     int err = getentropy(&r, n);
62*4d6fc14bSjoerg     if (err)
63*4d6fc14bSjoerg         __throw_system_error(errno, "random_device getentropy failed");
64*4d6fc14bSjoerg     return r;
65*4d6fc14bSjoerg }
66*4d6fc14bSjoerg 
67*4d6fc14bSjoerg #elif defined(_LIBCPP_USING_ARC4_RANDOM)
68*4d6fc14bSjoerg 
69*4d6fc14bSjoerg random_device::random_device(const string& __token)
70*4d6fc14bSjoerg {
71*4d6fc14bSjoerg     if (__token != "/dev/urandom")
72*4d6fc14bSjoerg         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
73*4d6fc14bSjoerg }
74*4d6fc14bSjoerg 
75*4d6fc14bSjoerg random_device::~random_device()
76*4d6fc14bSjoerg {
77*4d6fc14bSjoerg }
78*4d6fc14bSjoerg 
79*4d6fc14bSjoerg unsigned
80*4d6fc14bSjoerg random_device::operator()()
81*4d6fc14bSjoerg {
82*4d6fc14bSjoerg     return arc4random();
83*4d6fc14bSjoerg }
84*4d6fc14bSjoerg 
85*4d6fc14bSjoerg #elif defined(_LIBCPP_USING_DEV_RANDOM)
86*4d6fc14bSjoerg 
87*4d6fc14bSjoerg random_device::random_device(const string& __token)
88*4d6fc14bSjoerg     : __f_(open(__token.c_str(), O_RDONLY))
89*4d6fc14bSjoerg {
90*4d6fc14bSjoerg     if (__f_ < 0)
91*4d6fc14bSjoerg         __throw_system_error(errno, ("random_device failed to open " + __token).c_str());
92*4d6fc14bSjoerg }
93*4d6fc14bSjoerg 
94*4d6fc14bSjoerg random_device::~random_device()
95*4d6fc14bSjoerg {
96*4d6fc14bSjoerg     close(__f_);
97*4d6fc14bSjoerg }
98*4d6fc14bSjoerg 
99*4d6fc14bSjoerg unsigned
100*4d6fc14bSjoerg random_device::operator()()
101*4d6fc14bSjoerg {
102*4d6fc14bSjoerg     unsigned r;
103*4d6fc14bSjoerg     size_t n = sizeof(r);
104*4d6fc14bSjoerg     char* p = reinterpret_cast<char*>(&r);
105*4d6fc14bSjoerg     while (n > 0)
106*4d6fc14bSjoerg     {
107*4d6fc14bSjoerg         ssize_t s = read(__f_, p, n);
108*4d6fc14bSjoerg         if (s == 0)
109*4d6fc14bSjoerg             __throw_system_error(ENODATA, "random_device got EOF");
110*4d6fc14bSjoerg         if (s == -1)
111*4d6fc14bSjoerg         {
112*4d6fc14bSjoerg             if (errno != EINTR)
113*4d6fc14bSjoerg                 __throw_system_error(errno, "random_device got an unexpected error");
114*4d6fc14bSjoerg             continue;
115*4d6fc14bSjoerg         }
116*4d6fc14bSjoerg         n -= static_cast<size_t>(s);
117*4d6fc14bSjoerg         p += static_cast<size_t>(s);
118*4d6fc14bSjoerg     }
119*4d6fc14bSjoerg     return r;
120*4d6fc14bSjoerg }
121*4d6fc14bSjoerg 
122*4d6fc14bSjoerg #elif defined(_LIBCPP_USING_NACL_RANDOM)
123*4d6fc14bSjoerg 
124*4d6fc14bSjoerg random_device::random_device(const string& __token)
125*4d6fc14bSjoerg {
126*4d6fc14bSjoerg     if (__token != "/dev/urandom")
127*4d6fc14bSjoerg         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
128*4d6fc14bSjoerg     int error = nacl_secure_random_init();
129*4d6fc14bSjoerg     if (error)
130*4d6fc14bSjoerg         __throw_system_error(error, ("random device failed to open " + __token).c_str());
131*4d6fc14bSjoerg }
132*4d6fc14bSjoerg 
133*4d6fc14bSjoerg random_device::~random_device()
134*4d6fc14bSjoerg {
135*4d6fc14bSjoerg }
136*4d6fc14bSjoerg 
137*4d6fc14bSjoerg unsigned
138*4d6fc14bSjoerg random_device::operator()()
139*4d6fc14bSjoerg {
140*4d6fc14bSjoerg     unsigned r;
141*4d6fc14bSjoerg     size_t n = sizeof(r);
142*4d6fc14bSjoerg     size_t bytes_written;
143*4d6fc14bSjoerg     int error = nacl_secure_random(&r, n, &bytes_written);
144*4d6fc14bSjoerg     if (error != 0)
145*4d6fc14bSjoerg         __throw_system_error(error, "random_device failed getting bytes");
146*4d6fc14bSjoerg     else if (bytes_written != n)
147*4d6fc14bSjoerg         __throw_runtime_error("random_device failed to obtain enough bytes");
148*4d6fc14bSjoerg     return r;
149*4d6fc14bSjoerg }
150*4d6fc14bSjoerg 
151*4d6fc14bSjoerg #elif defined(_LIBCPP_USING_WIN32_RANDOM)
152*4d6fc14bSjoerg 
153*4d6fc14bSjoerg random_device::random_device(const string& __token)
154*4d6fc14bSjoerg {
155*4d6fc14bSjoerg     if (__token != "/dev/urandom")
156*4d6fc14bSjoerg         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
157*4d6fc14bSjoerg }
158*4d6fc14bSjoerg 
159*4d6fc14bSjoerg random_device::~random_device()
160*4d6fc14bSjoerg {
161*4d6fc14bSjoerg }
162*4d6fc14bSjoerg 
163*4d6fc14bSjoerg unsigned
164*4d6fc14bSjoerg random_device::operator()()
165*4d6fc14bSjoerg {
166*4d6fc14bSjoerg     unsigned r;
167*4d6fc14bSjoerg     errno_t err = rand_s(&r);
168*4d6fc14bSjoerg     if (err)
169*4d6fc14bSjoerg         __throw_system_error(err, "random_device rand_s failed.");
170*4d6fc14bSjoerg     return r;
171*4d6fc14bSjoerg }
172*4d6fc14bSjoerg 
173*4d6fc14bSjoerg #else
174*4d6fc14bSjoerg #error "Random device not implemented for this architecture"
175*4d6fc14bSjoerg #endif
176*4d6fc14bSjoerg 
177*4d6fc14bSjoerg double
entropy() const178*4d6fc14bSjoerg random_device::entropy() const noexcept
179*4d6fc14bSjoerg {
180*4d6fc14bSjoerg #if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT)
181*4d6fc14bSjoerg   int ent;
182*4d6fc14bSjoerg   if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0)
183*4d6fc14bSjoerg     return 0;
184*4d6fc14bSjoerg 
185*4d6fc14bSjoerg   if (ent < 0)
186*4d6fc14bSjoerg     return 0;
187*4d6fc14bSjoerg 
188*4d6fc14bSjoerg   if (ent > std::numeric_limits<result_type>::digits)
189*4d6fc14bSjoerg     return std::numeric_limits<result_type>::digits;
190*4d6fc14bSjoerg 
191*4d6fc14bSjoerg   return ent;
192*4d6fc14bSjoerg #elif defined(__OpenBSD__)
193*4d6fc14bSjoerg   return std::numeric_limits<result_type>::digits;
194*4d6fc14bSjoerg #else
195*4d6fc14bSjoerg   return 0;
196*4d6fc14bSjoerg #endif
197*4d6fc14bSjoerg }
198*4d6fc14bSjoerg 
199*4d6fc14bSjoerg _LIBCPP_END_NAMESPACE_STD
200