The default constructor of SecureRandom uses GetSeed(8), which is only 64 bits, 
but worse yet, GetSeed seeds itself from the system clock Ticks.

There are 10million ticks per second, and a single laptop CPU core can perform 
between 10million and 200million AES operations per second, depending on 
hardware acceleration, clock speed, and how efficient the software library is.  
This means, suppose you used SecureRandom() to generate an AES key, a 
completely unsophisticated brute force attacker could guess your key in a 
period of time that's less than the precision he has on guessing *when* you 
created your key.  If he knows when you generated it +/- 12 hours, then he 
would expect to require something between 0.5 and 12 hours to guess your key, 
divided by the number of CPU cores he has available.

Even if an attacker had no idea when you generated some key, it's still limited 
to 64 bits, which is just nowhere near good enough.

Even if you're aware of this, and you painstakingly and consistently use things 
like ThreadedSeedGenerator to seed the SecureRandom, there are tons of places 
where SecureRandom() is used *internally* by Bouncy Castle.  By searching code, 
I see 526 references.  I discovered this today, because I painstakingly created 
strong random to seed my ECKeyPairGenerator, and then signed & verified data, 
only to discover that the insecure SecureRandom() is used internally by 
ECDSASigner.

So the questions I have are ...  What to do about it.

Option 1:  More education to the users.
Response:  I see code examples all over the internet, where people advise each 
other to use SecureRandom and expect it to be secure, as the name implies.  So 
the idea of just educating people on proper usage and expectations is 
unrealistic.  The name "SecureRandom" in a widely trusted crypto library such 
as Bouncy Castle is important and meaningful.

More importantly, SecureRandom() is used *internally* by Bouncy Castle.  Which 
underscores the futility of "user education" as the solution.  As described 
above, I painstakingly ensured I used good random, only to find it undermined 
internally by ECDSASigner.

Option 2:  Instead of seeding SecureRandom from system time, seed it from 
ThreadedSeedGenerator, or better yet, a combination of the two, or better yet, 
pull from both of those sources plus the OS crypto API and everything else 
available to provide seed material.

In fact, that's what we're doing in TinHat Random.  http://tinhatrandom.org
If the solution is to seed SecureRandom from a bunch of different sources, then 
I would like to see TinHat Random folded into the source of Bouncy Castle.  
Which might be easier said than done, given the Java / C# duality.

Also, there might be some logistical difficulties, compatibility with different 
system types, different OSes with different threading models, etc.  I would be 
brazen to assume there always exists an OS crypto API on every platform where 
BC gets used.  Not to mention, the assumption that ThreadedSeedGenerator is 
valid to use.  Which is another big assumption.

Option 3:  I am rather expecting to hear a lot of "can't" in response to Option 
2.  But I am working for an employer who is planning to use BC for secure 
communications, and I cannot afford to deliver "can't" as my answer.  So I am 
estimating probably my response will be forced, to fork BC, and fold TinHat 
Random into it, to make it suitable for my employer's purposes.  And I'll have 
to go around promoting my fork to application developers, etc.  But I'm hoping 
for a more graceful integration process somehow that doesn't result in 
fragmentation of community or development efforts.

Other options?  Ideas?  Comments?

Thanks...  PS, I love BC and as always, thanks to everyone who contributed and 
contributes to it.

Reply via email to