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