This is randpool.c in view mode; [Download] [Up]
/* * True random number computation and storage * * (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. * The author assumes no liability for damages resulting from the use * of this software, even if the damage results from defects in this * software. No warranty is expressed or implied. * * Note that while most PGP source modules bear Philip Zimmermann's * copyright notice, many of them have been revised or entirely written * by contributors who frequently failed to put their names in their * code. Code that has been incorporated into PGP from other authors * was either originally published in the public domain or is used with * permission from the various authors. * * PGP is available for free to the public under certain restrictions. * See the PGP User's Guide (included in the release package) for * important information about licensing, patent restrictions on * certain algorithms, trademarks, copyrights, and export controls. * * Written by Colin Plumb. */ #include <stdlib.h> #include <string.h> #include "randpool.h" #include "usuals.h" #include "md5.h" /* The pool must be a multiple of the 16-byte (128-bit) MD5 block size */ #define RANDPOOLWORDS ((RANDPOOLBITS+127 & ~127) >> 5) #if RANDPOOLWORDS <= 16 /* #error is not portable, this has the same effect */ #include "Random pool too small - please increase RANDPOOLBITS in randpool.h" #endif /* Must be word-aligned, so make it words. Cast to bytes as needed. */ static word32 randPool[RANDPOOLWORDS]; /* Random pool */ static unsigned randPoolGetPos = sizeof(randPool); /* Position to get from */ static unsigned randPoolAddPos = 0; /* Position to add to */ static void xorbytes(byte *dest, byte const *src, unsigned len) { while (len--) *dest++ ^= *src++; } /* * Destroys already-used random numbers. Ensures no sensitive data * remains in memory that can be recovered later. This is also * called to "stir in" newly acquired environmental noise bits before * removing any random bytes. * * The transformation is carried out by "encrypting" the data in CFB * mode with MD5 as the block cipher. Then, to make certain the stirring * operation is strictly one-way, we destroy the key, getting 64 bytes * from the beginning of the pool and using them to reinitialize the * key. These bytes are not returned by randPoolGetBytes(). * * The stirring operation is done twice, to ensure that each bit in the * pool depends on each bit of entropy XORed in after each call to * randPoolStir(). * * To make this useful for pseudo-random (that is, repeatable) operations, * the MD5 transformation is always done with a consistent byte order. * MD5Transform itself works with 32-bit words, not bytes, so the pool, * usually an array of bytes, is transformed into an array of 32-bit words, * taking each group of 4 bytes in big-endian order. At the end of the * stirring, the transformation is reversed. */ void randPoolStir(void) { int i; byte *p; word32 t; word32 iv[4]; static word32 randPoolKey[16] = {0}; /* Convert to word32s for stirring operation */ p = (byte *)randPool; for (i = 0; i < RANDPOOLWORDS; i++) { t = (word32)((unsigned)p[3]<<8 | p[2]) << 16 | (unsigned)p[1]<<8 | p[0]; randPool[i] = t; p += 4; } /* Start IV from last block of randPool */ memcpy(iv, randPool+RANDPOOLWORDS-4, sizeof(iv)); /* First CFB pass */ for (i = 0; i < RANDPOOLWORDS; i += 4) { MD5Transform(iv, randPoolKey); iv[0] = randPool[i ] ^= iv[0]; iv[1] = randPool[i+1] ^= iv[1]; iv[2] = randPool[i+2] ^= iv[2]; iv[3] = randPool[i+3] ^= iv[3]; } /* Get new key */ memcpy(randPoolKey, randPool, sizeof(randPoolKey)); /* Second CFB pass */ for (i = 0; i < RANDPOOLWORDS; i += 4) { MD5Transform(iv, randPoolKey); iv[0] = randPool[i ] ^= iv[0]; iv[1] = randPool[i+1] ^= iv[1]; iv[2] = randPool[i+2] ^= iv[2]; iv[3] = randPool[i+3] ^= iv[3]; } /* Get new key */ memcpy(randPoolKey, randPool, sizeof(randPoolKey)); /* Wipe iv from memory */ memset(iv, 0, sizeof(iv)); /* Convert randPool back to bytes for further use */ p = (byte *)randPool; for (i = 0; i < RANDPOOLWORDS; i++) { t = randPool[i]; p[0] = t>>24; p[1] = t>>16; p[2] = t>>8; p[3] = t; p += 4; } /* Set up pointers for future addition or removal of random bytes */ randPoolAddPos = 0; randPoolGetPos = sizeof(randPoolKey); } /* * Make a deposit of information (entropy) into the pool. The bits * deposited need not have any particular distribution; the stirring * operation transformes them to uniformly-distributed bits. */ void randPoolAddBytes(byte const *buf, unsigned len) { unsigned t; while (len > (t = sizeof(randPool) - randPoolAddPos)) { xorbytes((byte *)randPool+randPoolAddPos, buf, t); buf += t; len -= t; randPoolStir(); } if (len) { xorbytes((byte *)randPool+randPoolAddPos, buf, len); randPoolAddPos += len; randPoolGetPos = sizeof(randPool); /* Force stir on get */ } } /* * Withdraw some bits from the pool. Regardless of the distribution of the * input bits, the bits returned are uniformly distributed, although they * cannot, of course, contain more Shannon entropy than the input bits. */ void randPoolGetBytes(byte *buf, unsigned len) { unsigned t; while (len > (t = sizeof(randPool) - randPoolGetPos)) { memcpy(buf, (byte *)randPool+randPoolGetPos, t); buf += t; len -= t; randPoolStir(); } if (len) { memcpy(buf, (byte *)randPool+randPoolGetPos, len); randPoolGetPos += len; } } byte randPoolGetByte(void) { if (randPoolGetPos == sizeof(randPool)) randPoolStir(); return (((byte *)randPool)[randPoolGetPos++]); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.