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

302 lines
8.3 KiB
C

/*
* Copyright (c) 1993, 1994 Colin Plumb. All rights reserved.
* For licensing and other legal details, see the file legal.c.
*
* Cryptographic random number generation.
*/
#include "first.h"
#include <string.h>
#include "kb.h" /* For kbGet() other stuff */
#include "md5.h"
#include "noise.h"
#include "random.h"
#include "randpool.h"
#include "userio.h"
#include "kludge.h"
/*
* This code uses the randpool.c code to generate random numbers.
* That can be augmented with other techniques, such as the
* ANSI X9.17 generator, but the X9.17 generator uses a key-generating
* key which needs to be obtained from somewhere, and the location is
* not entirely clear. The randpool.c functions are entirely
* adequate; extra layers are for belt-and-suspenders security and
* compliance to standards.
*
* For generating long-lived secret keys, we go one more step:
* actually keep track of (an estimate of) the amount of entropy
* which is in the random number pool, and wait for events until
* the amount of entropy accumulated is enough to make all of the
* bits of the secret key truly random. Of course, the guarantees
* of cryptographic strength still apply even if this estimation
* is faulty.
*/
/* Get some random bytes */
void
randBytes(byte *buf, unsigned len)
{
randPoolGetBytes(buf, len);
}
/*
* A handy utility for generating uniformly distributed random numbers
* in a small range.
*/
unsigned
randRange(unsigned range)
{
unsigned div, r;
byte b[2];
if (range <= 1)
return 0;
if (range <= 256) {
div = 256/range;
do {
randBytes(b, 1);
r = b[0]/div;
} while (r >= range);
} else {
div = (unsigned)(65536/range);
do {
randBytes(b, 2);
r = ((unsigned)b[0] << 8 | b[1])/div;
} while (r >= range);
}
b[0] = b[1] = 0;
return r;
}
#ifdef UNIX /* Or we have popen() */
/*
* Execute the command "string", adding the entropy from the data thus
* gethered to the random number pool. Because the pool is rather
* slow and we want to encourage the use of lots of data, rather than
* adding the data directly, the MD5 is taken and that is added to the
* pool.
*/
int
randSourceSet(char const *string, unsigned len, int pri)
{
FILE *f;
struct MD5Context md5;
char buf[256];
int i;
(void)len; /* string is null-terminated */
(void)pri; /* Use every argument, regardless of priority */
f = popen(string, "r");
if (!f)
return -1;
MD5Init(&md5);
while ((i = fread(buf, 1, sizeof(buf), f)) > 0)
MD5Update(&md5, (unsigned char *)buf, i);
pclose(f);
MD5Final((unsigned char *)buf, &md5);
randPoolAddBytes((unsigned char *)buf, 16);
memset(buf, 0, sizeof(buf));
return 0;
}
#endif
/*
* True random bit handling
*/
/*
* Truly random bits are difficult to get and must be carefully hoarded.
* These functions use the randpool.c code to store the entropy, and provide
* some bookkeeping on the count of bits of true (Shannon) entropy available
* in the pool.
*
* For generating ordinary session keys, "as much entropy as you've got"
* is good enough, and no accounting is done, except to get some entropy
* to generate the random number seed file if necessary.
*
* But for generating long-lived secret key components, extraordinary
* measures are called for. In addition to what may have been available
* from the random seed file, random data from timed keystrokes is
* accumulated until enough is available.
*
* An estimate of the number of bits of true (Shannon) entropy in the pool
* is kept in trueRandBits. This is incremented when timed keystrokes
* are available, and decremented when bits are explicitly consumed for
* some purpose or another. This counter is maintained here, scaled by
* FRACBITS to count fractional bits for thoroughness. (Thus, the name
* "trueRandBits" is a bit misleading, since it actually counts sixteenths
* of a bit, but I can't think of a better one.)
*
* randFlush is the pool-stirring function. It is also called to
* obliterate traces of old random bits after prime generation is
* completed. (Primes are the most carefully-guarded values in PGP.)
*/
#define FRACBITS 4
#define DERATING 0x28 /* 2.5 bits subtracted for derating */
static word32 trueRandBits = 0; /* Bits of entropy in pool */
/*
* Ensure that the random numbers generated by prior calls to randBytes
* will never be recoverable from the contents of memory. This doesn't
* wipe memory to a fixed value (the entropy might come in handy for future
* operations), it just runs the generators forward enough that the previous
* state is irretrievable.
*
* This is called after prime generation, before the random data is saved
* out, so it is protecting prime data and is particularly paranoid.
*/
void
randFlush(void)
{
byte buf[16];
int i;
for (i = 0; i < 3; i++) /* Zipper + Belt + Suspenders */
randPoolStir(); /* Clean pseudo-random generator */
memset(buf, 0, sizeof(buf));
trueRandBits = 0;
}
/*
* Given an event (typically a keystroke) coded by "event" at a random time,
* add all randomness to the random pool, compute a (conservative) estimate
* of the amount, add it to the pool, and return the amount of randomness.
* (The return value is just for informational purposes.)
*
* Double events are okay, but three in a row is considered
* suspicious and the randomness is counted as 0.
*
* As an extra precaution against key repeat or other very regular input
* data, the entropy extimate is derived not from the time interval measured,
* but from the minimum of it and the (absolute) difference between it and
* the previous time interval, i.e. the second-order delta.
*/
unsigned
randEvent(int event)
{
static int event1 = 0, event2 = 0; /* Previous events */
static word32 prevdelta; /* Previous delta */
word32 delta; /* Time between last two events */
unsigned cbits; /* Entropy estimate, in bits. */
word32 t; /* Temprary value */
int i;
delta = noise();
randPoolAddBytes((byte *)&event, sizeof(event));
/*
* Don't credit triple events with any entropy on the grounds that
* they're probably something periodic like key repeat. But remember
* the delta.
*/
if (event == event1 && event == event2) {
prevdelta = delta;
return 0;
}
event2 = event1;
event1 = event;
/* Compute second-order delta */
t = (delta > prevdelta) ? delta - prevdelta : prevdelta - delta;
/* Remember current delta for next time */
prevdelta = delta;
/* Find minimum of delta and second-order delta */
if (delta > t)
delta = t;
/* Avoid divide-by-zero errors below */
if (!delta)
return 0;
/* Count the number of bits of entropy available - integer log2. */
cbits = 0;
i = 16;
t = 0xffffffff;
do {
t <<= i;
if (delta & t)
cbits += i;
else
delta <<= i;
} while (i >>= 1);
/*
* At this point, delta is normalized and has its high bit set.
* Now count fractional bits, using binary logarithm algorithm
*/
for (i = 0; i < FRACBITS; i++) {
cbits <<= 1;
delta >>= 16;
delta *= delta;
if (delta & 0x80000000)
cbits++;
else
delta <<= 1;
}
if (cbits <= DERATING)
return 0; /* nothing */
cbits -= DERATING;
trueRandBits += cbits;
if (trueRandBits > RANDPOOLBITS<<FRACBITS)
trueRandBits = RANDPOOLBITS<<FRACBITS;
return cbits;
}
/*
* Performs an accumulation of random bits. As long as there are
* fewer bits in the buffer than are needed, prompt for more.
* (kbGet is known to call randEvent() which increments trueRandBits.)
*/
void
randAccum(unsigned count)
{
word32 randbits = trueRandBits;
noise(); /* Establish a baseline for timing comparisons */
if (count > RANDPOOLBITS)
count = RANDPOOLBITS;
if (randbits>>FRACBITS >= count)
return;
userPrintf("\n\
We need to generate %u random bits. This is done by measuring the\n\
time intervals between your keystrokes. Please enter some random text\n\
on your keyboard until you hear the beep:\n", count - (randbits>>FRACBITS));
kbCbreak();
do {
/* display counter to show progress */
userPrintf(("\r%4u "), count-(unsigned)(randbits>>FRACBITS));
userFlush(); /* ensure screen update */
kbFlush(0); /* Typeahead is illegal */
(void)kbGet(); /* Wait for next char */
/* Print flag indicating acceptance (or not) */
userPutc(trueRandBits == randbits ? '?' : '.');
randbits = trueRandBits;
} while (randbits>>FRACBITS < count);
/* Do final display update */
userPuts(("\r 0 *"));
userPuts("\a -Enough, thank you.\n");
/* Do an extra-thorough flush to absorb extra typing. */
kbFlush(1);
kbNorm();
}