⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unix.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -