@ -39,10 +39,9 @@ win32_urandom_init(int raise)
return 0 ;
error :
if ( raise )
if ( raise ) {
PyErr_SetFromWindowsErr ( 0 ) ;
else
Py_FatalError ( " Failed to initialize Windows random API (CryptoGen) " ) ;
}
return - 1 ;
}
@ -55,8 +54,9 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
if ( hCryptProv = = 0 )
{
if ( win32_urandom_init ( raise ) = = - 1 )
if ( win32_urandom_init ( raise ) = = - 1 ) {
return - 1 ;
}
}
while ( size > 0 )
@ -65,11 +65,9 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
if ( ! CryptGenRandom ( hCryptProv , ( DWORD ) chunk , buffer ) )
{
/* CryptGenRandom() failed */
if ( raise )
if ( raise ) {
PyErr_SetFromWindowsErr ( 0 ) ;
else
Py_FatalError ( " Failed to initialized the randomized hash "
" secret using CryptoGen) " ) ;
}
return - 1 ;
}
buffer + = chunk ;
@ -86,29 +84,28 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
/* Fill buffer with size pseudo-random bytes generated by getentropy().
Return 0 on success , or raise an exception and return - 1 on error .
If fatal is nonzero , call Py_FatalError ( ) instead of raising an exception
on error . */
If raise is zero , don ' t raise an exception on error . */
static int
py_getentropy ( unsigned char * buffer , Py_ssize_t size , int fatal )
py_getentropy ( char * buffer , Py_ssize_t size , int raise )
{
while ( size > 0 ) {
Py_ssize_t len = Py_MIN ( size , 256 ) ;
int res ;
if ( ! fatal ) {
if ( raise ) {
Py_BEGIN_ALLOW_THREADS
res = getentropy ( buffer , len ) ;
Py_END_ALLOW_THREADS
if ( res < 0 ) {
PyErr_SetFromErrno ( PyExc_OSError ) ;
return - 1 ;
}
}
else {
res = getentropy ( buffer , len ) ;
if ( res < 0 )
Py_FatalError ( " getentropy() failed " ) ;
}
if ( res < 0 ) {
if ( raise ) {
PyErr_SetFromErrno ( PyExc_OSError ) ;
}
return - 1 ;
}
buffer + = len ;
@ -195,18 +192,15 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
if ( errno = = EINTR ) {
if ( PyErr_CheckSignals ( ) ) {
if ( ! raise )
Py_FatalError ( " getrandom() interrupted by a signal " ) ;
return - 1 ;
}
/* retry getrandom() */
continue ;
}
if ( raise )
if ( raise ) {
PyErr_SetFromErrno ( PyExc_OSError ) ;
else
Py_FatalError ( " getrandom() failed " ) ;
}
return - 1 ;
}
@ -225,9 +219,9 @@ static struct {
/* Read size bytes from /dev/urandom into buffer.
Call Py_FatalError ( ) on error . */
static void
dev_urandom_noraise ( unsigned char * buffer , Py_ssize_t size )
Return 0 success , or return - 1 on error . */
static int
dev_urandom_noraise ( char * buffer , Py_ssize_t size )
{
int fd ;
Py_ssize_t n ;
@ -235,31 +229,35 @@ dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
assert ( 0 < size ) ;
# ifdef PY_GETRANDOM
if ( py_getrandom ( buffer , size , 0 ) = = 1 )
return ;
if ( py_getrandom ( buffer , size , 0 ) = = 1 ) {
return 0 ;
}
/* getrandom() is not supported by the running kernel, fall back
* on reading / dev / urandom */
# endif
fd = _Py_open_noraise ( " /dev/urandom " , O_RDONLY ) ;
if ( fd < 0 )
Py_FatalError ( " Failed to open /dev/urandom " ) ;
if ( fd < 0 ) {
return - 1 ;
}
while ( 0 < size )
{
do {
n = read ( fd , buffer , ( size_t ) size ) ;
} while ( n < 0 & & errno = = EINTR ) ;
if ( n < = 0 )
{
if ( n < = 0 ) {
/* stop on error or if read(size) returned 0 */
Py_FatalError ( " Failed to read bytes from /dev/urandom " ) ;
break ;
return - 1 ;
}
buffer + = n ;
size - = n ;
}
close ( fd ) ;
return 0 ;
}
/* Read size bytes from /dev/urandom into buffer.
@ -379,31 +377,51 @@ lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
}
}
/* Fill buffer with size pseudo-random bytes from the operating system random
number generator ( RNG ) . It is suitable for most cryptographic purposes
except long living private keys for asymmetric encryption .
Return 0 on success , raise an exception and return - 1 on error . */
int
_PyOS_UR andom( void * buffer , Py_ssize_t size )
/* If raise is zero:
* - Don ' t raise exceptions on error
* - Don ' t call PyErr_CheckSignals ( ) on EINTR ( retry directly the interrupted
* syscall )
* - Don ' t release the GIL to call syscalls . */
static int
pyur andom( void * buffer , Py_ssize_t size , int rais e )
{
if ( size < 0 ) {
PyErr_Format ( PyExc_ValueError ,
" negative argument not allowed " ) ;
if ( raise ) {
PyErr_Format ( PyExc_ValueError ,
" negative argument not allowed " ) ;
}
return - 1 ;
}
if ( size = = 0 )
if ( size = = 0 ) {
return 0 ;
}
# ifdef MS_WINDOWS
return win32_urandom ( ( unsigned char * ) buffer , size , 1 ) ;
return win32_urandom ( ( unsigned char * ) buffer , size , raise ) ;
# elif defined(PY_GETENTROPY)
return py_getentropy ( buffer , size , 0 ) ;
return py_getentropy ( buffer , size , raise ) ;
# else
return dev_urandom_python ( ( char * ) buffer , size ) ;
if ( raise ) {
return dev_urandom_python ( buffer , size ) ;
}
else {
return dev_urandom_noraise ( buffer , size ) ;
}
# endif
}
/* Fill buffer with size pseudo-random bytes from the operating system random
number generator ( RNG ) . It is suitable for most cryptographic purposes
except long living private keys for asymmetric encryption .
Return 0 on success , raise an exception and return - 1 on error . */
int
_PyOS_URandom ( void * buffer , Py_ssize_t size )
{
return pyurandom ( buffer , size , 1 ) ;
}
void
_PyRandom_Init ( void )
{
@ -442,13 +460,14 @@ _PyRandom_Init(void)
}
}
else {
# ifdef MS_WINDOWS
( void ) win32_urandom ( secret , secret_size , 0 ) ;
# elif defined(PY_GETENTROPY)
( void ) py_getentropy ( secret , secret_size , 1 ) ;
# else
dev_urandom_noraise ( secret , secret_size ) ;
# endif
int res ;
/* _PyRandom_Init() is called very early in the Python initialization
* and so exceptions cannot be used . */
res = pyurandom ( secret , secret_size , 0 ) ;
if ( res < 0 ) {
Py_FatalError ( " failed to get random numbers to initialize Python " ) ;
}
}
}