Path: blob/main/system/lib/libcxx/src/random.cpp
6175 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <__config>910#if defined(_LIBCPP_USING_WIN32_RANDOM)11// Must be defined before including stdlib.h to enable rand_s().12# define _CRT_RAND_S13#endif // defined(_LIBCPP_USING_WIN32_RANDOM)1415#include <__system_error/throw_system_error.h>16#include <limits>17#include <random>18#include <string>1920#include <errno.h>21#include <stdio.h>22#include <stdlib.h>2324#if defined(_LIBCPP_USING_GETENTROPY)25# include <sys/random.h>26#elif defined(_LIBCPP_USING_DEV_RANDOM)27# include <fcntl.h>28# include <unistd.h>29# if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>)30# include <linux/random.h>31# include <sys/ioctl.h>32# endif33#elif defined(_LIBCPP_USING_NACL_RANDOM)34# include <nacl/nacl_random.h>35#elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)36# include <zircon/syscalls.h>37#endif3839_LIBCPP_BEGIN_NAMESPACE_STD4041#if defined(_LIBCPP_USING_GETENTROPY)4243random_device::random_device(const string& __token) {44if (__token != "/dev/urandom")45std::__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());46}4748random_device::~random_device() {}4950unsigned random_device::operator()() {51unsigned r;52size_t n = sizeof(r);53int err = getentropy(&r, n);54if (err)55std::__throw_system_error(errno, "random_device getentropy failed");56return r;57}5859#elif defined(_LIBCPP_USING_ARC4_RANDOM)6061random_device::random_device(const string&) {}6263random_device::~random_device() {}6465unsigned random_device::operator()() { return arc4random(); }6667#elif defined(_LIBCPP_USING_DEV_RANDOM)6869random_device::random_device(const string& __token) : __f_(open(__token.c_str(), O_RDONLY)) {70if (__f_ < 0)71std::__throw_system_error(errno, ("random_device failed to open " + __token).c_str());72}7374random_device::~random_device() { close(__f_); }7576unsigned random_device::operator()() {77unsigned r;78size_t n = sizeof(r);79char* p = reinterpret_cast<char*>(&r);80while (n > 0) {81ssize_t s = read(__f_, p, n);82if (s == 0)83std::__throw_system_error(ENOMSG, "random_device got EOF");84if (s == -1) {85if (errno != EINTR)86std::__throw_system_error(errno, "random_device got an unexpected error");87continue;88}89n -= static_cast<size_t>(s);90p += static_cast<size_t>(s);91}92return r;93}9495#elif defined(_LIBCPP_USING_NACL_RANDOM)9697random_device::random_device(const string& __token) {98if (__token != "/dev/urandom")99std::__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());100int error = nacl_secure_random_init();101if (error)102std::__throw_system_error(error, ("random device failed to open " + __token).c_str());103}104105random_device::~random_device() {}106107unsigned random_device::operator()() {108unsigned r;109size_t n = sizeof(r);110size_t bytes_written;111int error = nacl_secure_random(&r, n, &bytes_written);112if (error != 0)113std::__throw_system_error(error, "random_device failed getting bytes");114else if (bytes_written != n)115std::__throw_runtime_error("random_device failed to obtain enough bytes");116return r;117}118119#elif defined(_LIBCPP_USING_WIN32_RANDOM)120121random_device::random_device(const string& __token) {122if (__token != "/dev/urandom")123std::__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());124}125126random_device::~random_device() {}127128unsigned random_device::operator()() {129unsigned r;130errno_t err = rand_s(&r);131if (err)132std::__throw_system_error(err, "random_device rand_s failed.");133return r;134}135136#elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)137138random_device::random_device(const string& __token) {139if (__token != "/dev/urandom")140std::__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());141}142143random_device::~random_device() {}144145unsigned random_device::operator()() {146// Implicitly link against the vDSO system call ABI without147// requiring the final link to specify -lzircon explicitly when148// statically linking libc++.149# pragma comment(lib, "zircon")150151// The system call cannot fail. It returns only when the bits are ready.152unsigned r;153_zx_cprng_draw(&r, sizeof(r));154return r;155}156157#else158# error "Random device not implemented for this architecture"159#endif160161double random_device::entropy() const noexcept {162#if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT)163int ent;164if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0)165return 0;166167if (ent < 0)168return 0;169170if (ent > std::numeric_limits<result_type>::digits)171return std::numeric_limits<result_type>::digits;172173return ent;174#elif defined(_LIBCPP_USING_ARC4_RANDOM) || defined(_LIBCPP_USING_FUCHSIA_CPRNG)175return std::numeric_limits<result_type>::digits;176#else177return 0;178#endif179}180181_LIBCPP_END_NAMESPACE_STD182183184