19

It seemed to me that the Bouncy Castle SecureRandom class for C#/.NET only uses DateTime.Now.Ticks as its seed by default.

I was wrong, but wouldn't that be unsafe to do?

Maarten Bodewes
  • 92,551
  • 13
  • 161
  • 313
  • 4
    I see lots of questions about Bouncy Castle, here and on other SE sites. Is it really that bad? Should I start warning people whenever I see someone using it? – otus Jul 18 '14 at 19:42
  • 2
    Could you point me to the source, where they do that? Maybe add it to the question? Edit: Actually, I think I get it... – otus Jul 18 '14 at 20:04
  • 5
    I am sorry - I just stepped through code for the nineteenth time, and I just discovered I was wrong. YES, it's bad to use time as seed to prng, NO that's not all bouncy castle does. In fact, BC SecureRandom has a static instance called Master, which is seeded from Ticks and ThreadedSeedGenerator. The "SetSeed" method is confusing because it only adds seed material from Ticks; does not reduce the strength of the already present seed. – Edward Ned Harvey Jul 18 '14 at 20:25
  • Yes, that matches what I read in the Java version. – otus Jul 18 '14 at 20:29
  • Uggh. This is off-topic now for the question about system time, but it turns out, ThreadedSeedGenerator returns poor quality random - In all my tests, 50% compressible output was pretty typical and I've seen the output compress as much as 10:1. Which means a lot of patterns. And it fails the NIST sts tests. So in fact, regardless of the Ticks question, bouncy castle securerandom is unsafe to use. You might consider http://tinhatrandom.org as an alternative. – Edward Ned Harvey Aug 04 '14 at 14:43
  • It uses only ThreadedSeedGenerator? The Java version also uses system entropy sources like /dev/random as an initial seed. Either way, the seed material doesn't necessarily have to pass statistical tests if enough is used. E.g. 512 bits of seed material with half a bit of entropy per bit would still give the PRNG 256 bits of entropy. – otus Aug 04 '14 at 16:13
  • Yes, bc-csharp only uses system time and ThreadedSeedGenerator. I'm no java expert, but how do you know what it uses in java? I don't see it in the java SecureRandom source code. – Edward Ned Harvey Aug 04 '14 at 21:13
  • 1
    That's only on J2ME where I don't think the system libraries have SecureRandom. Elsewhere it should use the system one, which should use OS entropy sources. – otus Aug 05 '14 at 07:20
  • I think your diagnosis is correct, since they derive from System.Random which has no entropy. Can't imagine why they wouldn't use RNGCryptoServiceProvider as the basis. – otus Aug 05 '14 at 07:27
  • I've submitted patches to bc-csharp, which should fix bouncy castle SecureRandom in 1.8 onward. However, in java, I don't see any SecureRandom other than the aforementioned j2me version, which extends java.util.Random, without any secure seed. @otus you said the java version uses system entropy sources. Can you provide any kind of links? – Edward Ned Harvey Aug 05 '14 at 16:18
  • 1
    AFAIU, when not on J2ME, it should use the SecureRandom class from the system libraries. It is technically implementation defined how that gets seeded, but usually something like this – i.e. reading /dev/[u]random for seed material. – otus Aug 05 '14 at 17:20

2 Answers2

25

Yes, it is unsafe to seed a PRNG with only with the system time. No, that's not all Bouncy Castle's SecureRandom does.

The SecureRandom default constructor calls SetSeed(GetSeed(8)); which calls Master.GenerateSeed(length); which calls SetSeed(DateTime.Now.Ticks); which is misleading because SetSeed only adds seed material to an already existing prng (the static instance called Master). If you look at the static declaration for private static SecureRandom Master you'll see that it actually seeds itself from a combination of Ticks and ThreadedSeedGenerator.

Why the system time is not enough

Using just the system time would be unsafe. The whole point of a crypto random generator is to be unguessable by an adversary, and by using the system time as a seed to the random number generator, you make it easy for an adversary to guess your seed and hence your random output.

DateTime.Now.Ticks has precision of 10 million ticks per second. Suppose an attacker knows what time you generated a key, +/- 1 second. They only need to make 20 million guesses ($2^{20}$ or so) in order to guess your random seed. This is likely crackable in a matter of seconds with a modern laptop.

Suppose an attacker has absolutely no idea what time you generated some key. They only know it was after – let's say – the year 2000. Since it's 2014 now, the entire space of 14 years occupies 51-52 bits. log2(10000000*60*60*24*365*14) ~= 51.97… This means the absolute highest level of entropy that you're likely to have in anything generated from system time is around 51 bits, which is small enough to be easily crackable, and realistically, you'll never even come close to that.

e-sushi
  • 17,891
  • 12
  • 83
  • 229
4

All Bouncy Castle's random generator classes seem to derive from java.security.SecureRandom, where seed doesn't mean "initialize state to this". It means "stir in any entropy from this".

That means what they do is not insecure, but shouldn't actually help either, since java.security.SecureRandom is already seeded with entropy from the system (e.g. /dev/urandom).

I'm assuming the same is true for the C# version, though I don't use C# so I'm not sure.

otus
  • 32,132
  • 5
  • 70
  • 165