We looked at the RNG seed sources recently when we noticed that the RNG when
used as "new SecureRandom(new DigestRandomGenerator(new Sha256Digest()))"
will always produce the same sequence. Entropy within a stream is fine but
correlations ACROSS streams is a perfect 1.0 which is fatal performance for
a RNG. Of course, it's due to non-singleton + default seed + digest mode but
were surprised that the default behavior is to always use a seed of 0 rather
than a pseudo-random seed. IMHO, the default seeding behavior of BC's
SecureRandom is faulty and should be fixed. For testing/generating same
sequences, one can always explicitly set the seed to 0, so that argument
doesn't fly. Heck, even system clock ticks would be a one line fix and a big
step from current seed of zero.

 

Anyway, going a step ahead, since system ticks isn't that great, take a look
at https://gist.github.com/sidshetye/97631352f54a68184418 for mixing
together additional sources of entropy like

*         Current process memory numbers

*         Other processes running on the system

*         OS environment variables mixed in

 

The above is inspired from
http://upokecenter.dreamhosters.com/articles/2011/04/entropy-source-random-s
eed-generator-in-c/ which does NOT compile. That one spawns a background
thread to capture entropy on a rolling basis and also mixes entropy from
keyboard and mouse inputs - features not very suited for a library, so I
didn't add them to the GitHub Gist.

 

Ideally one should also be mixing in entropy from the processor's thermal
diode IF the underlying processor allows it. Intel has RDRAND
(https://software.intel.com/en-us/articles/intel-digital-random-number-gener
ator-drng-software-implementation-guide) and for calling assembly from C#
check
http://stackoverflow.com/questions/959087/is-it-possible-to-execute-an-x86-a
ssembly-sequence-from-within-c 

 

The RNG class interface could allow specifying what sources of entropy
should be pulled in for those wanting to stay only in the managed code
domain

 

Example: SecureRandom( ., bool managedCodeOnly) { . }

 

Cheers

Sid

 

From: Edward Ned Harvey (bouncycastle) [mailto:bouncycas...@nedharvey.com] 
Sent: Monday, July 28, 2014 11:55 PM
To: dev-crypto-csharp@bouncycastle.org
Subject: [dev-crypto-csharp] FYI - Low entropy in ThreadedSeedGenerator and
DateTime.Now.Ticks

 

Just FYI, I've been doing some statistical analysis on random numbers
generated from various entropy sources.  Here is a really simple test that
has produced some illuminating results:  Generate a bunch of random bytes.
Then split it all out, one bit at a time (so if there's a pattern, it will
be more easily recognizable).  Compress it and see how compressible it is.
(I'm using lzma from SharpCompress).

 

So I create a list of RNG's.  One of the RNG's is the zero RNG, which just
produces an endless stream of zero's.  This is in the list for the sake of
calibration and as a test control.  I create a byte array, say 64KB, and I
populate it with random bytes from the first RNG.  Split each bit out (now I
have an array of 512KB), and compress it.  Keep track of its compressed
size.  Repeat for each RNG in turn.

 

After repeating with a dozen or so RNG's, I use the maximum one as the
calibration point for assumed pure random, and I use the minimum one (the
all-zero RNG) as the calibration point for completely worthless non-random.
And then linearly scale each RNG result in between these two points, to
estimate the number of entropy bits per bit of output.

 

ThreadedSeedGenerator (with fast=false) is producing approx 0.7 bits of
entropy per bit.

 

ThreadedSeedGenerator (with fast=true) is producing approx 0.5 bits of
entropy per bit.

 

This is not a fatal flaw, as long as you're compensating for it - By
default, SecureRandom seeds itself with one sample of Ticks, and 24 bytes
(192 bits) of ThreadedSeedGenerator (with fast=true).  By my estimation,
this is approx 100-104 bits of entropy.  And each subsequent call to
SecureRandom adds another sample of Ticks seed material, which is approx 8
bits of entropy (at most).

 

I really think each call to SecureRandom should get another 256 bits from
ThreadedSeedGenerator (effectively adding another 128 bit seed), but that's
me.

 

Additionally, I measured the statistical randomness of each individual bit
of Ticks, when sampled thousands of times with a Sleep(1) in between each
sample.  All the least significant 8 bits were indistinguishable from
random.  The 9th and 10th bit started deviating measurably, and after that,
the deviation was very clear, but nonzero entropy until maybe the 29th bit
or so.  The total estimate of entropy in all the bits of a single sample of
Ticks was about 14 bits, but realistically, only 8 bits looked random, so I
wouldn't be comfortable trusting more than 2 or 4 bits of entropy from a
single sample of Ticks.

Reply via email to