📄 unix.c
字号:
noBytes = read( randFD, buffer, DEVRANDOM_BYTES );
close( randFD );
if( noBytes < 1 )
{
#ifdef DEBUG_RANDOM
printf( __FILE__ ": /dev/random read failed.\n" );
#endif /* DEBUG_RANDOM */
return( 0 );
}
#ifdef DEBUG_RANDOM
printf( __FILE__ ": /dev/random contributed %d bytes.\n", noBytes );
#endif /* DEBUG_RANDOM */
setMessageData( &msgData, buffer, noBytes );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_ENTROPY );
zeroise( buffer, DEVRANDOM_BYTES );
if( noBytes < DEVRANDOM_BYTES )
return( 0 );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE,
( void * ) &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
return( quality );
}
/* egd/prngd interface */
CHECK_RETVAL \
static int getEGDdata( void )
{
static const char *egdSources[] = {
"/var/run/egd-pool", "/dev/egd-pool", "/etc/egd-pool", NULL, NULL };
MESSAGE_DATA msgData;
BYTE buffer[ DEVRANDOM_BYTES + 8 ];
static const int quality = 75;
int egdIndex, sockFD, noBytes = CRYPT_ERROR, status;
/* Look for the egd/prngd output. We re-search each time because,
unlike /dev/random, it's both a user-level process and a movable
feast, so it can disappear and reappear at a different location
between runs */
sockFD = socket( AF_UNIX, SOCK_STREAM, 0 );
if( sockFD < 0 )
return( 0 );
for( egdIndex = 0; egdSources[ egdIndex ] != NULL && \
egdIndex < FAILSAFE_ARRAYSIZE( egdSources, char * );
egdIndex++ )
{
struct sockaddr_un sockAddr;
memset( &sockAddr, 0, sizeof( struct sockaddr_un ) );
sockAddr.sun_family = AF_UNIX;
strlcpy_s( sockAddr.sun_path, sizeof( sockAddr.sun_path ),
egdSources[ egdIndex ] );
if( connect( sockFD, ( struct sockaddr * ) &sockAddr,
sizeof( struct sockaddr_un ) ) >= 0 )
break;
}
ENSURES( egdIndex < FAILSAFE_ARRAYSIZE( egdSources, char * ) );
if( egdSources[ egdIndex ] == NULL )
{
close( sockFD );
return( 0 );
}
/* Read up to 128 bytes of data from the source:
write: BYTE 1 = read data nonblocking
BYTE DEVRANDOM_BYTES = count
read: BYTE returned bytes
BYTE[] data
As with /dev/random we only assign this a 75% quality factor to
ensure that we still get randomness from other sources as well */
buffer[ 0 ] = 1;
buffer[ 1 ] = DEVRANDOM_BYTES;
status = write( sockFD, buffer, 2 );
if( status == 2 )
{
status = read( sockFD, buffer, 1 );
noBytes = buffer[ 0 ];
if( status != 1 || noBytes < 0 || noBytes > DEVRANDOM_BYTES )
status = -1;
else
status = read( sockFD, buffer, noBytes );
}
close( sockFD );
if( ( status < 0 ) || ( status != noBytes ) )
{
#ifdef DEBUG_RANDOM
printf( __FILE__ ": EGD (%s) read failed.\n", egdSources[ egdIndex ] );
#endif /* DEBUG_RANDOM */
return( 0 );
}
/* Send the data to the pool */
#ifdef DEBUG_RANDOM
printf( __FILE__ ": EGD (%s) contributed %d bytes.\n",
egdSources[ egdIndex ], noBytes );
#endif /* DEBUG_RANDOM */
setMessageData( &msgData, buffer, noBytes );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_ENTROPY );
zeroise( buffer, DEVRANDOM_BYTES );
if( noBytes < DEVRANDOM_BYTES )
return( 0 );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE,
( void * ) &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
return( quality );
}
/* Named process information /procfs interface. Each source is given a
weighting of 1-3, with 1 being a static (although unpredictable) source,
2 being a slowly-changing source, and 3 being a rapidly-changing
source */
CHECK_RETVAL \
static int getProcFSdata( void )
{
typedef struct {
const char *source;
const int value;
} PROCSOURCE_INFO;
static const PROCSOURCE_INFO procSources[] = {
{ "/proc/diskstats", 2 }, { "/proc/interrupts", 3 },
{ "/proc/loadavg", 2 }, { "/proc/locks", 1 },
{ "/proc/meminfo", 3 }, { "/proc/net/dev", 2 },
{ "/proc/net/ipx", 2 }, { "/proc/modules", 1 },
{ "/proc/mounts", 1 }, { "/proc/net/netstat", 2 },
{ "/proc/net/rt_cache", 1 }, { "/proc/net/rt_cache_stat", 3 },
{ "/proc/net/snmp", 2 }, { "/proc/net/softnet_stat", 2 },
{ "/proc/net/stat/arp_cache", 3 }, { "/proc/net/stat/ndisc_cache", 2 },
{ "/proc/net/stat/rt_cache", 3 }, { "/proc/net/tcp", 3 },
{ "/proc/net/udp", 2 }, { "/proc/net/wireless", 2 },
{ "/proc/slabinfo", 3 }, { "/proc/stat", 3 },
{ "/proc/sys/fs/inode-state", 1 }, { "/proc/sys/fs/file-nr", 1 },
{ "/proc/sys/fs/dentry-state", 1 }, { "/proc/sysvipc/msg", 1 },
{ "/proc/sysvipc/sem", 1 }, { "/proc/sysvipc/shm", 1 },
{ "/proc/zoneinfo", 3 },
{ NULL, 0 }, { NULL, 0 }
};
MESSAGE_DATA msgData;
BYTE buffer[ 1024 + 8 ];
int procIndex, procFD, procValue = 0, quality;
/* Read the first 1K of data from some of the more useful sources (most
of these produce far less than 1K output) */
for( procIndex = 0;
procSources[ procIndex ].source != NULL && \
procIndex < FAILSAFE_ARRAYSIZE( procSources, PROCSOURCE_INFO );
procIndex++ )
{
int count, status;
/* Try and open the data source */
procFD = open( procSources[ procIndex ].source, O_RDONLY );
if( procFD < 0 )
continue;
if( procFD <= 2 )
{
/* We've been given a standard I/O handle, something's wrong */
close( procFD );
return( 0 );
}
/* Read data from the source */
count = read( procFD, buffer, 1024 );
if( count > 16 )
{
#ifdef DEBUG_RANDOM
printf( __FILE__ ": %s contributed %d bytes.\n",
procSources[ procIndex ].source, count );
#endif /* DEBUG_RANDOM */
setMessageData( &msgData, buffer, count );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_ENTROPY );
if( cryptStatusOK( status ) )
procValue += procSources[ procIndex ].value;
}
close( procFD );
}
ENSURES( procIndex < FAILSAFE_ARRAYSIZE( procSources, PROCSOURCE_INFO ) );
zeroise( buffer, 1024 );
if( procValue < 5 )
return( 0 );
/* Produce an estimate of the data's value. We require that we get a
quality value of at least 5 and limit it to a maximum value of 50 to
ensure that some data is still coming from other sources */
quality = min( procValue, 50 );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE,
( void * ) &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
return( quality );
}
/* Get data from an entropy source */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int getEntropySourceData( INOUT DATA_SOURCE_INFO *dataSource,
OUT_BUFFER( bufSize, *bufPos ) BYTE *bufPtr,
IN_LENGTH const int bufSize,
OUT_LENGTH int *bufPos )
{
int bufReadPos = 0, bufWritePos = 0;
size_t noBytes;
/* Try and get more data from the source. If we get zero bytes, the
source has sent us all it has */
if( ( noBytes = fread( bufPtr, 1, bufSize, dataSource->pipe ) ) <= 0 )
{
struct rusage rusage;
int total = 0;
/* If there's a problem, exit */
if( my_pclose( dataSource, &rusage ) != 0 )
return( 0 );
/* Try and estimate how much entropy we're getting from a data
source */
if( dataSource->usefulness != 0 )
{
if( dataSource->usefulness < 0 )
/* Absolute rating, 1024 / -n */
total = 1025 / -dataSource->usefulness;
else
/* Relative rating, 1024 * n */
total = dataSource->length / dataSource->usefulness;
}
#ifdef DEBUG_RANDOM
printf( __FILE__ ": %s %s contributed %d bytes (compressed), "
"usefulness = %d.\n", dataSource->path,
( dataSource->arg != NULL ) ? dataSource->arg : "",
dataSource->length, total );
#endif /* DEBUG_RANDOM */
/* Copy in the last bit of entropy data, the resource usage of the
popen()ed child */
if( sizeof( struct rusage ) < bufSize )
{
memcpy( bufPtr, &rusage, sizeof( struct rusage ) );
*bufPos += sizeof( struct rusage );
}
return( total );
}
/* Run-length compress the input byte sequence */
while( bufReadPos < noBytes )
{
const int ch = bufPtr[ bufReadPos ];
/* If it's a single byte or we're at the end of the buffer, just
copy it over */
if( bufReadPos >= bufSize - 1 || ch != bufPtr[ bufReadPos + 1 ] )
{
bufPtr[ bufWritePos++ ] = ch;
bufReadPos++;
}
else
{
int count = 0;
/* It's a run of repeated bytes, replace them with the byte
count mod 256 */
while( bufReadPos < noBytes && ( ch == bufPtr[ bufReadPos ] ) )
{
count++;
bufReadPos++;
}
bufPtr[ bufWritePos++ ] = count;
}
}
/* Remember the number of (compressed) bytes of input that we obtained */
*bufPos += bufWritePos;
dataSource->length += noBytes;
return( 0 );
}
/* The child process that performs the polling, forked from slowPoll() */
#define SLOWPOLL_TIMEOUT 30 /* Time out after 30 seconds */
static void childPollingProcess( const int existingEntropy )
{
GATHERER_INFO *gathererInfo;
MONOTIMER_INFO timerInfo;
BOOLEAN moreSources;
struct timeval tv;
struct rlimit rl = { 0, 0 };
fd_set fds;
#if defined( __hpux )
size_t maxFD = 0;
#else
int maxFD = 0;
#endif /* OS-specific brokenness */
int usefulness = 0, fdIndex, bufPos, i, iterationCount, status;
/* General housekeeping: Make sure that we can never dump core, and close
all inherited file descriptors. We need to do this because if we
don't and the calling app has FILE *'s open, these will be flushed
when we call exit() in the child and again when the parent writes to
them or closes them, resulting in everything that was present in the
FILE * buffer at the time of the fork() being written twice. An
alternative solution would be to call _exit() instead if exit() below,
but this is somewhat system-dependant and therefore a bit risky to
use.
In addition to this we should in theory call cryptEnd() since we
don't need any cryptlib objects beyond this point and it'd be a good
idea to clean them up to get rid of sensitive data held in memory.
However in some cases when using a crypto device or network interface
or similar item the shutdown in the child will also shut down the
parent item because while cryptlib objects are reference-counted the
external items aren't (they're beyond the control of cryptlib). Even
destroying just contexts with keys loaded isn't possible because they
may be tied to a device that will propagate the shutdown from the
child to the parent via the device.
In general the child will be short-lived, and the use in its further
children of vfork() or the fact that many modern fork()s have copy-on-
write semantics even if no vfork() is available will mean that
cryptlib memory is never copied to the child and further children. It
would, however, be better if there were some way to perform a neutron-
bomb type shutdown that only zeroises senstive information while
leaving structures intact */
setrlimit( RLIMIT_CORE, &rl );
for( fdIndex = getdtablesize() - 1; fdIndex > STDOUT_FILENO; fdIndex-- )
close( fdIndex );
fclose( stderr ); /* Arrghh!! It's Stuart code!! */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -