> From: Mat Robichaud [mailto:[email protected]] > > connection--we are anticipating 10,000+. Should I share one SecureRandom > object for all handlers for use in the TlsServerProcotol class, or should I > create > a new SecureRandom for each handler?
Looking at the code now, I see: crypto\src\security\SecureRandom.cs lines 35 to 42 The SecureRandom PORTABLE static ctor seeds itself with the clock ticks (at most 8 or 14 bits entropy, realistically probably 4 bits), and 32 bytes from ThreadedSeedGenerator. There is a comment there, referencing the bug reported Aug 2014 http://www.bouncycastle.org/csharpdevmailarchive/msg00814.html about ThreadedSeedGenerator returning low entropy. The assumption seems to be that seeding with 16 bytes is probably sufficient, and if ThreadedSeedGenerator generates 32 bytes, it hopefully has 16 bytes entropy. My personal feeling is that you should aim for seeding with 32 bytes, and assume 10% or 5% quality of entropy returned by ThreadedSeedGenerator. So I would seed with 320 to 640 bytes from ThreadedSeedGenerator. Also, the measurements that show ThreadedSeedGenerator to provide poor entropy were based on my Macbook Pro, and Windows VM. I don't know how/where to build/run/test the PORTABLE library. Ideally you'd want to measure the randomness of ThreadedSeedGenerator on the target platform where you intend to run it, because the nature of TSG is highly platform dependent. When you run TSG for 32 bytes on your system, for all we know, you might be getting anywhere between 0 and 256 bits of entropy. To answer your question about instantiating just one, or more than one: If you use the default ctor, it won't make any difference. It's just a wrapper around a static instance. This also has the unfortunate disadvantage of never reseeding. The PRNG itself is based on an iterative hash function. While there are no obvious weaknesses of this, all hash functions (and block ciphers) exhibit some bias over large sets of data. Some countermeasures are already in place (one hash-based PRNG feeds another hash-based PRNG, which reseeds every so often from the first) but it's probably still advisable to reseed occasionally. Ideally you'd have a deep understanding of all the statistics and use a calculation to determine how often to reseed, but realistically, almost nobody has that level of depth, and it's all estimations anyway. So as a reasonable way of coming up with some estimate of how often to reseed, take for example Fortuna, which reseeds every 1MB, and is based on a block cipher that needs reseeding much more frequently (some orders of magnitude). In reality, even if you never reseed, you'll probably never encounter a problem, because as I said, countermeasures are already in place. So if you're uber-paranoid, you would construct your own SecureRandom, and you'll have a separate one for each connection, each seeded with a new unique seed that you generated yourself, and you'll reseed periodically (which implies you'll need to keep a reference to "prng"), as follows. var digest = new Org.BouncyCastle.Crypto.Digests.Sha256Digest(); var prng = new Org.BouncyCastle.Crypto.Prng.DigestRandomGenerator(digest); byte[] newSeed; newSeed = BitConverter.GetBytes(DateTime.Now.Ticks); // At most 8 to 14 bits, realistically maybe 4 prng.AddSeedMaterial(newSeed); Array.Clear(newSeed, 0, newSeed.Length); var tsg = new Org.BouncyCastle.Crypto.Prng.ThreadedSeedGenerator(); newSeed = tsg.GenerateSeed(640, fast: false); // Assuming 5% entropy, this is 20x 32 bytes prng.AddSeedMaterial(newSeed); Array.Clear(newSeed,0,newSeed.Length); // Similarly, add entropy from any additional sources available. // If you feel like it, take a look at https://tinhatrandom.org // In particular, the WindowsFormsMouse and WinFormsKeyboardInputPrompt // And see List of Random Number Servers (http://en.wikipedia.org/wiki/List_of_random_number_generators#Random_Number_Servers) var foo = new Org.BouncyCastle.Security.SecureRandom(prng); > What I am observing is > in the ThreadedSeedGenerator class, the DoGenerateSeed function is stuck > in what appears to be an infinite loop as the Run method is never hit to > increase the counter. That is indeed, bad news. I'm going to write a separate reply to it.
