Travis Cross d2edcad66e Merge Phil Zimmermann's libzrtp as a FreeSWITCH library
Thanks to Phil Zimmermann for the code and for the license exception
we needed to include it.

There remains some build system integration work to be done before
this code will build properly in the FreeSWITCH tree.
2012-03-31 23:42:27 +00:00

159 lines
4.6 KiB
C

/*
* Copyright (c) 1993, 1994 Colin Plumb. All rights reserved.
* For licensing and other legal details, see the file legal.c.
*
* True random number computation and storage
*
*/
#include "first.h"
#include <stdlib.h>
#include <string.h>
#include "md5.h"
#include "randpool.h"
#include "usuals.h"
/* This is a parameter of the MD5 algorithm */
#define RANDKEYWORDS 16
/* The pool must be a multiple of the 16-byte (128-bit) MD5 block size */
#define RANDPOOLWORDS (((RANDPOOLBITS+127) & ~127) >> 5)
#if RANDPOOLWORDS <= RANDKEYWORDS
#error 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 word32 randKey[RANDKEYWORDS]; /* Random pool */
static unsigned randKeyAddPos = 0; /* Position to add to */
static unsigned randPoolGetPos = 16; /* Position to get from */
/*
* 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 key for the stirring operation is the XOR of some bytes from the
* previous pool contents (not provably necessary, but it produces uniformly
* distributed keys, which "feels better") and the newly added raw noise,
* which will have a profound effect on every bit in the pool.
*
* 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;
word32 iv[4];
/* Convert to word32s for stirring operation */
byteSwap(randPool, RANDPOOLWORDS);
byteSwap(randKey, RANDKEYWORDS);
/* Start IV from last block of randPool */
memcpy(iv, randPool+RANDPOOLWORDS-4, sizeof(iv));
/* CFB pass */
for (i = 0; i < RANDPOOLWORDS; i += 4) {
MD5Transform(iv, randKey);
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];
}
/* Wipe iv from memory */
iv[3] = iv[2] = iv[1] = iv[0] = 0;
/* Convert randPool back to bytes for further use */
byteSwap(randPool, RANDPOOLWORDS);
/* Get new key */
memcpy(randKey, randPool, sizeof(randKey));
/* Set up pointers for future addition or removal of random bytes */
randKeyAddPos = 0;
randPoolGetPos = sizeof(randKey);
}
/*
* Make a deposit of information (entropy) into the pool. This is done by
* XORing them into the key which is used to encrypt the pool. Before any
* bytes are retrieved from the pool, the altered key will be used to encrypt
* the whole pool, causing all bits in the pool to depend on the new
* information.
*
* The bits deposited need not have any particular distribution; the stirring
* operation transforms them to uniformly-distributed bits.
*/
void
randPoolAddBytes(byte const *buf, unsigned len)
{
byte *p = (byte *)randKey + randKeyAddPos;
unsigned t = sizeof(randKey) - randKeyAddPos;
while (len > t) {
len -= t;
while (t--)
*p++ ^= *buf++;
randPoolStir(); /* sets randKeyAddPos to 0 */
p = (byte *)randKey;
t = sizeof(randKey);
}
if (len) {
randKeyAddPos += len;
do
*p++ ^= *buf++;
while (--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;
buf += len;
}
}
byte
randPoolGetByte(void)
{
if (randPoolGetPos == sizeof(randPool))
randPoolStir();
return ((byte *)randPool)[randPoolGetPos++];
}