prng: support getrandom & getentropy

If the C library supports these random functions, use them directly
instead of reading the /dev/urandom file.  This makes life easier on
platforms that don't have /dev/urandom (like WASM).
This commit is contained in:
Mike Frysinger
2026-01-19 21:36:54 -05:00
committed by Alex Chernyakhovsky
parent 8e472066be
commit b5775df441
2 changed files with 43 additions and 1 deletions
+3
View File
@@ -272,6 +272,7 @@ AC_CHECK_HEADERS(m4_normalize([
stdlib.h
string.h
sys/ioctl.h
sys/random.h
sys/resource.h
sys/socket.h
sys/stat.h
@@ -304,6 +305,8 @@ AC_TYPE_UINTPTR_T
# Checks for library functions.
AC_CHECK_FUNCS(m4_normalize([
getentropy
getrandom
gettimeofday
posix_memalign
cfmakeraw
+40 -1
View File
@@ -33,6 +33,20 @@
#ifndef PRNG_HPP
#define PRNG_HPP
#include "config.h"
#if !defined( HAVE_GETENTROPY ) && !defined( HAVE_GETRANDOM )
#define HAVE_URANDOM 1
#else
#undef HAVE_URANDOM
#endif
#include <unistd.h>
#ifdef HAVE_SYS_RANDOM_H
#include <sys/random.h>
#endif
#include <algorithm>
#include <cstdint>
#include <fstream>
#include <string>
@@ -43,21 +57,29 @@
We rely on stdio buffering for efficiency. */
#ifdef HAVE_URANDOM
static const char rdev[] = "/dev/urandom";
#endif
using namespace Crypto;
class PRNG
{
private:
#ifdef HAVE_URANDOM
std::ifstream randfile;
#endif
/* unimplemented to satisfy -Weffc++ */
PRNG( const PRNG& );
PRNG& operator=( const PRNG& );
public:
PRNG() : randfile( rdev, std::ifstream::in | std::ifstream::binary ) {}
PRNG()
#ifdef HAVE_URANDOM
: randfile( rdev, std::ifstream::in | std::ifstream::binary )
#endif
{}
void fill( void* dest, size_t size )
{
@@ -65,10 +87,27 @@ public:
return;
}
#if defined( HAVE_GETRANDOM )
if ( getrandom( dest, size, 0 ) != static_cast<ssize_t>( size ) ) {
throw CryptoException( "getrandom fell short" );
}
#elif defined( HAVE_GETENTROPY )
// getentropy() can only read up to 256 bytes at a time :(.
const size_t max_read = 256;
while ( size ) {
size_t this_size = std::min( max_read, size );
if ( getentropy( dest, this_size ) ) {
throw CryptoException( "getentropy fell short" );
}
size -= this_size;
dest = static_cast<char*>( dest ) + this_size;
}
#else
randfile.read( static_cast<char*>( dest ), size );
if ( !randfile ) {
throw CryptoException( "Could not read from " + std::string( rdev ) );
}
#endif
}
uint8_t uint8()