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

📄 rndwin32.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
			DWORD dwSize = PERFORMANCE_BUFFER_SIZE, dwType;
			int noResults = 0;

			/* Scan the first 64 possible information types (we don't bother
			   with increasing the buffer size as we do with the Win32 version
			   of the performance data read, we may miss a few classes but
			   it's no big deal).  In addition the returned size value for
			   some classes is wrong (eg 23 and 24 return a size of 0) so we
			   miss a few more things, but again it's no big deal.  This scan
			   typically yields around 20 pieces of data, there's nothing in
			   the range 65...128 so chances are there won't be anything above
			   there either */
			for( dwType = 0; dwType < 64; dwType++ )
				{
				status = pNtQuerySystemInfo( dwType, ( DWORD ) buffer,
											 32768, ( DWORD ) &dwSize );
				if( status == ERROR_SUCCESS && dwSize > 0 )
					{
					setResourceData( &msgData, buffer, dwSize );
					status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
										RESOURCE_IMESSAGE_SETATTRIBUTE_S,
										&msgData, CRYPT_IATTRIBUTE_RANDOM );
					if( cryptStatusOK( status ) )
						noResults++;
					}
				}
			free( buffer );

			/* If we got enough data, we can leave now without having to try
			   for a Win32-level performance information query */
			if( noResults > 15 )
				{
				int quality = 100;

				krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								 RESOURCE_IMESSAGE_SETATTRIBUTE, &quality,
								 CRYPT_IATTRIBUTE_RANDOM_QUALITY );
				return;
				}
			}
		}

	/* Wait for any async keyset driver binding to complete.  You may be
	   wondering what this call is doing here... the reason it's necessary is
	   because RegQueryValueEx() will hang indefinitely if the async driver
	   bind is in progress.  The problem occurs in the dynamic loading and
	   linking of driver DLL's, which work as follows:

		hDriver = LoadLibrary( DRIVERNAME );
		pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 );
		pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 );

	   If RegQueryValueEx() is called while the GetProcAddress()'s are in
	   progress, it will hang indefinitely.  This is probably due to some
	   synchronisation problem in the NT kernel where the GetProcAddress()
	   calls affect something like a module reference count or function
	   reference count while RegQueryValueEx() is trying to take a snapshot of
	   the statistics, which include the reference counts.  Because of this,
	   we have to wait until any async driver bind has completed before we can
	   call RegQueryValueEx() */
	waitSemaphore( SEMAPHORE_DRIVERBIND );

	/* Get information from the system performance counters.  This can take a
	   few seconds to do.  In some environments the call to RegQueryValueEx()
	   can produce an access violation at some random time in the future, in
	   some cases adding a short delay after the following code block makes
	   the problem go away.  This problem is extremely difficult to
	   reproduce, I haven't been able to get it to occur despite running it
	   on a number of machines.  MS knowledge base article Q178887 covers
	   this type of problem, it's typically caused by an external driver or
	   other program which adds its own values under the
	   HKEY_PERFORMANCE_DATA key.  The NT kernel, via Advapi32.dll, calls the
	   required external module to map in the data inside an SEH try/except
	   block, so problems in the module's collect function don't pop up until
	   after it has finished, so the fault appears to occur in Advapi32.dll.
	   There may be problems in the NT kernel as well though, a low-level
	   memory checker indicated that ExpandEnvironmentStrings() in
	   Kernel32.dll, called an interminable number of calls down inside
	   RegQueryValueEx(), was overwriting memory (it wrote twice the
	   allocated size of a buffer to a buffer allocated by the NT kernel).
	   OTOH this could be coming from the external module calling back into
	   the kernel, which eventually causes the problem described above.

	   Possibly as an extension of the problem which the waitSemaphore() call
	   above works around, running two instances of cryptlib (eg two
	   applications which use it) under NT4 can result in one of them hanging
	   in the RegQueryValueEx() call.  This happens only under NT4 and is
	   hard to reproduce in any consistent manner.

	   One workaround which helps a bit is to read the registry as a remote
	   (rather than local) registry, it's possible that the use of a network
	   RPC call isolates the calling app from the problem in that whatever
	   service handles the RPC is taking the hit and not affecting the
	   calling app.  Since this would require another round of extensive
	   testing to verify and the NT native API call is working fine, we'll
	   stick with the native API call for now.

	   Some versions of NT4 had a problem where the amount of data returned
	   was mis-reported and would never settle down, because of this the code
	   below includes a safety-catch which bails out after 10 attempts have
	   been made, this results in no data being returned but at does ensure
	   that the thread will terminate.

	   In addition to these problems the code in RegQueryValueEx() which
	   estimates the amount of memory required to return the performance
	   counter information isn't very accurate (it's much worse than the
	   "slightly-inaccurate" level which the MS docs warn about, it's usually
	   wildly off) since it always returns a worst-case estimate which is
	   usually nowhere near the actual amount required.  For example it may
	   report that 128K of memory is required, but only return 64K of data.

	   Even worse than the registry-based performance counters is the
	   performance data helper (PDH) shim which tries to make the counters
	   look like the old Win16 API (which is also used by Win95).  Under NT
	   this can consume tens of MB of memory and huge amounts of CPU time
	   while it gathers its data, and even once running can still consume
	   about 1/2MB of memory */
	pPerfData = ( PPERF_DATA_BLOCK ) malloc( cbPerfData );
	while( pPerfData != NULL && iterations++ < 10 )
		{
		dwSize = cbPerfData;
		status = RegQueryValueEx( HKEY_PERFORMANCE_DATA, "Global", NULL,
								  NULL, ( LPBYTE ) pPerfData, &dwSize );
		if( status == ERROR_SUCCESS )
			{
			if( !memcmp( pPerfData->Signature, L"PERF", 8 ) )
				{
				int quality = 100, status;

				setResourceData( &msgData, pPerfData, dwSize );
				status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								RESOURCE_IMESSAGE_SETATTRIBUTE_S, &msgData,
								CRYPT_IATTRIBUTE_RANDOM );
				if( cryptStatusOK( status ) )
					krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								RESOURCE_IMESSAGE_SETATTRIBUTE, &quality,
								CRYPT_IATTRIBUTE_RANDOM_QUALITY );
				}
			free( pPerfData );
			pPerfData = NULL;
			}
		else
			if( status == ERROR_MORE_DATA )
				{
				cbPerfData += PERFORMANCE_BUFFER_STEP;
				pPerfData = ( PPERF_DATA_BLOCK ) realloc( pPerfData, cbPerfData );
				}
		}

	/* Although this isn't documented in the Win32 API docs, it's necessary to
	   explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
	   implicitly opened on the first call to RegQueryValueEx()).  If this
	   isn't done then any system components which provide performance data
	   can't be removed or changed while the handle remains active */
	RegCloseKey( HKEY_PERFORMANCE_DATA );
	}

