From daw@cs.berkeley.edu Fri Apr 26 22:04:22 PDT 1996 Article: 416 of isaac.lists.coderpunks Path: news.isaac.cs.berkeley.edu!not-for-mail From: daw@cs.berkeley.edu (David Wagner) Newsgroups: isaac.lists.coderpunks Subject: Re: Distilled Wisdom for Cryptograph Random Sources Date: 8 Apr 1996 12:58:51 -0700 Organization: ISAAC Group, UC Berkeley Lines: 66 Sender: bin@abraham.cs.berkeley.edu Approved: mail2news@news.isaac.cs.berkeley.edu Distribution: isaac Message-ID: <4kblk7$he@joseph.cs.berkeley.edu> References: <199604070041.QAA28730@netcom9.netcom.com> NNTP-Posting-Host: abraham.cs.berkeley.edu Precedence: bulk In article <199604070041.QAA28730@netcom9.netcom.com>, Bill Frantz wrote: > MD5hash myRandPool; > > addEntropy(Time eventTime) { > MD5 md5 = new MD5(); > md5.update(myRandPool); > md5.update(eventTime); > myRandPool = md5.final(); > } > > RandData genRand() { > RandData temp; > MD5 md5 = new MD5(); > md5.update(myRandPool); > md5.update(currentTime); > temp = md5.final(); > MD5 md5 = new MD5(); > md5.update(temp); > md5.update(currentTime); > myRandPool = md5.final(); > return temp; > } If I understand this correctly, this is absolutely horrible. The state of the RandPool is updated as a known function of the previous PRNG output: so given one known PRNG output, I can recover all the following PRNG outputs. Eek! Here's my straw man proposal; I haven't analyzed it carefully, but it avoids a lot of the common potential weaknesses, I think. [Excuse my pseudo-Java: I don't know Java at all.] /* secret global variables */ /* it's crucial that these two have a fixed length */ byte myRandPool[16]; /* pool of entropy */ long counter; addEntropy(byte buf[]) { /* crunch in some more entropy */ MD5 md5 = new MD5(); md5.update("addEntropy() cruncher"); /* for slightly more robust security */ md5.update(myRandPool); md5.update(buf); myRandPool = md5.final(); /* really should have a conservative entropy estimator here */ } typedef byte randOutput[4]; /* don't call this until you're *sure* you've crunched in enough entropy */ randOutput genRand() { /* generate & output some PRNG bytes */ MD5 md5 = new MD5(); long x; /* we probably should refuse to generate output unless we've estimated that "enough" entropy has been crunched in, to be idiot-proof. */ md5.update("genRand() prng"); /* for slightly more robust security */ md5.update(myRandPool); atomic { x = ++counter; }; /* this line had better be atomic!!! */ md5.update(x); return first4bytes(md5.final()); /* for slightly more robust security */ } Note the md5.update() with a string describing the function's use of MD5: this essentially gives you two different independent hash functions, h() and h'(); using an independent hash for each logically different usage seems more robust to design failures, IMHO.