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

📄 rndunix.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
		printf( "PIOCUSAGE contributed %d bytes.\n", sizeof( prusage_t ) );
#endif /* DEBUG_RANDOM */
		addRandomData( randomState, &prUsage, sizeof( prusage_t ) );
		noEntries++;
		}
#endif /* PIOCUSAGE */
	close( fd );

	/* Flush any remaining data through and produce an estimate of its
	   value.  We require that at least two of the sources exist and accesses
	   to them succeed, and give them a relatively low value since they're
	   returning information that has some overlap with that returned by the
	   general slow poll (although there's also a lot of low-level stuff
	   present that the slow poll doesn't get) */
	endRandomData( randomState, ( noEntries > 2 ) ? 10 : 0 );
	}
#endif /* Slowaris || OSF/1 || Linux */

/* /dev/random interface */

#define DEVRANDOM_BYTES		128

static void getDevRandomData( void )
	{
	RESOURCE_DATA msgData;
	BYTE buffer[ DEVRANDOM_BYTES ];
#ifdef __APPLE__
	static const int quality = 50;	/* See comment below */
#else
	static const int quality = 75;
#endif /* Mac OS X */
	int randFD, noBytes;

	/* Check whether there's a /dev/random present */
	if( ( randFD = open( "/dev/urandom", O_RDONLY ) ) < 0 )
		return;

	/* Read data from /dev/urandom, which won't block (although the quality
	   of the noise is less).  We only assign this a 75% quality factor to
	   ensure that we still get randomness from other sources as well.  Under
	   OS X, the /dev/random implementation is broken, using a pretend-dev-
	   random implemented with Yarrow and a 160-bit pool, so we only assign
	   a 50% quality factor. The OS X generator also lies about entropy,
	   with both /random and /urandom being the same PRNG-based
	   implementation */
	noBytes = read( randFD, buffer, DEVRANDOM_BYTES );
	close( randFD );
	if( noBytes < 1 )
		return;
#ifdef DEBUG_RANDOM
	printf( "/dev/random contributed %d bytes.\n", DEVRANDOM_BYTES );
#endif /* DEBUG_RANDOM */
	setMessageData( &msgData, buffer, DEVRANDOM_BYTES );
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData,
					 CRYPT_IATTRIBUTE_ENTROPY );
	zeroise( buffer, DEVRANDOM_BYTES );
	if( noBytes == DEVRANDOM_BYTES )
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE,
						 ( void * ) &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
	}

/* egd/prngd interface */

static void getEGDdata( void )
	{
	static const char *egdSources[] = {
		"/var/run/egd-pool", "/dev/egd-pool", "/etc/egd-pool", NULL };
	RESOURCE_DATA msgData;
	BYTE buffer[ DEVRANDOM_BYTES ];
	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;
	for( egdIndex = 0; egdSources[ egdIndex ] != NULL; egdIndex++ )
		{
		struct sockaddr_un sockAddr;

		memset( &sockAddr, 0, sizeof( struct sockaddr_un ) );
		sockAddr.sun_family = AF_UNIX;
		strcpy( sockAddr.sun_path, egdSources[ egdIndex ] );
		if( connect( sockFD, ( struct sockaddr * ) &sockAddr,
					 sizeof( struct sockaddr_un ) ) >= 0 )
			break;
		}
	if( egdSources[ egdIndex ] == NULL )
		{
		close( sockFD );
		return;
		}

	/* 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 ) )
		return;

	/* Send the data to the pool */
#ifdef DEBUG_RANDOM
	printf( "EGD (%s) contributed %d bytes.\n", egdSources[ egdIndex ],
			DEVRANDOM_BYTES );
#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 )
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE,
						 ( void * ) &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
	}

/* Named process information /procfs interface */

static void getProcFSdata( void )
	{
	static const char *procSources[] = {
		"/proc/interrupts", "/proc/loadavg", "/proc/locks", "/proc/meminfo",
		"/proc/stat", "/proc/net/tcp", "/proc/net/udp", "/proc/net/dev",
		"/proc/net/ipx", NULL };
	RESOURCE_DATA msgData;
	BYTE buffer[ 1024 ];
	static const int quality = 4;
	int procIndex, procFD;

	/* 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 ] != NULL; procIndex++ )
		{
		if( ( procFD = open( procSources[ procIndex ], O_RDONLY ) ) >= 0 )
			{
			const int count = read( procFD, buffer, 1024 );

			if( count > 16 )
				{
#ifdef DEBUG_RANDOM
				printf( "%s contributed %d bytes.\n", buffer, count );
#endif /* DEBUG_RANDOM */
				setMessageData( &msgData, buffer, count );
				krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								 IMESSAGE_SETATTRIBUTE_S, &msgData,
								 CRYPT_IATTRIBUTE_ENTROPY );
				krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE,
								 ( void * ) &quality,
								 CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
				}
			close( procFD );
			}
		}
	zeroise( buffer, 1024 );
	}

