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

📄 pgprndseed.c

📁 PGP8.0源码 请认真阅读您的文件包然后写出其具体功能
💻 C
字号:
/*____________________________________________________________________________
	Copyright (C) 2002 PGP Corporation
	All rights reserved.

	$Id: pgpRndSeed.c,v 1.26 2002/10/08 22:28:33 wjb Exp $
____________________________________________________________________________*/
#include "pgpConfig.h"

#include "pgpDebug.h"
#include "pgpMem.h"
#include "pgpPFLPriv.h"

#include "pgpRnd.h"
#include "pgpCFB.h"
#include "pgpErrors.h"
#include "pgpFileUtilities.h"

#include "pgpCFBPriv.h"
#include "pgpRndSeed.h"
#include "pgpRandomPoolPriv.h"
#include "pgpRandomContext.h"
#include "pgpRandomX9_17.h"
#include "pgpUtilities.h"
#include "pgpEnv.h"
#include "pgpContext.h"
#include "pgpFileRef.h"
#include "pgpFIPSPriv.h"
#include "pgpKeyPriv.h"

#if PGP_MACINTOSH
#include "MacErrors.h"
#include "MacFiles.h"
#include "MacStrings.h"

#elif PGP_WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif


/* evil, but the random pool IS global */
static PGPBoolean		sIsSeeded	= FALSE;
static PFLFileSpecRef	sRandSeedFile = NULL;


#if PGP_MACINTOSH	/* [ */	
	
	static PGPError
GetDefaultRandSeedFileRef(
	PGPMemoryMgrRef		mgr,
	PFLFileSpecRef	*	outRef)
{
	PGPError	err	= kPGPError_NoErr;
	FSSpec		fileSpec;
	
	err = MacErrorToPGPError( FindPGPPreferencesFolder( kOnSystemDisk,
					&fileSpec.vRefNum, &fileSpec.parID ) );
	if( IsntPGPError( err ) )
	{
		CopyPString( "\pPGP Random Seed", fileSpec.name );
		
		err = PFLNewFileSpecFromFSSpec( mgr, &fileSpec, outRef );
	}
			
	return err;
}

#elif PGP_WIN32	/* ][ */

/*	
 *	we're going to use SHFOLDER.DLL to supply us with the folder
 *	location of where the default randseed file goes 
 */

#ifndef CSIDL_COMMON_APPDATA
#define CSIDL_COMMON_APPDATA	0x0023
#endif
#ifndef CSIDL_FLAG_CREATE
#define CSIDL_FLAG_CREATE		0x8000
#endif

#define PGP_RELATIVEPATHNAME		("PGP Corporation\\PGP\\")
typedef HRESULT (_stdcall *SHGetFolderPathProc)
				(HWND, int, HANDLE, DWORD, LPTSTR);


/*
 *	create the specified path if it doesn't already exist
 */

	static void
sCreatePath (
		LPSTR	pszPath)
{
	DWORD	dw;
	LPSTR	p;

	dw = GetFileAttributes( pszPath );
	if( ( dw != 0xFFFFFFFF ) &&
		( dw & FILE_ATTRIBUTE_DIRECTORY ) )
	{
		return;
	}

	if( dw != 0xFFFFFFFF )
		return;

	p = strchr( pszPath, '\\' );
	while ( p )
	{
		*p = '\0';
		CreateDirectory( pszPath, NULL );
		*p = '\\';
		p++;
		p = strchr( p, '\\' );
	}
	return;
}


	static PGPError
GetDefaultRandSeedFileRef(
	PGPMemoryMgrRef		mgr,
	PFLFileSpecRef	*	outRef)
{
	PGPError	err		= kPGPError_NoErr;
	HMODULE		hmod	= NULL;
	SHGetFolderPathProc	fpSHGetFolderPath = NULL;

	char		path[MAX_PATH];
	
	path[0] = '\0';

	hmod = LoadLibrary( "SHFOLDER.DLL" );
	if (hmod != NULL)
	{
		fpSHGetFolderPath = (SHGetFolderPathProc)
				GetProcAddress(hmod, "SHGetFolderPathA");

		if (fpSHGetFolderPath != NULL)
		{
			if ( SUCCEEDED( fpSHGetFolderPath(
					NULL, CSIDL_COMMON_APPDATA|CSIDL_FLAG_CREATE, 
					NULL, 0, path ) ) &&
				( path[0] != 0 ) )
			{
				if( path[strlen( path )-1] != '\\' )
					strcat( path, "\\" );
				
				strcat( path, PGP_RELATIVEPATHNAME );
			}
		}
		FreeLibrary(hmod);
	}

	if( path[0] == '\0' )
	{
		// error, try the Windows directory
		if( GetWindowsDirectory( path, sizeof(path) ) == 0 )
			strcpy( path, "." );
	}

	if( path[strlen( path )-1] != '\\' )
		strcat( path, "\\" );

	strcat( path, "randseed.rnd" );
	sCreatePath( path );

	err	= PFLNewFileSpecFromFullPath( mgr, path, outRef );
			
	return err;
}


#elif PGP_UNIX && !PGP_OSX	/* ][ */

	static PGPError
GetDefaultRandSeedFileRef(
	PGPMemoryMgrRef		mgr,
	PFLFileSpecRef	*	outRef)
{
	PGPError			err	= kPGPError_NoErr;
	const char *		pgppath1;
	const char *		randSeedFileName = "randseed.rnd";
	const char *		pgppath2 = "/";
	char *				prefpath;
	
	pgppath1 = getenv( "PGPPATH" );
	if( IsNull( pgppath1 ) )
	{
		pgppath1 = getenv( "HOME" );
		if( IsNull( pgppath1 ) )
		{
			pgppath1 = ".";
		}
		else
		{
			pgppath2 = "/.pgp/";
		}
	}

	prefpath = PGPNewData( mgr, strlen(pgppath1) + strlen(pgppath2) +
					strlen(randSeedFileName) + 1, 0 );
	if( IsNull( prefpath ) )
		return kPGPError_OutOfMemory;
	
	strcpy( prefpath, pgppath1 );
	strcat( prefpath, pgppath2 );
	strcat( prefpath, randSeedFileName );

	err = PFLNewFileSpecFromFullPath( mgr, prefpath, outRef );

	PGPFreeData( prefpath );

	return err;
}

#endif



/*
 * Save the state of the random number generator to "file" using "cfb"
 * as the washing mechanism.  If cfb is NULL, do not wash the output.
 *
 * Try to write "bytes", or a reasonable minimum size, whichever is the
 * greater.  Returns the number of bytes actually written.
 */
	static PGPError
pgpRandSeedWriteBytes (
	PGPIORef					io,
	PGPRandomContext const *	rc,
	PGPCFBContext *				cfb,
	PGPUInt32					requestCount,
	PGPSize *					writeCount)
{
	PGPUInt32					total	= 0;
	PGPUInt32					minsize;
	PGPRandomContext			randPoolContext;
	PGPByte						buf[ 512 ];
	PGPError					err	= kPGPError_NoErr;
	
	pgpAssertAddrValid( io, char );
	if ( IsntNull( writeCount ) )
		*writeCount	= 0;

	pgpInitGlobalRandomPoolContext( &randPoolContext );

	/* If no randomcontext passed, default to the global pool */
	if ( IsNull( rc ) )
	{
		rc = (PGPRandomContext const *)&randPoolContext;
	}

	/* Figure out a "reasonable minimum size" */
	minsize = (PGPGlobalRandomPoolGetSize()+7)/8;
	if (minsize < PGP_SEED_MIN_BYTES)
		minsize = PGP_SEED_MIN_BYTES;
	else if (minsize > 512)
		minsize = 512;

	/* Always try to write at least this "reasonable minimum size" */
	if (requestCount < minsize)
		requestCount = minsize;

	/* Add entropy to the global random pool based on current time */
	(void)pgpRandomCollectEntropy( &randPoolContext );

	/* Stir, to hide patterns */
	pgpRandomStir(rc);

	total = 0;
	while (total < requestCount)
	{
		PGPUInt32	len;
		
		len	= requestCount - total;
		if ( len > sizeof( buf ) )
			len	= sizeof( buf );

		pgpRandomGetBytes(rc, buf, len);
		if( IsntNull( cfb ) )
			pgpCFBEncryptInternal (cfb, buf, len, buf);
		err = PGPIOWrite( io, len, buf );
		if ( IsPGPError( err ) )
			break;
			
		total += len;
	}
	/* is there any security reason to do this? */
	pgpClearMemory( buf, sizeof(buf) );
	
	if ( IsntNull( writeCount ) )
		*writeCount	= total;
	
	return( err );
}


/*
 * Save the "state" of the random number generator to "file" using
 * "cfb" as the washing mechanism.  If cfb is NULL, do not wash
 * the output.
 */
	static void
pgpRandSeedWrite(
	PGPIORef					io,
	PGPRandomContext const *	rc,
	PGPCFBContext *	cfb)
{
	pgpAssertAddrValid( io, char );

	(void)pgpRandSeedWriteBytes( io, rc, cfb, 0, NULL );
}



/*
 * Load the RNG state from the file on disk (randseed.rnd).
 * Returns 0 on success, <0 on error.
 * Must read at least 24 bytes (the size of the X9.17 generator's
 * state) to be considered successful.  Any additional data is just
 * dumped into the "true" randpool.
 */
	static PGPError
pgpRandSeedRead(
	PGPIORef					io,
	PGPRandomContext const *	rc)
{
	PGPSize				total, rewriteCount;
	PGPRandomContext	randPoolContext;
	PGPError			err	= kPGPError_NoErr;
	
	pgpAssert( IsntNull( io ) );
	if ( IsNull( io ) )
		return kPGPError_BadParams;

	pgpInitGlobalRandomPoolContext( &randPoolContext );

	/* Dump the file into the random number generator */
	total = 0;
	while ( TRUE )
	{
		PGPByte				buf[ 512 ];
		PGPSize				actualCount;
		
		err	= PGPIORead( io, sizeof( buf ), buf, &actualCount );
		if ( IsPGPError( err ) )
			break;
			
		total += actualCount;
		/* Add the data both to the X9.17 layer and the underlying pool */
		if ( IsntNull( rc ) )
		{
			pgpRandomAddBytes(rc, buf, actualCount);
		}
		pgpRandomAddBytes( &randPoolContext, buf, actualCount );
	}

	/* Write it back out again */
	err	= PGPIOSetPos( io, 0 );
	if ( IsntPGPError( err ) )
	{
		err = pgpRandSeedWriteBytes( io, rc, NULL, total, &rewriteCount );
	}
	else
	{
		rewriteCount	= 0;
	}

	/*
	 * If we can't rewrite it, we may have the same seed as
	 * another run of the program, which means it's not entropy
	 * at all.  We try not to depend *totally* on the seed file,
	 * but paranoia is many levels deep.
	 */
	/* If we didn't read enough *or* rewrite enough, complain */
	if (total < PGP_SEED_MIN_BYTES || rewriteCount < PGP_SEED_MIN_BYTES)
		return kPGPError_RandomSeedTooSmall;
		
	return kPGPError_NoErr;
}


	PGPBoolean	
pgpGlobalRandomPoolIsSeeded( void )
{
	return( sIsSeeded );
}

	void
pgpSetIsSeeded( void)
{
	sIsSeeded = TRUE;
}

	static PGPError
sSeedGlobalRandomPool( )
{
	PGPError			err	= kPGPError_NoErr;
	PGPRandomContext	randomContext;
	PGPFileIORef		fileIO	= NULL;

	if ( !sIsSeeded ) 
		pgpInitGlobalRandomPool();

	pgpInitGlobalRandomPoolContext( &randomContext );

	/* Read in the randseed file */

	err	= PGPOpenFileSpec( sRandSeedFile, kPFLFileOpenFlags_ReadWrite,
						   &fileIO );

	if ( IsntPGPError( err ) )
	{
		err	= pgpRandSeedRead( (PGPIORef)fileIO, &randomContext );
		PGPFreeIO( (PGPIORef)fileIO );
		fileIO	= NULL;
	}
	
	if( IsntPGPError( err ) )
		sIsSeeded	= TRUE;
	
	return( err );
}



/*____________________________________________________________________________
	Add file data into the pool.  Used to add existing random pool file data
	into the random pool before overwiting it.  This fixes a problem where
	the last client to quit wipes out contributions of previous clients to
	the random pool.
____________________________________________________________________________*/
	static void
sAddFileToPool(
	PGPIORef					io,
	PGPRandomContext const *	rc)
{
	PGPError		err	= kPGPError_NoErr;
	PGPFileOffset	startPos;
	
	err	= PGPIOGetPos( io, &startPos );
	if ( IsntPGPError( err ) )
		err	= PGPIOSetPos( io, 0 );
	
	while ( IsntPGPError( err ) )
	{
		PGPByte			buffer[ 512 ];
		PGPSize			actualCount;
		
		err	= PGPIORead( io, sizeof( buffer ), buffer, &actualCount );
		if ( IsntPGPError( err ) || err == kPGPError_EOF )
		{
			pgpRandomAddBytes( rc, buffer, actualCount);
		}
		else
		{
			pgpAssertNoErr( err );
		}
	}
	
	(void)PGPIOSetPos( io, startPos );
}


	PGPError
