Thanks Ed, but I don't think you can't call it incorrect usage since it is the proper public interface to begin with. Also, the default used in SecureRandom() uses SHA1 internally - something we're not allowed to use anymore. So what ends up happening is something like this:
Code (don't use this in production!) static void Main(string[] args) { var key1 = new byte[32]; var rng1 = new SecureRandom(new DigestRandomGenerator(new Sha256Digest())); rng1.NextBytes(key1); var key2 = new byte[32]; var rng2 = new SecureRandom(new DigestRandomGenerator(new Sha256Digest())); rng2.NextBytes(key2); Console.WriteLine("key1: {0}", BitConverter.ToString(key1).Replace("-","")); Console.WriteLine("key2: {0}", BitConverter.ToString(key2).Replace("-", "")); Console.WriteLine("Crypto keys are {0}", Arrays.ConstantTimeAreEqual(key1,key2) ? "IDENTICAL": "different"); Console.ReadLine(); } Output: key1: 43DA581B578449E4AD3C0AB7FF917B90765CAEEE883481DC82A746EF80625E75 key2: 43DA581B578449E4AD3C0AB7FF917B90765CAEEE883481DC82A746EF80625E75 Crypto keys are IDENTICAL Yes, there are techniques to fix that behavior like singletons, timer tick seeds, your ThreadedSeedGenerator() suggestion etc - but they are fixing an issue that shouldn't be there in the first place. Talking of ThreadedSeedGenerator() (and with no disrespect to anyone here!), isn't it just a counter inside a constant time-periodic timer? In fact seems that the first few bytes can predict inter-byte generation timings, which can then be used to somewhat predict subsequent bytes. That seems significantly weaker than even GitHub Gist patch floated in my prev mail - unless I'm missing something? Looking at stronger entropy sources, here is someone else's GitHub project I modified (https://github.com/sidshetye/RdRand) to get it working to get random numbers right from hardware (RDRAND which sources from diode thermal noise for a True-RNG seed). Best to blend 3-4 entropy sources than rely on just one but that probably is a deeper discussion topic than this (and unfortunately after today's RdRand experiment, I'm out of tinkering time this month!) Finally, you're right about the SetSeed(). But that doesn't help the fact that the RNGs can still produce identical sequences and that the seed isn't very strong. Regards Sid From: Edward Ned Harvey (bouncycastle) [mailto:bouncycas...@nedharvey.com] Sent: Tuesday, July 29, 2014 2:10 PM To: Sid Shetye; dev-crypto-csharp@bouncycastle.org Subject: RE: [dev-crypto-csharp] FYI - Low entropy in ThreadedSeedGenerator and DateTime.Now.Ticks > From: Sid Shetye [mailto:sid...@outlook.com] > > "new SecureRandom(new DigestRandomGenerator(new > Sha256Digest()))" will always produce the same sequence. You're using it wrong. Here, try this: This seeds itself with 1 sample of ticks (approx 8 bits entropy) and 24 bytes ThreadedSeedGenerator (at approx 0.5 bits entropy per bit, this is approx 96 bits entropy) = approx 104 bits total entropy new SecureRandom(); Or, to do something stronger, try this: (This should get you near actual 256 bits entropy in the prng) byte[] seed; // approx 0.5 bits entropy per bit, this is approx 256 bits entropy seed = new ThreadedSeedGenerator().GenerateSeed(64,fast:false); var prng = new DigestRandomGenerator(new Sha256Digest()); prng.AddSeedMaterial(seed); var myRand = new SecureRandom(prng); > For > testing/generating same sequences, one can always explicitly set the seed to > 0, Actually, that's not true. Because once you AddSeedMaterial, you can never get it back out. DigestRandomGenerator.SetSeed() does not actually set seed, but rather, *adds* seed material without losing prior seed material. > 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 We are doing this in TinHat Random. For more details, see "Advanced Usage" https://tinhatrandom.org/doku.php#advanced_usage