17a984708SDavid Chisnall //===-------------------------- random.cpp --------------------------------===//
27a984708SDavid Chisnall //
37a984708SDavid Chisnall // The LLVM Compiler Infrastructure
47a984708SDavid Chisnall //
57a984708SDavid Chisnall // This file is dual licensed under the MIT and the University of Illinois Open
67a984708SDavid Chisnall // Source Licenses. See LICENSE.TXT for details.
77a984708SDavid Chisnall //
87a984708SDavid Chisnall //===----------------------------------------------------------------------===//
97a984708SDavid Chisnall
10aed8d94eSDimitry Andric #include <__config>
11aed8d94eSDimitry Andric
12854fa44bSDimitry Andric #if defined(_LIBCPP_USING_WIN32_RANDOM)
134f7ab58eSDimitry Andric // Must be defined before including stdlib.h to enable rand_s().
144f7ab58eSDimitry Andric #define _CRT_RAND_S
15854fa44bSDimitry Andric #endif // defined(_LIBCPP_USING_WIN32_RANDOM)
164f7ab58eSDimitry Andric
177a984708SDavid Chisnall #include "random"
187a984708SDavid Chisnall #include "system_error"
197a984708SDavid Chisnall
20d72607e9SDimitry Andric #if defined(__sun__)
2194e3ee44SDavid Chisnall #define rename solaris_headers_are_broken
22d72607e9SDimitry Andric #endif // defined(__sun__)
23854fa44bSDimitry Andric
24854fa44bSDimitry Andric #include <errno.h>
25854fa44bSDimitry Andric #include <stdio.h>
26854fa44bSDimitry Andric #include <stdlib.h>
27854fa44bSDimitry Andric
28*b2c7081bSDimitry Andric #if defined(_LIBCPP_USING_GETENTROPY)
29*b2c7081bSDimitry Andric #include <sys/random.h>
30*b2c7081bSDimitry Andric #elif defined(_LIBCPP_USING_DEV_RANDOM)
317a984708SDavid Chisnall #include <fcntl.h>
327a984708SDavid Chisnall #include <unistd.h>
33854fa44bSDimitry Andric #elif defined(_LIBCPP_USING_NACL_RANDOM)
34d72607e9SDimitry Andric #include <nacl/nacl_random.h>
35854fa44bSDimitry Andric #endif
36854fa44bSDimitry Andric
377a984708SDavid Chisnall
387a984708SDavid Chisnall _LIBCPP_BEGIN_NAMESPACE_STD
397a984708SDavid Chisnall
40*b2c7081bSDimitry Andric #if defined(_LIBCPP_USING_GETENTROPY)
41*b2c7081bSDimitry Andric
random_device(const string & __token)42*b2c7081bSDimitry Andric random_device::random_device(const string& __token)
43*b2c7081bSDimitry Andric {
44*b2c7081bSDimitry Andric if (__token != "/dev/urandom")
45*b2c7081bSDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
46*b2c7081bSDimitry Andric }
47*b2c7081bSDimitry Andric
~random_device()48*b2c7081bSDimitry Andric random_device::~random_device()
49*b2c7081bSDimitry Andric {
50*b2c7081bSDimitry Andric }
51*b2c7081bSDimitry Andric
52*b2c7081bSDimitry Andric unsigned
operator ()()53*b2c7081bSDimitry Andric random_device::operator()()
54*b2c7081bSDimitry Andric {
55*b2c7081bSDimitry Andric unsigned r;
56*b2c7081bSDimitry Andric size_t n = sizeof(r);
57*b2c7081bSDimitry Andric int err = getentropy(&r, n);
58*b2c7081bSDimitry Andric if (err)
59*b2c7081bSDimitry Andric __throw_system_error(errno, "random_device getentropy failed");
60*b2c7081bSDimitry Andric return r;
61*b2c7081bSDimitry Andric }
62*b2c7081bSDimitry Andric
63*b2c7081bSDimitry Andric #elif defined(_LIBCPP_USING_ARC4_RANDOM)
64d72607e9SDimitry Andric
65d72607e9SDimitry Andric random_device::random_device(const string& __token)
66d72607e9SDimitry Andric {
67d72607e9SDimitry Andric if (__token != "/dev/urandom")
68d72607e9SDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
69d72607e9SDimitry Andric }
70d72607e9SDimitry Andric
71d72607e9SDimitry Andric random_device::~random_device()
72d72607e9SDimitry Andric {
73d72607e9SDimitry Andric }
74d72607e9SDimitry Andric
75d72607e9SDimitry Andric unsigned
76d72607e9SDimitry Andric random_device::operator()()
77d72607e9SDimitry Andric {
78854fa44bSDimitry Andric return arc4random();
79d72607e9SDimitry Andric }
80d72607e9SDimitry Andric
81854fa44bSDimitry Andric #elif defined(_LIBCPP_USING_DEV_RANDOM)
82d72607e9SDimitry Andric
837a984708SDavid Chisnall random_device::random_device(const string& __token)
847a984708SDavid Chisnall : __f_(open(__token.c_str(), O_RDONLY))
857a984708SDavid Chisnall {
86d72607e9SDimitry Andric if (__f_ < 0)
877a984708SDavid Chisnall __throw_system_error(errno, ("random_device failed to open " + __token).c_str());
887a984708SDavid Chisnall }
897a984708SDavid Chisnall
907a984708SDavid Chisnall random_device::~random_device()
917a984708SDavid Chisnall {
927a984708SDavid Chisnall close(__f_);
937a984708SDavid Chisnall }
947a984708SDavid Chisnall
957a984708SDavid Chisnall unsigned
967a984708SDavid Chisnall random_device::operator()()
977a984708SDavid Chisnall {
987a984708SDavid Chisnall unsigned r;
99d72607e9SDimitry Andric size_t n = sizeof(r);
100d72607e9SDimitry Andric char* p = reinterpret_cast<char*>(&r);
101d72607e9SDimitry Andric while (n > 0)
102d72607e9SDimitry Andric {
103d72607e9SDimitry Andric ssize_t s = read(__f_, p, n);
104d72607e9SDimitry Andric if (s == 0)
105d72607e9SDimitry Andric __throw_system_error(ENODATA, "random_device got EOF");
106d72607e9SDimitry Andric if (s == -1)
107d72607e9SDimitry Andric {
108d72607e9SDimitry Andric if (errno != EINTR)
109d72607e9SDimitry Andric __throw_system_error(errno, "random_device got an unexpected error");
110d72607e9SDimitry Andric continue;
111d72607e9SDimitry Andric }
112d72607e9SDimitry Andric n -= static_cast<size_t>(s);
113d72607e9SDimitry Andric p += static_cast<size_t>(s);
114d72607e9SDimitry Andric }
1157a984708SDavid Chisnall return r;
1167a984708SDavid Chisnall }
117d72607e9SDimitry Andric
118854fa44bSDimitry Andric #elif defined(_LIBCPP_USING_NACL_RANDOM)
119854fa44bSDimitry Andric
120854fa44bSDimitry Andric random_device::random_device(const string& __token)
121854fa44bSDimitry Andric {
122854fa44bSDimitry Andric if (__token != "/dev/urandom")
123854fa44bSDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
124854fa44bSDimitry Andric int error = nacl_secure_random_init();
125854fa44bSDimitry Andric if (error)
126854fa44bSDimitry Andric __throw_system_error(error, ("random device failed to open " + __token).c_str());
127854fa44bSDimitry Andric }
128854fa44bSDimitry Andric
129854fa44bSDimitry Andric random_device::~random_device()
130854fa44bSDimitry Andric {
131854fa44bSDimitry Andric }
132854fa44bSDimitry Andric
133854fa44bSDimitry Andric unsigned
134854fa44bSDimitry Andric random_device::operator()()
135854fa44bSDimitry Andric {
136854fa44bSDimitry Andric unsigned r;
137854fa44bSDimitry Andric size_t n = sizeof(r);
138854fa44bSDimitry Andric size_t bytes_written;
139854fa44bSDimitry Andric int error = nacl_secure_random(&r, n, &bytes_written);
140854fa44bSDimitry Andric if (error != 0)
141854fa44bSDimitry Andric __throw_system_error(error, "random_device failed getting bytes");
142854fa44bSDimitry Andric else if (bytes_written != n)
143854fa44bSDimitry Andric __throw_runtime_error("random_device failed to obtain enough bytes");
144854fa44bSDimitry Andric return r;
145854fa44bSDimitry Andric }
146854fa44bSDimitry Andric
147854fa44bSDimitry Andric #elif defined(_LIBCPP_USING_WIN32_RANDOM)
148854fa44bSDimitry Andric
149854fa44bSDimitry Andric random_device::random_device(const string& __token)
150854fa44bSDimitry Andric {
151854fa44bSDimitry Andric if (__token != "/dev/urandom")
152854fa44bSDimitry Andric __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
153854fa44bSDimitry Andric }
154854fa44bSDimitry Andric
155854fa44bSDimitry Andric random_device::~random_device()
156854fa44bSDimitry Andric {
157854fa44bSDimitry Andric }
158854fa44bSDimitry Andric
159854fa44bSDimitry Andric unsigned
160854fa44bSDimitry Andric random_device::operator()()
161854fa44bSDimitry Andric {
162854fa44bSDimitry Andric unsigned r;
163854fa44bSDimitry Andric errno_t err = rand_s(&r);
164854fa44bSDimitry Andric if (err)
165854fa44bSDimitry Andric __throw_system_error(err, "random_device rand_s failed.");
166854fa44bSDimitry Andric return r;
167854fa44bSDimitry Andric }
168854fa44bSDimitry Andric
169854fa44bSDimitry Andric #else
170854fa44bSDimitry Andric #error "Random device not implemented for this architecture"
171854fa44bSDimitry Andric #endif
1727a984708SDavid Chisnall
1737a984708SDavid Chisnall double
entropy() const174936e9439SDimitry Andric random_device::entropy() const _NOEXCEPT
1757a984708SDavid Chisnall {
1767a984708SDavid Chisnall return 0;
1777a984708SDavid Chisnall }
1787a984708SDavid Chisnall
1797a984708SDavid Chisnall _LIBCPP_END_NAMESPACE_STD
180