xref: /aosp_15_r20/external/libcxx/src/random.cpp (revision 58b9f456b02922dfdb1fad8a988d5fd8765ecb80)
1*58b9f456SAndroid Build Coastguard Worker //===-------------------------- random.cpp --------------------------------===//
2*58b9f456SAndroid Build Coastguard Worker //
3*58b9f456SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*58b9f456SAndroid Build Coastguard Worker //
5*58b9f456SAndroid Build Coastguard Worker // This file is dual licensed under the MIT and the University of Illinois Open
6*58b9f456SAndroid Build Coastguard Worker // Source Licenses. See LICENSE.TXT for details.
7*58b9f456SAndroid Build Coastguard Worker //
8*58b9f456SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*58b9f456SAndroid Build Coastguard Worker 
10*58b9f456SAndroid Build Coastguard Worker #include <__config>
11*58b9f456SAndroid Build Coastguard Worker 
12*58b9f456SAndroid Build Coastguard Worker #if defined(_LIBCPP_USING_WIN32_RANDOM)
13*58b9f456SAndroid Build Coastguard Worker // Must be defined before including stdlib.h to enable rand_s().
14*58b9f456SAndroid Build Coastguard Worker #define _CRT_RAND_S
15*58b9f456SAndroid Build Coastguard Worker #endif // defined(_LIBCPP_USING_WIN32_RANDOM)
16*58b9f456SAndroid Build Coastguard Worker 
17*58b9f456SAndroid Build Coastguard Worker #include "random"
18*58b9f456SAndroid Build Coastguard Worker #include "system_error"
19*58b9f456SAndroid Build Coastguard Worker 
20*58b9f456SAndroid Build Coastguard Worker #if defined(__sun__)
21*58b9f456SAndroid Build Coastguard Worker #define rename solaris_headers_are_broken
22*58b9f456SAndroid Build Coastguard Worker #endif // defined(__sun__)
23*58b9f456SAndroid Build Coastguard Worker 
24*58b9f456SAndroid Build Coastguard Worker #include <errno.h>
25*58b9f456SAndroid Build Coastguard Worker #include <stdio.h>
26*58b9f456SAndroid Build Coastguard Worker #include <stdlib.h>
27*58b9f456SAndroid Build Coastguard Worker 
28*58b9f456SAndroid Build Coastguard Worker #if defined(_LIBCPP_USING_GETENTROPY)
29*58b9f456SAndroid Build Coastguard Worker #include <sys/random.h>
30*58b9f456SAndroid Build Coastguard Worker #elif defined(_LIBCPP_USING_DEV_RANDOM)
31*58b9f456SAndroid Build Coastguard Worker #include <fcntl.h>
32*58b9f456SAndroid Build Coastguard Worker #include <unistd.h>
33*58b9f456SAndroid Build Coastguard Worker #elif defined(_LIBCPP_USING_NACL_RANDOM)
34*58b9f456SAndroid Build Coastguard Worker #include <nacl/nacl_random.h>
35*58b9f456SAndroid Build Coastguard Worker #endif
36*58b9f456SAndroid Build Coastguard Worker 
37*58b9f456SAndroid Build Coastguard Worker 
38*58b9f456SAndroid Build Coastguard Worker _LIBCPP_BEGIN_NAMESPACE_STD
39*58b9f456SAndroid Build Coastguard Worker 
40*58b9f456SAndroid Build Coastguard Worker #if defined(_LIBCPP_USING_GETENTROPY)
41*58b9f456SAndroid Build Coastguard Worker 
random_device(const string & __token)42*58b9f456SAndroid Build Coastguard Worker random_device::random_device(const string& __token)
43*58b9f456SAndroid Build Coastguard Worker {
44*58b9f456SAndroid Build Coastguard Worker     if (__token != "/dev/urandom")
45*58b9f456SAndroid Build Coastguard Worker         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
46*58b9f456SAndroid Build Coastguard Worker }
47*58b9f456SAndroid Build Coastguard Worker 
~random_device()48*58b9f456SAndroid Build Coastguard Worker random_device::~random_device()
49*58b9f456SAndroid Build Coastguard Worker {
50*58b9f456SAndroid Build Coastguard Worker }
51*58b9f456SAndroid Build Coastguard Worker 
52*58b9f456SAndroid Build Coastguard Worker unsigned
operator ()()53*58b9f456SAndroid Build Coastguard Worker random_device::operator()()
54*58b9f456SAndroid Build Coastguard Worker {
55*58b9f456SAndroid Build Coastguard Worker     unsigned r;
56*58b9f456SAndroid Build Coastguard Worker     size_t n = sizeof(r);
57*58b9f456SAndroid Build Coastguard Worker     int err = getentropy(&r, n);
58*58b9f456SAndroid Build Coastguard Worker     if (err)
59*58b9f456SAndroid Build Coastguard Worker         __throw_system_error(errno, "random_device getentropy failed");
60*58b9f456SAndroid Build Coastguard Worker     return r;
61*58b9f456SAndroid Build Coastguard Worker }
62*58b9f456SAndroid Build Coastguard Worker 
63*58b9f456SAndroid Build Coastguard Worker #elif defined(_LIBCPP_USING_ARC4_RANDOM)
64*58b9f456SAndroid Build Coastguard Worker 
65*58b9f456SAndroid Build Coastguard Worker random_device::random_device(const string& __token)
66*58b9f456SAndroid Build Coastguard Worker {
67*58b9f456SAndroid Build Coastguard Worker     if (__token != "/dev/urandom")
68*58b9f456SAndroid Build Coastguard Worker         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
69*58b9f456SAndroid Build Coastguard Worker }
70*58b9f456SAndroid Build Coastguard Worker 
71*58b9f456SAndroid Build Coastguard Worker random_device::~random_device()
72*58b9f456SAndroid Build Coastguard Worker {
73*58b9f456SAndroid Build Coastguard Worker }
74*58b9f456SAndroid Build Coastguard Worker 
75*58b9f456SAndroid Build Coastguard Worker unsigned
76*58b9f456SAndroid Build Coastguard Worker random_device::operator()()
77*58b9f456SAndroid Build Coastguard Worker {
78*58b9f456SAndroid Build Coastguard Worker     return arc4random();
79*58b9f456SAndroid Build Coastguard Worker }
80*58b9f456SAndroid Build Coastguard Worker 
81*58b9f456SAndroid Build Coastguard Worker #elif defined(_LIBCPP_USING_DEV_RANDOM)
82*58b9f456SAndroid Build Coastguard Worker 
83*58b9f456SAndroid Build Coastguard Worker random_device::random_device(const string& __token)
84*58b9f456SAndroid Build Coastguard Worker     : __f_(open(__token.c_str(), O_RDONLY))
85*58b9f456SAndroid Build Coastguard Worker {
86*58b9f456SAndroid Build Coastguard Worker     if (__f_ < 0)
87*58b9f456SAndroid Build Coastguard Worker         __throw_system_error(errno, ("random_device failed to open " + __token).c_str());
88*58b9f456SAndroid Build Coastguard Worker }
89*58b9f456SAndroid Build Coastguard Worker 
90*58b9f456SAndroid Build Coastguard Worker random_device::~random_device()
91*58b9f456SAndroid Build Coastguard Worker {
92*58b9f456SAndroid Build Coastguard Worker     close(__f_);
93*58b9f456SAndroid Build Coastguard Worker }
94*58b9f456SAndroid Build Coastguard Worker 
95*58b9f456SAndroid Build Coastguard Worker unsigned
96*58b9f456SAndroid Build Coastguard Worker random_device::operator()()
97*58b9f456SAndroid Build Coastguard Worker {
98*58b9f456SAndroid Build Coastguard Worker     unsigned r;
99*58b9f456SAndroid Build Coastguard Worker     size_t n = sizeof(r);
100*58b9f456SAndroid Build Coastguard Worker     char* p = reinterpret_cast<char*>(&r);
101*58b9f456SAndroid Build Coastguard Worker     while (n > 0)
102*58b9f456SAndroid Build Coastguard Worker     {
103*58b9f456SAndroid Build Coastguard Worker         ssize_t s = read(__f_, p, n);
104*58b9f456SAndroid Build Coastguard Worker         if (s == 0)
105*58b9f456SAndroid Build Coastguard Worker             __throw_system_error(ENODATA, "random_device got EOF");
106*58b9f456SAndroid Build Coastguard Worker         if (s == -1)
107*58b9f456SAndroid Build Coastguard Worker         {
108*58b9f456SAndroid Build Coastguard Worker             if (errno != EINTR)
109*58b9f456SAndroid Build Coastguard Worker                 __throw_system_error(errno, "random_device got an unexpected error");
110*58b9f456SAndroid Build Coastguard Worker             continue;
111*58b9f456SAndroid Build Coastguard Worker         }
112*58b9f456SAndroid Build Coastguard Worker         n -= static_cast<size_t>(s);
113*58b9f456SAndroid Build Coastguard Worker         p += static_cast<size_t>(s);
114*58b9f456SAndroid Build Coastguard Worker     }
115*58b9f456SAndroid Build Coastguard Worker     return r;
116*58b9f456SAndroid Build Coastguard Worker }
117*58b9f456SAndroid Build Coastguard Worker 
118*58b9f456SAndroid Build Coastguard Worker #elif defined(_LIBCPP_USING_NACL_RANDOM)
119*58b9f456SAndroid Build Coastguard Worker 
120*58b9f456SAndroid Build Coastguard Worker random_device::random_device(const string& __token)
121*58b9f456SAndroid Build Coastguard Worker {
122*58b9f456SAndroid Build Coastguard Worker     if (__token != "/dev/urandom")
123*58b9f456SAndroid Build Coastguard Worker         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
124*58b9f456SAndroid Build Coastguard Worker     int error = nacl_secure_random_init();
125*58b9f456SAndroid Build Coastguard Worker     if (error)
126*58b9f456SAndroid Build Coastguard Worker         __throw_system_error(error, ("random device failed to open " + __token).c_str());
127*58b9f456SAndroid Build Coastguard Worker }
128*58b9f456SAndroid Build Coastguard Worker 
129*58b9f456SAndroid Build Coastguard Worker random_device::~random_device()
130*58b9f456SAndroid Build Coastguard Worker {
131*58b9f456SAndroid Build Coastguard Worker }
132*58b9f456SAndroid Build Coastguard Worker 
133*58b9f456SAndroid Build Coastguard Worker unsigned
134*58b9f456SAndroid Build Coastguard Worker random_device::operator()()
135*58b9f456SAndroid Build Coastguard Worker {
136*58b9f456SAndroid Build Coastguard Worker     unsigned r;
137*58b9f456SAndroid Build Coastguard Worker     size_t n = sizeof(r);
138*58b9f456SAndroid Build Coastguard Worker     size_t bytes_written;
139*58b9f456SAndroid Build Coastguard Worker     int error = nacl_secure_random(&r, n, &bytes_written);
140*58b9f456SAndroid Build Coastguard Worker     if (error != 0)
141*58b9f456SAndroid Build Coastguard Worker         __throw_system_error(error, "random_device failed getting bytes");
142*58b9f456SAndroid Build Coastguard Worker     else if (bytes_written != n)
143*58b9f456SAndroid Build Coastguard Worker         __throw_runtime_error("random_device failed to obtain enough bytes");
144*58b9f456SAndroid Build Coastguard Worker     return r;
145*58b9f456SAndroid Build Coastguard Worker }
146*58b9f456SAndroid Build Coastguard Worker 
147*58b9f456SAndroid Build Coastguard Worker #elif defined(_LIBCPP_USING_WIN32_RANDOM)
148*58b9f456SAndroid Build Coastguard Worker 
149*58b9f456SAndroid Build Coastguard Worker random_device::random_device(const string& __token)
150*58b9f456SAndroid Build Coastguard Worker {
151*58b9f456SAndroid Build Coastguard Worker     if (__token != "/dev/urandom")
152*58b9f456SAndroid Build Coastguard Worker         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
153*58b9f456SAndroid Build Coastguard Worker }
154*58b9f456SAndroid Build Coastguard Worker 
155*58b9f456SAndroid Build Coastguard Worker random_device::~random_device()
156*58b9f456SAndroid Build Coastguard Worker {
157*58b9f456SAndroid Build Coastguard Worker }
158*58b9f456SAndroid Build Coastguard Worker 
159*58b9f456SAndroid Build Coastguard Worker unsigned
160*58b9f456SAndroid Build Coastguard Worker random_device::operator()()
161*58b9f456SAndroid Build Coastguard Worker {
162*58b9f456SAndroid Build Coastguard Worker     unsigned r;
163*58b9f456SAndroid Build Coastguard Worker     errno_t err = rand_s(&r);
164*58b9f456SAndroid Build Coastguard Worker     if (err)
165*58b9f456SAndroid Build Coastguard Worker         __throw_system_error(err, "random_device rand_s failed.");
166*58b9f456SAndroid Build Coastguard Worker     return r;
167*58b9f456SAndroid Build Coastguard Worker }
168*58b9f456SAndroid Build Coastguard Worker 
169*58b9f456SAndroid Build Coastguard Worker #else
170*58b9f456SAndroid Build Coastguard Worker #error "Random device not implemented for this architecture"
171*58b9f456SAndroid Build Coastguard Worker #endif
172*58b9f456SAndroid Build Coastguard Worker 
173*58b9f456SAndroid Build Coastguard Worker double
entropy() const174*58b9f456SAndroid Build Coastguard Worker random_device::entropy() const _NOEXCEPT
175*58b9f456SAndroid Build Coastguard Worker {
176*58b9f456SAndroid Build Coastguard Worker     return 0;
177*58b9f456SAndroid Build Coastguard Worker }
178*58b9f456SAndroid Build Coastguard Worker 
179*58b9f456SAndroid Build Coastguard Worker _LIBCPP_END_NAMESPACE_STD
180