/* Get data from an entropy source */

static int getEntropySourceData( struct RI *dataSource, BYTE *bufPtr,
								 const int bufSize, 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 or no data was obtained, exit */
		if( my_pclose( dataSource, &rusage ) != 0 || \
			dataSource->usefulness <= 0 )
			return( 0 );

		/* Try and estimate how much entropy we're getting from a data
		   source */
		if( dataSource->usefulness < 0 )
			total = ( dataSource->length + 999 ) / -dataSource->usefulness;
		else
			total = dataSource->length / dataSource->usefulness;
#ifdef DEBUG_RANDOM
		printf( "%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( ( ch == bufPtr[ bufReadPos ] ) && bufReadPos < noBytes )
				{
				count++;
				bufReadPos++;
				}
			bufPtr[ bufWritePos++ ] = count;
			}
		}

	/* Remember the number of (compressed) bytes of input we obtained */
	*bufPos += bufWritePos;
	dataSource->length += noBytes;

	return( 0 );
	}

/* Unix slow poll.  If a few of the randomness sources create a large amount
   of output then the slowPoll() stops once the buffer has been filled (but
   before all the randomness sources have been sucked dry) so that the
   'usefulness' factor remains below the threshold.  For this reason the
   gatherer buffer has to be fairly sizeable on moderately loaded systems */

#define SHARED_BUFSIZE		49152	/* Usually about 25K are filled */
#define SLOWPOLL_TIMEOUT	30		/* Time out after 30 seconds */

void slowPoll( void )
	{
	GATHERER_INFO *gathererInfo;
	BOOLEAN moreSources;
	struct timeval tv;
	struct rlimit rl = { 0, 0 };
	struct sigaction act, oact;
	fd_set fds;
	time_t startTime;
	const int pageSize = getPageSize();
#if defined( __hpux )
	size_t maxFD = 0;
#else
	int maxFD = 0;
#endif /* OS-specific brokenness */
	int fd, bufPos, i, usefulness = 0;

	/* Make sure we don't start more than one slow poll at a time */
	enterMutex( MUTEX_RANDOMPOLLING );
	if( gathererProcess	)
		{
		exitMutex( MUTEX_RANDOMPOLLING );
		return;
		}

	/* Some systems provide further info that we can grab before we start
	   the slow poll */
	getDevRandomData();
	if( access( "/proc/interrupts", R_OK ) )
		getProcFSdata();
	getEGDdata();
#ifdef USE_KSTAT
	getKstatData();
#endif /* USE_KSTAT */
#ifdef USE_PROC
	getProcData();
#endif /* USE_PROC */

	/* Reset the SIGCHLD handler to the system default.  This is necessary
	   because if the program that cryptlib is a part of installs its own
	   SIGCHLD handler, it will end up reaping the cryptlib children before
	   cryptlib can.  As a result, my_pclose() will call waitpid() on a
	   process that has already been reaped by the installed handler and
	   return an error, so the read data won't be added to the randomness
	   pool */
#if 1
	memset( &act, 0, sizeof( act ) );
	act.sa_handler = SIG_DFL;
	sigemptyset( &act.sa_mask );
	if( sigaction( SIGCHLD, &act, &oact ) < 0 )
		{
		/* This assumes that stderr is open, i.e. that we're not a daemon
		   (this should be the case at least during the development/debugging
		   stage) */
		fprintf( stderr, "cryptlib: sigaction failed, errno = %d, "
				 "file = %s, line = %d.\n", errno, __FILE__, __LINE__ );
		abort();
		}

	/* Check for handler override. */
	if( oact.sa_handler != SIG_DFL && oact.sa_handler != SIG_IGN )
		/* We overwrote the caller's handler, warn them about this */
		fprintf( stderr, "cryptlib: Conflicting SIGCHLD handling detected "
				 "in randomness polling code,\nfile " __FILE__ ", line %d.  "
				 "See the source code for more\ninformation.\n", __LINE__ );

#else	/* Deprecated - 6/4/03 */
	void ( *disp )( int );

	/* Under the old unreliable signals interface there are two types of
	   SIGC(H)LD naming, the SysV SIGCLD (with weird SysV-specific
	   semantics) and the BSD/Posix SIGCHLD, so we need to handle either
	   possibility */
  #ifdef SIGCLD
	disp = signal( SIGCLD, SIG_DFL );
  #else
	disp = signal( SIGCHLD, SIG_DFL );
  #endif /* SIGCLD */
	if( disp != SIG_DFL && disp != SIG_IGN )
		{
		/* The user has installed their own SIGC(H)LD handler, warn them that
		   they need to take special steps to manage this problem.  This is

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -