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

📄 pgprandomx9_17.c

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

	$Id: pgpRandomX9_17.c,v 1.14 2002/08/06 20:11:05 dallen Exp $
____________________________________________________________________________*/
/*
 * pgpRandomX9_17.c -- a general RNG interface
 *
 * Written by:	Colin Plumb and Derek Atkins <warlord@MIT.EDU>
 */
#include "pgpConfig.h"

#include "pgpMem.h"
#include "pgpContext.h"
#include "pgpCFBPriv.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpRandomPoolPriv.h"
#include "pgpRandomX9_17.h"
#include "pgpFIPSPriv.h"
#include "pgpKeyPriv.h"



/**************************** X9.17 RNG ********************************/

typedef struct X9_17Context
{
	PGPCFBContext *cfb;
	PGPRandomContext const *base_rc;
} X9_17Context;

static void
randomX9_17AddBytes(void *priv, PGPByte const *buf, unsigned len)
{
	X9_17Context *ctx = (X9_17Context *)priv;
	PGPCFBRandomWash(ctx->cfb, buf, len);
}

static void
randomX9_17GetBytesEntropy(
	void *priv,
	PGPByte *buf,
	unsigned len,
	unsigned bits)
{
	X9_17Context *ctx = (X9_17Context *)priv;
	PGPByte salt[ PGP_CFB_MAXBLOCKSIZE ];
	PGPUInt32	blocksize;
	PGPSize t;

	blocksize	= pgpCFBGetBlockSize( ctx->cfb );

	/* Charge the entropy to the base RNG */
	pgpRandomGetBytesEntropy(ctx->base_rc, buf, 0, bits);

	(void)PGPCFBGetRandom(ctx->cfb, len, buf, &t);
	len -= t;
	buf += t;

	while (len) {
		pgpRandomGetBytesEntropy(ctx->base_rc, salt, blocksize, 0);

		if( pgpFIPSModeEnabled() )
		{
			PGPByte 						inbuf[PGP_CFB_MAXBLOCKSIZE];
			PGPByte 						outbuf[PGP_CFB_MAXBLOCKSIZE];
			PGPUInt32						timeOfDay;
			PGPSymmetricCipherContextRef 	sref;
			PGPUInt32						index;
			
			pgpClearMemory( inbuf, sizeof( inbuf ) );
			pgpClearMemory( outbuf, sizeof( outbuf ) );
			
			/* for FIPS, use a date/time approach to increase the entropy */
			/* encrypt the date/time */
			
			timeOfDay = PGPGetTime();
			pgpCopyMemory( &timeOfDay, inbuf, sizeof( timeOfDay ) );
			
			/* now encrypt the date/time information into outbuf */
			PGPCFBGetSymmetricCipher( ctx->cfb, &sref );
			PGPSymmetricCipherEncrypt( sref, inbuf, outbuf );
			
			/* XOR outbuf into the salt */
			
			for( index = 0; index < blocksize; index++ )
			{
				salt[index] ^= outbuf[index];
			}
		}

		PGPCFBRandomCycle(ctx->cfb, salt);
		(void)PGPCFBGetRandom(ctx->cfb, len, buf, &t);
		len -= t;
		buf += t;
	}
}

static void
randomX9_17Stir(void *priv)
{
	X9_17Context *ctx = (X9_17Context *)priv;
	PGPCFBRandomWash(ctx->cfb, (PGPByte const *)"", 0);
	pgpRandomStir(ctx->base_rc);
}

static void
randomX9_17Destroy (PGPRandomContext *rc)
{
	X9_17Context *				ctx = (X9_17Context *)rc->priv;
	PGPCFBContextRef	cfbp = ctx->cfb;
	PGPContextRef				cdkContext;

	pgpAssertAddrValid( rc, PGPRandomContext );
	cdkContext	= rc->context;

	pgpCFBWipe( cfbp );
	PGPFreeCFBContext( cfbp );

	pgpClearMemory( ctx, sizeof(*ctx) );
	pgpContextMemFree( cdkContext, ctx );

	pgpClearMemory( rc, sizeof(*rc) );
	pgpContextMemFree( cdkContext, rc );
}


PGPRandomVTBL X9_17Desc = {
	"X9.17-based cryptographic PRNG",
	randomX9_17AddBytes, randomX9_17GetBytesEntropy,
	randomX9_17Stir
};


	PGPRandomContext *
pgpRandomCreateX9_17(
	PGPContextRef				context,
	PGPCipherAlgorithm			algorithm,
	PGPRandomContext const *	base)
{
	PGPRandomContext *			rc;
	PGPCFBContextRef	cfb;
	X9_17Context *				ctx;
	PGPByte 					buf[32];
	PGPMemoryMgrRef				memoryMgr	= PGPPeekContextMemoryMgr( context );

	pgpAssert( context );
	pgpAssert( base );

	cfb = pgpCFBCreate( memoryMgr, pgpCipherGetVTBL( algorithm ) );
	if (!cfb)
		return 0;
	rc = (PGPRandomContext *)pgpContextMemAlloc( context, sizeof(*rc),
												kPGPMemoryMgrFlags_Clear );
	if (!rc) {
		PGPFreeCFBContext( cfb );
		return 0;
	}

	ctx = (X9_17Context *)pgpContextMemAlloc( context, sizeof(*ctx),
											 kPGPMemoryMgrFlags_Clear );
	if (!ctx) {
		PGPFreeCFBContext( cfb );
		pgpContextMemFree( context, rc );
		return 0;
	}

	/* Get a reasonable initial state */
	pgpRandomGetBytesEntropy( base, buf, sizeof(buf), 0 );
	PGPCFBRandomWash( cfb, buf, sizeof(buf) );
	pgpClearMemory( buf, sizeof(buf) );

	rc->vtbl = &X9_17Desc;
	rc->priv = ctx;
	rc->context	= context;
	rc->destroy = randomX9_17Destroy;
	ctx->cfb = cfb;
	ctx->base_rc = base;

	return rc;
}

/* The default: X9.17, with CAST5, based on the pgpRandomPool. */
	static PGPRandomContext *
pgpRandomCreate_internal(PGPContextRef context)
{
	PGPRandomContext * randomContext;
	PGPCipherAlgorithm	cipherAlg;
	
	randomContext	= pgpContextGetGlobalPoolRandomContext( context );
	pgpAssert( randomContext );

	if( pgpFIPSModeEnabled() )
	{
		cipherAlg = kPGPCipherAlgorithm_3DES;
	}
	else
	{
		cipherAlg = kPGPCipherAlgorithm_CAST5;
	}
	
	return pgpRandomCreateX9_17( context, cipherAlg, randomContext );
}



/******************** Front End RNG ********************************/

typedef struct rngFront {
	PGPContextRef		context;
	PGPByte *			allocBuf;		/* Buffer holding reserved bits */
	PGPSize				allocBufSize;	/* Size of allocBuf */
} rngFront;

/* This just passes requests through to the back end */

static void
randomFrontAddBytes(void *priv, PGPByte const *buf, unsigned len)
{
	rngFront *rf = (rngFront *) priv;
	(void)pgpRandomAddBytes_back( rf->context, buf, len );
}