/* Perform a thread-safe slow poll for Windows NT.  The following function
   *must* be started as a thread */

unsigned __stdcall threadSafeSlowPollWinNT( void *dummy )
	{
	UNUSED( dummy );

	slowPollWinNT();
	_endthreadex( 0 );
	return( 0 );
	}

/* Perform a generic slow poll.  This starts the OS-specific poll in a
   separate thread */

void slowPoll( void )
	{
	static BOOLEAN serialRngInitialised = FALSE;
	unsigned threadID;

	/* Try and initialise the serial-port RNG.  We can't do this during the
	   general initialisation because it requires access to user config
	   options (specifying the port and parameters) which aren't available
	   at that point */
	if( !serialRngInitialised )
		{
		initSerialRNG();	/* Sets hComm if it succeeds */
		serialRngInitialised = TRUE;
		}

	/* If there's a PIII RNG present, read data from it */
	if( hProv != NULL )
		{
		BYTE buffer[ PIIIRNG_BYTES ];

		/* Read 128 bytes from the serial PIII.  We don't rely on this for
		   all our randomness requirements in case it's broken in some way */
		if( pCryptGenRandom( hProv, PIIIRNG_BYTES, buffer ) )
			{
			RESOURCE_DATA msgData;
			int quality = 90;

			setResourceData( &msgData, buffer, PIIIRNG_BYTES );
			krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							 RESOURCE_IMESSAGE_SETATTRIBUTE_S, &msgData,
							 CRYPT_IATTRIBUTE_RANDOM );
			krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							 RESOURCE_IMESSAGE_SETATTRIBUTE, &quality,
							 CRYPT_IATTRIBUTE_RANDOM_QUALITY );
			zeroise( buffer, PIIIRNG_BYTES );
			}
		}

	/* If there's a serial-port RNG present, read data from it */
	if( hComm != NULL )
		{
		BYTE buffer[ SERIALRNG_BYTES ];
		DWORD bytesRead;

		/* Read 128 bytes from the serial RNG.  We don't rely on this for
		   all our randomness requirements in case it's broken in some way */
		PurgeComm( hComm, PURGE_RXABORT | PURGE_RXCLEAR );
		if( ReadFile( hComm, buffer, SERIALRNG_BYTES, &bytesRead, NULL ) && \
			bytesRead == SERIALRNG_BYTES )
			{
			RESOURCE_DATA msgData;
			int quality = 90;

			setResourceData( &msgData, buffer, SERIALRNG_BYTES );
			krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							 RESOURCE_IMESSAGE_SETATTRIBUTE_S, &msgData,
							 CRYPT_IATTRIBUTE_RANDOM );
			krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							 RESOURCE_IMESSAGE_SETATTRIBUTE, &quality,
							 CRYPT_IATTRIBUTE_RANDOM_QUALITY );
			zeroise( buffer, SERIALRNG_BYTES );
			}
		}

	/* Start a threaded slow poll.  If a slow poll is already running, we
	   just return since there isn't much point in running two of them at the
	   same time */
	if( !hThread )
		if( isWin95 )
			hThread = ( HANDLE ) _beginthreadex( NULL, 0, &threadSafeSlowPollWin95,
												 NULL, 0, &threadID );
		else
			hThread = ( HANDLE ) _beginthreadex( NULL, 0, &threadSafeSlowPollWinNT,
												 NULL, 0, &threadID );
	}

