@ -1,6 +1,6 @@
/*
* random . c
* Random functions .
* Acquire randomness from system . For seeding RNG .
*
* Copyright ( c ) 2001 Marko Kreen
* All rights reserved .
@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*
* $ PostgreSQL : pgsql / contrib / pgcrypto / random . c , v 1.10 2005 / 03 / 21 05 : 22 : 14 neilc Exp $
* $ PostgreSQL : pgsql / contrib / pgcrypto / random . c , v 1.11 2005 / 07 / 10 03 : 55 : 28 momjian Exp $
*/
@ -34,8 +34,20 @@
# include "px.h"
/* how many bytes to ask from system random provider */
# define RND_BYTES 32
# if defined(RAND_DEV)
/*
* Try to read from / dev / urandom or / dev / random on these OS ' es .
*
* The list can be pretty liberal , as the device not existing
* is expected event .
*/
# if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
| | defined ( __NetBSD__ ) | | defined ( __DragonFly__ ) \
| | defined ( __darwin__ ) | | defined ( __SOLARIS__ )
# define TRY_DEV_RANDOM
# include <errno.h>
# include <fcntl.h>
@ -64,94 +76,169 @@ safe_read(int fd, void *buf, size_t count)
return done ;
}
int
px_get_random_bytes ( uint8 * dst , unsigned coun t )
static u int8 *
try_dev_random ( uint8 * dst )
{
int fd ;
int res ;
fd = open ( RAND_DEV , O_RDONLY ) ;
fd = open ( " /dev/urandom " , O_RDONLY ) ;
if ( fd = = - 1 )
return PXE_DEV_READ_ERROR ;
res = safe_read ( fd , dst , count ) ;
{
fd = open ( " /dev/random " , O_RDONLY ) ;
if ( fd = = - 1 )
return dst ;
}
res = safe_read ( fd , dst , RND_BYTES ) ;
close ( fd ) ;
return res ;
if ( res > 0 )
dst + = res ;
return dst ;
}
int
px_get_pseudo_random_bytes ( uint8 * dst , unsigned count )
{
return px_get_random_bytes ( dst , count ) ;
}
# endif
# elif defined(RAND_SILLY)
/*
* Try to find randomness on Windows
*/
# ifdef WIN32
int
px_get_pseudo_random_bytes ( uint8 * dst , unsigned count )
{
int i ;
# define TRY_WIN32_GENRAND
# define TRY_WIN32_PERFC
for ( i = 0 ; i < count ; i + + )
* dst + + = random ( ) ;
return i ;
}
# define _WIN32_WINNT 0x0400
# include <windows.h>
# include <wincrypt.h>
int
px_get_random_bytes ( uint8 * dst , unsigned count )
/*
* this function is from libtomcrypt
*
* try to use Microsoft crypto API
*/
static uint8 * try_win32_genrand ( uint8 * dst )
{
return PXE_NO_RANDOM ;
int res ;
HCRYPTPROV h = 0 ;
res = CryptAcquireContext ( & h , NULL , MS_DEF_PROV , PROV_RSA_FULL ,
( CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET ) ) ;
if ( ! res )
res = CryptAcquireContext ( & h , NULL , MS_DEF_PROV , PROV_RSA_FULL ,
CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET ) ;
if ( ! res )
return dst ;
res = CryptGenRandom ( h , NUM_BYTES , dst ) ;
if ( res = = TRUE )
dst + = len ;
CryptReleaseContext ( h , 0 ) ;
return dst ;
}
# elif defined(RAND_OPENSSL)
# include <openssl/evp.h>
# include <openssl/blowfish.h>
# include <openssl/rand.h>
# include <openssl/err.h>
static uint8 * try_win32_perfc ( uint8 * dst )
{
int res ;
LARGE_INTEGER time ;
static int openssl_random_init = 0 ;
res = QueryPerformanceCounter ( & time ) ;
if ( ! res )
return dst ;
/*
* OpenSSL random should re - feeded occasionally . From / dev / urandom
* preferably .
*/
static void init_openssl ( )
{
if ( RAND_get_rand_method ( ) = = NULL )
RAND_set_rand_method ( RAND_SSLeay ( ) ) ;
openssl_random_init = 1 ;
memcpy ( dst , & time , sizeof ( time ) ) ;
return dst + sizeof ( time ) ;
}
int
px_get_random_bytes ( uint8 * dst , unsigned count )
{
int res ;
# endif /* WIN32 */
if ( ! openssl_random_init )
init_openssl ( ) ;
res = RAND_bytes ( dst , count ) ;
if ( res = = 1 )
return count ;
/*
* If we are not on Windows , then hopefully we are
* on a unix - like system . Use the usual suspects
* for randomness .
*/
# ifndef WIN32
return PXE_OSSL_RAND_ERROR ;
}
# define TRY_UNIXSTD
int
px_get_pseudo_random_bytes ( uint8 * dst , unsigned count )
# include <sys/types.h>
# include <sys/time.h>
# include <time.h>
# include <unistd.h>
/*
* Everything here is predictible , only needs some patience .
*
* But there is a chance that the system - specific functions
* did not work . So keep faith and try to slow the attacker down .
*/
static uint8 *
try_unix_std ( uint8 * dst )
{
int res ;
pid_t pid ;
int x ;
PX_MD * md ;
struct timeval tv ;
int res ;
/* process id */
pid = getpid ( ) ;
memcpy ( dst , ( uint8 * ) & pid , sizeof ( pid ) ) ;
dst + = sizeof ( pid ) ;
/* time */
gettimeofday ( & tv , NULL ) ;
memcpy ( dst , ( uint8 * ) & tv , sizeof ( tv ) ) ;
dst + = sizeof ( tv ) ;
/* pointless, but should not hurt */
x = random ( ) ;
memcpy ( dst , ( uint8 * ) & x , sizeof ( x ) ) ;
dst + = sizeof ( x ) ;
/* let's be desperate */
res = px_find_digest ( " sha1 " , & md ) ;
if ( res > = 0 ) {
uint8 * ptr ;
uint8 stack [ 8192 ] ;
int alloc = 32 * 1024 ;
px_md_update ( md , stack , sizeof ( stack ) ) ;
ptr = px_alloc ( alloc ) ;
px_md_update ( md , ptr , alloc ) ;
px_free ( ptr ) ;
px_md_finish ( md , dst ) ;
px_md_free ( md ) ;
dst + = 20 ;
}
if ( ! openssl_random_init )
init_openssl ( ) ;
return dst ;
}
res = RAND_pseudo_bytes ( dst , count ) ;
if ( res = = 0 | | res = = 1 )
return count ;
# endif
return PXE_OSSL_RAND_ERROR ;
/*
* try to extract some randomness for initial seeding
*
* dst should have room for 1024 bytes .
*/
unsigned px_acquire_system_randomness ( uint8 * dst )
{
uint8 * p = dst ;
# ifdef TRY_DEV_RANDOM
p = try_dev_random ( p ) ;
# endif
# ifdef TRY_WIN32_GENRAND
p = try_win32_genrand ( p ) ;
# endif
# ifdef TRY_WIN32_PERFC
p = try_win32_perfc ( p ) ;
# endif
# ifdef TRY_UNIXSTD
p = try_unix_std ( p ) ;
# endif
return p - dst ;
}
# else
# error "Invalid random source"
# endif