static void
randomFrontGetBytesEntropy(
	void *priv,
	PGPByte *buf,
	unsigned len,
	unsigned bits)
{
	PGPByte *randBuf;
	PGPSize randBufLen;
	rngFront *rf = (rngFront *) priv;

	/* Satisfy request from local buffer if counting entropy */
	if( rf->allocBufSize > 0  &&  bits > 0 )
	{
		PGPSize cnt = pgpMin( (bits+7)/8, len );
		pgpAssert( (bits+7)/8 <= len );	// we handle even if this is false

		cnt = pgpMin( cnt, rf->allocBufSize );
		pgpCopyMemory( rf->allocBuf, buf, cnt );
		len -= cnt;
		if( bits > 8*cnt )
			bits -= 8*cnt;
		else
			bits = 0;
		buf += cnt;

		if( rf->allocBufSize == cnt )
		{
			pgpClearMemory( rf->allocBuf, rf->allocBufSize );
			pgpContextMemFree( rf->context, rf->allocBuf );
			rf->allocBuf = NULL;
			rf->allocBufSize = 0;
		} else {
			void *vbuf = rf->allocBuf;
			PGPSize i;
			/* Copy data back to beginning of buffer (overlapping copy) */
			for( i=cnt; i<rf->allocBufSize; ++i )
				rf->allocBuf[i-cnt] = rf->allocBuf[i];
			pgpClearMemory( rf->allocBuf+rf->allocBufSize-cnt, cnt );
			/* Shrink buffer to new size */
			(void)pgpContextMemRealloc( rf->context, &vbuf,
										rf->allocBufSize-cnt, 0 );
			rf->allocBuf = vbuf;
			rf->allocBufSize -= cnt;
		}

		if( len == 0 )
			return;
	}

	(void)pgpRandomGetBytesEntropy_back( rf->context, len, bits,
										 &randBuf, &randBufLen );
	pgpAssert( IsntNull( randBuf ) );
	pgpCopyMemory( randBuf, buf, randBufLen );
	pgpClearMemory( randBuf, randBufLen );
	PGPFreeData( randBuf );
}

/* Reserve bytes so that we have at least minsize */
static PGPUInt32
randomFrontReserve( void *priv, PGPUInt32 minsize )
{
	rngFront *rf = (rngFront *) priv;
	PGPByte *randBuf;
	PGPSize randBufLen;
	PGPByte *fillptr;
	PGPUInt32 avail;
	PGPUInt32 request;

	if( minsize <= rf->allocBufSize )
		return rf->allocBufSize;

	/* Calculate how much is being requested to add */
	request = minsize - rf->allocBufSize;
	avail = PGPGlobalRandomPoolGetEntropy();
	request = pgpMin( request, avail );
	(void)pgpRandomGetBytesEntropy_back( rf->context, request, request*8,
										 &randBuf, &randBufLen );
	if( IsNull( randBuf ) )
		return rf->allocBufSize;

	if( IsntNull( rf->allocBuf ) )
	{
		void *vbuf = rf->allocBuf;
		PGPError err = pgpContextMemRealloc( rf->context, &vbuf,
									rf->allocBufSize+randBufLen, 0 );
		if( IsPGPError( err ) )
		{
			PGPFreeData( randBuf );
			return rf->allocBufSize;
		}
		rf->allocBuf = vbuf;
		fillptr = rf->allocBuf + rf->allocBufSize;
	} else {
		rf->allocBuf = PGPNewSecureData( PGPPeekContextMemoryMgr(rf->context),
										 randBufLen, 0 );
		if( IsNull( rf->allocBuf ) )
		{
			PGPFreeData( randBuf );
			return 0;
		}
		fillptr = rf->allocBuf;
	}

	pgpCopyMemory( randBuf, fillptr, randBufLen );
	pgpClearMemory( randBuf, randBufLen );
	PGPFreeData( randBuf );

	rf->allocBufSize += randBufLen;
	return rf->allocBufSize;
}


static void
randomFrontStir(void *priv)
{
	rngFront *rf = (rngFront *) priv;
	(void)pgpRandomStir_back( rf->context );
}

static void
randomFrontDestroy (PGPRandomContext *rc)
{
	PGPContextRef				cdkContext;
	rngFront *					rf;

	pgpAssertAddrValid( rc, PGPRandomContext );
	cdkContext	= rc->context;
	rf = (rngFront *)rc->priv;
	pgpClearMemory( rc, sizeof(*rc) );
	pgpContextMemFree( cdkContext, rc );

	if( IsntNull( rf->allocBuf ) )
	{
		pgpClearMemory( rf->allocBuf, rf->allocBufSize );
		pgpContextMemFree( cdkContext, rf->allocBuf );
	}
	pgpClearMemory( rf, sizeof(*rf) );
	pgpContextMemFree( cdkContext, rf );
}


PGPRandomVTBL frontDesc = {
	"frontend to cryptographic PRNG",
	randomFrontAddBytes, randomFrontGetBytesEntropy,
	randomFrontStir
};

	PGPRandomContext *