/* Wait for the randomness gathering to finish.  Anything that requires the
   gatherer process to have completed gathering entropy should call
   waitforRandomCompletion(), which will block until the background process
   completes */

void waitforRandomCompletion( void )
	{
	if( hThread )
		{
		WaitForSingleObject( hThread, INFINITE );
		CloseHandle( hThread );
		hThread = NULL;
		}
	}

/* Initialise and clean up any auxiliary randomness-related objects */

void initRandomPolling( void )
	{
	/* Reset the various module and object handles */
	hAdvAPI32 = hNetAPI32 = hThread = hComm = hProv = NULL;

	/* Try and connect to the PIII RNG CSP if it's present */
	if( ( hAdvAPI32 = GetModuleHandle( "ADVAPI32.DLL" ) ) != NULL )
		{
		/* Now get pointers to the functions.  Although the acquire context
		   function looks like a standard function, it's actually a macro
		   which is mapped to CryptAcquireContextA so we access it under
		   that name */
		pCryptAcquireContext = ( CRYPTACQUIRECONTEXT ) GetProcAddress( hAdvAPI32,
													"CryptAcquireContextA" );
		pCryptGenRandom = ( CRYPTGENRANDOM ) GetProcAddress( hAdvAPI32,
													"CryptGenRandom" );
		pCryptReleaseContext = ( CRYPTRELEASECONTEXT ) GetProcAddress( hAdvAPI32,
													"CryptReleaseContext" );

		/* Make sure we got valid pointers for every CryptoAPI function and
		   that the required CSP is present */
		if( pCryptAcquireContext == NULL || \
			pCryptGenRandom == NULL || pCryptReleaseContext == NULL || \
			pCryptAcquireContext( &hProv, NULL, INTEL_DEF_PROV,
								  PROV_INTEL_SEC, 0 ) == FALSE )
			{
			hAdvAPI32 = NULL;
			hProv = NULL;
			}
		}
	}

void endRandomPolling( void )
	{
	if( hThread )
		CloseHandle( hThread );
	if( hNetAPI32 )
		{
		FreeLibrary( hNetAPI32 );
		hNetAPI32 = NULL;
		}
	if( hProv != NULL )
		{
		pCryptReleaseContext( hProv, 0 );
		hProv = NULL;
		}
	if( hComm != NULL )
		{
		CloseHandle( hComm );
		hComm = NULL;
		}
	}

⌨️ 快捷键说明

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