📄 pgprndseed.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 + -