Skip to content

Commit b5775df

Browse files
vapierachernya
authored andcommitted
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).
1 parent 8e47206 commit b5775df

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

configure.ac

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ AC_CHECK_HEADERS(m4_normalize([
272272
stdlib.h
273273
string.h
274274
sys/ioctl.h
275+
sys/random.h
275276
sys/resource.h
276277
sys/socket.h
277278
sys/stat.h
@@ -304,6 +305,8 @@ AC_TYPE_UINTPTR_T
304305

305306
# Checks for library functions.
306307
AC_CHECK_FUNCS(m4_normalize([
308+
getentropy
309+
getrandom
307310
gettimeofday
308311
posix_memalign
309312
cfmakeraw

src/crypto/prng.h

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@
3333
#ifndef PRNG_HPP
3434
#define PRNG_HPP
3535

36+
#include "config.h"
37+
38+
#if !defined( HAVE_GETENTROPY ) && !defined( HAVE_GETRANDOM )
39+
#define HAVE_URANDOM 1
40+
#else
41+
#undef HAVE_URANDOM
42+
#endif
43+
44+
#include <unistd.h>
45+
#ifdef HAVE_SYS_RANDOM_H
46+
#include <sys/random.h>
47+
#endif
48+
49+
#include <algorithm>
3650
#include <cstdint>
3751
#include <fstream>
3852
#include <string>
@@ -43,32 +57,57 @@
4357
4458
We rely on stdio buffering for efficiency. */
4559

60+
#ifdef HAVE_URANDOM
4661
static const char rdev[] = "/dev/urandom";
62+
#endif
4763

4864
using namespace Crypto;
4965

5066
class PRNG
5167
{
5268
private:
69+
#ifdef HAVE_URANDOM
5370
std::ifstream randfile;
71+
#endif
5472

5573
/* unimplemented to satisfy -Weffc++ */
5674
PRNG( const PRNG& );
5775
PRNG& operator=( const PRNG& );
5876

5977
public:
60-
PRNG() : randfile( rdev, std::ifstream::in | std::ifstream::binary ) {}
78+
PRNG()
79+
#ifdef HAVE_URANDOM
80+
: randfile( rdev, std::ifstream::in | std::ifstream::binary )
81+
#endif
82+
{}
6183

6284
void fill( void* dest, size_t size )
6385
{
6486
if ( 0 == size ) {
6587
return;
6688
}
6789

90+
#if defined( HAVE_GETRANDOM )
91+
if ( getrandom( dest, size, 0 ) != static_cast<ssize_t>( size ) ) {
92+
throw CryptoException( "getrandom fell short" );
93+
}
94+
#elif defined( HAVE_GETENTROPY )
95+
// getentropy() can only read up to 256 bytes at a time :(.
96+
const size_t max_read = 256;
97+
while ( size ) {
98+
size_t this_size = std::min( max_read, size );
99+
if ( getentropy( dest, this_size ) ) {
100+
throw CryptoException( "getentropy fell short" );
101+
}
102+
size -= this_size;
103+
dest = static_cast<char*>( dest ) + this_size;
104+
}
105+
#else
68106
randfile.read( static_cast<char*>( dest ), size );
69107
if ( !randfile ) {
70108
throw CryptoException( "Could not read from " + std::string( rdev ) );
71109
}
110+
#endif
72111
}
73112

74113
uint8_t uint8()

0 commit comments

Comments
 (0)