pgpRandomCreate_frontend(
	PGPContextRef				context )
{
	PGPRandomContext *			rc;
	rngFront *					rf;

	pgpAssert( context );

	rc = (PGPRandomContext *)pgpContextMemAlloc( context, sizeof(*rc),
												kPGPMemoryMgrFlags_Clear );
	if (!rc) {
		return 0;
	}

	rf = (rngFront *)pgpContextMemAlloc( context, sizeof(*rf),
												kPGPMemoryMgrFlags_Clear );
	if (!rf) {
		pgpContextMemFree( context, rc );
		return 0;
	}

	rf->context = context;

	rc->vtbl = &frontDesc;
	rc->priv = (void *)rf;
	rc->context	= context;
	rc->destroy = randomFrontDestroy;

	return rc;
}





/********************** Pseudo-Random RNG *************************/



/*
 * Pseudo-random number generator based on the dummy pool (which
 * always produces zeros).  This is useful for public data where we
 * just want uniqueness but don't need cryptographic strength, and where
 * we don't want to draw down the randomness in the true random pool.
 * An example would be generating the public prime in DSA key.
 * Use pgpRandomAddBytes to seed it.
 *
 * Note that you need to seed this with some really random data
 * (using pgpRandomAddBytes) or it will generate the same data every time.
 *
 * DO NOT USE THIS unless you know what you're doing.
 */
	PGPRandomContext *
pgpPseudoRandomCreate(PGPContextRef context)
{
	PGPRandomContext * 	randomContext;
	PGPCipherAlgorithm	cipherAlg;
	
	pgpAssert( context );

	randomContext	= pgpContextGetDummyRandomContext( context );
	pgpAssert( randomContext );

	if( pgpFIPSModeEnabled() )
	{
		cipherAlg = kPGPCipherAlgorithm_3DES;
	}
	else
	{
		cipherAlg = kPGPCipherAlgorithm_CAST5;
	}
	
	return pgpRandomCreateX9_17( context, cipherAlg, randomContext );
}



/******************************* Utilities ******************************/


PGPUInt32
pgpRandomReserveBytes( PGPRandomContext *rc, PGPUInt32 minsize )
{
	/* If no front end, use entropy in pool as only we can access it */
	if( rc->vtbl == &frontDesc )
		return randomFrontReserve( rc->priv, minsize );
	else
		return PGPGlobalRandomPoolGetEntropy() / 8;
}



/*
 * The simple get-byte function... entropy charged is the number of
 * bits read out.
 */
void
pgpRandomGetBytes(
	PGPRandomContext const *rc,
	void *					buf,
	PGPSize					len)
{
	pgpRandomGetBytesEntropy(rc, (PGPByte *) buf, len, 8*len);
}

/*
 * Generate a uniformly distributed random number from 0..range-1.
 * range is limited to 65536.
 *
 * This is very careful to avoid all bias in its selection, without
 * using too many input bytes.  For a range of 256 or less, it uses
 * one byte if possible, and an average of less then two, even for
 * the worst-case range=129.
 */
	PGPUInt32
pgpRandomRange(
	PGPRandomContext const *	rc,
	PGPUInt32					range,
	PGPUInt32					entropyBits)
{
    PGPUInt32		d,
					r;
	PGPByte			b[2];

	/* Count entropy bits */
	pgpRandomGetBytesEntropy(rc, b, 1, entropyBits);

    if (range <= 1)
        return 0;

	if (range <= 256) {
		d = 256/range;
		do {
			pgpRandomGetBytesEntropy(rc, b, 1, 0);
			r = b[0]/d;
		} while (r >= range);
	} else {
		d = (unsigned)(65536/range);
		do {
			pgpRandomGetBytesEntropy(rc, b, 2, 0);
			r = ((unsigned)b[0] << 8 | b[1])/d;
		} while (r >= range);
		b[1] = 0;
	}
	b[0] = 0;
	return r;
}

	PGPRandomContext *
pgpRandomCreate(PGPContextRef context)
{
	pgpAssert( context );

	if( !pgpRPCEnabled() )
	{
		return pgpRandomCreate_internal( context );
	}

	/* Else create a randomcontext which relies on the back end */

	return pgpRandomCreate_frontend( context );
}




/*__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 + -