pgpSaveGlobalRandomPool( )
{
	PGPError		err	= kPGPError_NoErr;
	PGPFileIORef	fileIO;

	if( IsNull( sRandSeedFile ) )
		return kPGPError_NoErr;

	err	= PGPOpenFileSpec( sRandSeedFile, kPFLFileOpenFlags_ReadWrite,
								&fileIO );

	if( err == kPGPError_FileNotFound )
	{
		pgpCreateFile( sRandSeedFile, kPGPFileTypeRandomSeed );
		err	= PGPOpenFileSpec( sRandSeedFile, kPFLFileOpenFlags_ReadWrite,
							   &fileIO );
	}

	if ( IsntPGPError( err ) )
	{
		PGPRandomContext randomContext;

		pgpInitGlobalRandomPoolContext( &randomContext );

		sAddFileToPool( (PGPIORef)fileIO, &randomContext );

		pgpRandSeedWrite( (PGPIORef)fileIO, &randomContext, NULL);
		PGPFreeIO( (PGPIORef)fileIO );
	}

	return( err );
}


	PGPError
pgpSetRandSeedFile_internal( PFLFileSpecRef randFile )
{
	PGPMemoryMgrRef mgr;
	PGPByte *randFileSpec;
	PGPSize randFileSpecSize;
	PGPError err;

	/* Ignore call if new file name is same as old one */
	if( IsntNull( sRandSeedFile ) )
	{
		PGPByte *oldfilespec, *newfilespec;
		PGPSize oldfilespecsize, newfilespecsize;
		PGPBoolean noChange;

		PFLExportFileSpec(sRandSeedFile, &oldfilespec, &oldfilespecsize);
		PFLExportFileSpec( randFile, &newfilespec, &newfilespecsize );
		noChange = oldfilespecsize == newfilespecsize &&
				   pgpMemoryEqual( oldfilespec, newfilespec, newfilespecsize );
		PGPFreeData( oldfilespec );
		PGPFreeData( newfilespec );
		if( noChange )
			return kPGPError_NoErr;
	}

	if( sIsSeeded  && IsntNull( sRandSeedFile ) )
	{
		pgpSaveGlobalRandomPool ();
	}

	if( IsntNull( sRandSeedFile ) )
	{
		PFLFreeFileSpec( sRandSeedFile );
		sRandSeedFile = NULL;
	}

	/* Copy incoming filespec, using default memory mgr */
	mgr = PGPGetDefaultMemoryMgr ();
	err = PFLExportFileSpec( randFile, &randFileSpec, &randFileSpecSize );
	if( IsPGPError( err ) )
		return err;
	err = PFLImportFileSpec( mgr, randFileSpec, randFileSpecSize,
							 &sRandSeedFile );
	PGPFreeData( randFileSpec );
	if( IsPGPError( err ) )
		return err;

	(void)sSeedGlobalRandomPool ();

	/* No error even if randseed file didn't previously exist */
	return kPGPError_NoErr;
}



/*
 * Call to set the name of the randseed file.  If one is open already we
 * will write out to it and then switch to the new one.
 */
	PGPError
PGPSetRandSeedFile( PFLFileSpecRef randFile )
{
	if( pgpRPCEnabled() )
	{
		return pgpSetRandSeedFile_back( randFile );
	}
	return pgpSetRandSeedFile_internal( randFile );
}

/* If we don't have a randseed file, set the default one */
	PGPError
pgpDefaultRandSeedFile( )
{
	PGPMemoryMgrRef		mgr;
	PFLFileSpecRef		defaultRef;
	PGPError			err = kPGPError_NoErr;

	if( IsNull (sRandSeedFile) )
	{
		mgr = PGPGetDefaultMemoryMgr();
		pgpAssert( IsntNull( mgr ) );
		err = GetDefaultRandSeedFileRef( mgr, &defaultRef );
		if( IsPGPError( err ) )
			return err;
		err = PGPSetRandSeedFile( defaultRef );
		PFLFreeFileSpec( defaultRef );
	}
	return err;
}

	void
pgpCleanupRandSeedFile ()
{
	if( IsntNull( sRandSeedFile ) )
		PFLFreeFileSpec( sRandSeedFile );
	sRandSeedFile = NULL;
	pgpCleanupGlobalRandomPool ();
	sIsSeeded = FALSE;
}


/*__Editor_settings____

	Local Variables:
	tab-width: 4
	End:
	vi: ts=4 sw=4
	vim: si
_____________________*/

⌨️ 快捷键说明

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