📄 pgprndseed.c
字号:
/*____________________________________________________________________________
Copyright (C) 1997 Network Associates Inc. and affiliated companies.
All rights reserved.
$Id: pgpRndSeed.c,v 1.44 1999/04/14 00:05:27 cpeterson Exp $
____________________________________________________________________________*/
#include "pgpConfig.h"
#include "pgpDebug.h"
#include "pgpMem.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 "pgpSDKPrefs.h"
#include "pgpFileRef.h"
/*
* 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, VoidAlign );
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, VoidAlign );
(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;
}
static PGPError
GetRandSeedFileRef(
PGPContextRef context,
PFLFileSpecRef * outRef)
{
PGPError err = kPGPError_NoErr;
PGPValidateParam( outRef );
*outRef = NULL;
PGPValidateContext( context );
if ( IsNull( pgpContextGetPrefs( context ) ) )
{
/* loading prefs has the side effect of copying into env */
err = PGPsdkLoadDefaultPrefs( context );
}
if ( IsntPGPError( err ) )
{
err = PGPsdkPrefGetFileSpec( context,
kPGPsdkPref_RandomSeedFile, (PGPFileSpecRef *)outRef );
}
return err;
}
static PGPError
sSeedRandomPool(
PGPContextRef context,
PGPRandomContext * randomContext)
{
PFLFileSpecRef randSeedRef = NULL;
PGPError err = kPGPError_NoErr;
(void)pgpInitGlobalRandomPool();
/* Read in the randseed file */
err = GetRandSeedFileRef( context, &randSeedRef);
if ( IsntPGPError( err ) )
{
PGPFileIORef fileIO = NULL;
err = PGPOpenFileSpec( randSeedRef, kPFLFileOpenFlags_ReadWrite,
&fileIO );
PFLFreeFileSpec(randSeedRef);
if ( IsntPGPError( err ) )
{
err = pgpRandSeedRead( (PGPIORef)fileIO, randomContext );
PGPFreeIO( (PGPIORef)fileIO );
fileIO = NULL;
}
}
return( err );
}
/* evil, but the random pool IS global */
static PGPBoolean sIsSeeded = FALSE;
PGPBoolean
pgpGlobalRandomPoolIsSeeded( void )
{
return( sIsSeeded );
}
void
pgpSetIsSeeded( void)
{
sIsSeeded = TRUE;
}
PGPError
pgpSeedGlobalRandomPool( PGPContextRef context )
{
PGPError err = kPGPError_NoErr;
PGPRandomContext * randomContext = NULL;
if ( sIsSeeded )
return( kPGPError_NoErr );
randomContext = pgpContextGetGlobalPoolRandomContext( context );
if ( IsntNull( randomContext ) )
{
err = sSeedRandomPool( context, randomContext );
}
/* be conservative, assume not seeded if error */
sIsSeeded = IsntPGPError( err );
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( PGPContextRef context )
{
PGPError err = kPGPError_NoErr;
PFLFileSpecRef randSeedRef = NULL;
PGPEnv *pgpEnv = NULL;
pgpEnv = pgpContextGetEnvironment( context );
err = GetRandSeedFileRef( context, &randSeedRef );
if ( IsntPGPError( err ) )
{
PGPFileIORef fileIO;
err = PGPOpenFileSpec( randSeedRef, kPFLFileOpenFlags_ReadWrite,
&fileIO );
if( err == kPGPError_FileNotFound )
{
pgpCreateFile( randSeedRef, kPGPFileTypeRandomSeed );
err = PGPOpenFileSpec( randSeedRef, kPFLFileOpenFlags_ReadWrite,
&fileIO );
}
PFLFreeFileSpec(randSeedRef);
if ( IsntPGPError( err ) )
{
PGPRandomContext * randomContext = NULL;
randomContext = pgpContextGetGlobalPoolRandomContext( context );
sAddFileToPool( (PGPIORef)fileIO, randomContext );
pgpRandSeedWrite( (PGPIORef)fileIO, randomContext, NULL);
PGPFreeIO( (PGPIORef)fileIO );
}
}
return( err );
}
/*__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 + -