diff --git a/configure.ac b/configure.ac index f75e75a..75dd7d2 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/src/crypto/prng.h b/src/crypto/prng.h index cc15f1f..f57e20e 100644 --- a/src/crypto/prng.h +++ b/src/crypto/prng.h @@ -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 +#ifdef HAVE_SYS_RANDOM_H +#include +#endif + +#include #include #include #include @@ -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( 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( dest ) + this_size; + } +#else randfile.read( static_cast( dest ), size ); if ( !randfile ) { throw CryptoException( "Could not read from " + std::string( rdev ) ); } +#endif } uint8_t uint8()