views:

1455

answers:

10

Why would anybody use the "standard" random number generator from System.Random at all instead of always using the cryptographically secure random number generator from System.Security.Cryptography.RandomNumberGenerator (or its subclasses because RandomNumberGenerator is abstract)?

Nate Lawson tells us in his Google Tech Talk presentation "Crypto Strikes Back" at minute 13:11 not to use the "standard" random number generators from Python, Java and C# and to instead use the cryptographically secure version.

I know the difference between the two versions of random number generators (see question 101337).

But what rationale is there to not always use the secure random number generator? Why use System.Random at all? Performance perhaps?

+7  A: 

System.Random is much more performant since it does not generate cryptographically secure random numbers.

A simple test on my machine filling a buffer of 4 bytes with random data 1,000,000 times takes 49 ms for Random, but 2845 ms for RNGCryptoServiceProvider. Note that if you increase the size of the buffer you are filling, the difference narrows as the overhead for RNGCryptoServiceProvider is less relevant.

Michael
Thank you for demonstrating it with an actual test.
Lernkurve
+1  A: 

Generating test data, when psuedo-random is 'good enough', etc

Marc
+33  A: 

Speed and also intent. If you are generating a random # and have no need for security why use a crypto function? You don't need security so why make a coder think that there may be some secure reason for it when there isn't...

klabranche
I very much like the intent argument.
Lernkurve
+1 Ditto.~~~~~~~~~~~~~~~~~~~~
Spencer Ruport
it all about entropy generation and speed
Sergey Mirvoda
+23  A: 

Apart from the speed and the more useful interface (NextDouble() etc) it is also possible to make a repeatable ramdom sequence by using a fixed seed value. That is quite useful, amongst others during Testing.

Random gen1 = new Random();     // auto seeded by the clock
Random gen2 = new Random(0);    // Next(10) always yields 7,8,7,5,2,....

An additional thought, to get a random int, you would need:

var g = System.Security.Cryptography.RandomNumberGenerator.Create();
var b = new byte[4];
g.GetBytes(b);
int value = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];  // msb/lsb not relevant

Which you could of course wrap in a method, but still.

Henk Holterman
Great hint about testing.
Lernkurve
And there's the BitConverter.ToInt32(Byte[] value, int startIndex) which may be easier to understand. ;)
Simon Svensson
Ian Bell and David Braben used a random generator in the computer game Elite to create a vast list of planets and their attributes (size, etc), with very limited memory.This also relies on the generator creating a deterministic pattern (from a seed) - which the Crypto one obviously doesn't provide (by design.)There's some more information on how they did it here:http://wiki.alioth.net/index.php/Random_number_generatorand the book "Infinite Game Universe: Mathematical Techniques" ISBN:1584500581 has a more general discussion on such techniques.
Daniel James Bryars
+1  A: 

If I don't need the security, i.e., I just want a relatively indeterminate value not one that's cryptographically strong, Random has a much easier interface to use.

tvanfosson
+2  A: 

Not everyone needs cryptographically secure random numbers, and they might benefit more from a speedier plain prng. Perhaps more importantly is that you can control the sequence for System.Random numbers.

In a simulation utilizing random numbers you might want to recreate, you rerun the simulation with the same seed. It can be handy for tracking bugs when you want to regenerate a given faulty scenario as well - running your program with the exact same sequence of random numbers that crashed the program.

nos
+3  A: 

If you're programming an online card game or lotter then you would want to make sure the sequence is next to impossible to guess. However, if you are showing users, say, a quote of the day the performance is more important than security.

Dan Diplo
+6  A: 

The most obvious reasons have already been mentioned, so here's a more obscure one: cryptographic PRNGs typically need to be continually be reseeded with "real" entropy. Thus, if you use a CPRNG too often, you could deplete the system's entropy pool, which (depending on the implementation of the CPRNG) will either weaken it (thus allowing an attacker to predict it) or it will block while trying to fill up its entropy pool (thus becoming an attack vector for a DoS attack).

Either way, your application has now become an attack vector for other, totally unrelated applications which – unlike yours – actually vitally depend on the cryptographic properties of the CPRNG.

This is an actual real world problem, BTW, that has been observed on headless servers (which naturally have rather small entropy pools because they lack entropy sources such as mouse and keyboard input) running Linux, where applications incorrectly use the /dev/random kernel CPRNG for all sorts of random numbers, whereas the correct behavior would be to read a small seed value from /dev/urandom and use that to seed their own PRNG.

Jörg W Mittag
I read the Wikipedia article and some other Internet sources on entropy and entropy depletion, and I don't quite understand it. How can I be depleting the entropy pool when the random number generator is fed with system time, number of free bytes etc.? How can others use it as a attack vector to predict random numbers? Can you provide an easy example? Perhaps this discussion must be taken offline.http://en.wikipedia.org/wiki/Entropy_%28computing%29
Lernkurve
System time is not an entropy source, because it's predictable. I'm not sure about the number of free bytes, but I doubt it's a high-quality entropy source either. By sending more requests to the server, the attacker can cause the number of free bytes to decrease, making it partially deterministic. You application becomes an attack vector because by depleting the entropy pool, it forces the other, security-critical application to use less-random random numbers -- or wait until the entropy source is replenished.
quant_dev
+2  A: 

This has been discussed at some length, but ultimately, the issue of performance is a secondary consideration when selecting a RNG. There are a vast array of RNGs out there, and the canned Lehmer LCG that most system RNGs consists of is not the best nor even necessarily the fastest. On old, slow systems it was an excellent compromise. That compromise is seldom ever really relevant these days. The thing persists into present day systems primarily because A) the thing is already built, and there is no real reason to 'reinvent the wheel' in this case, and B) for what the vast bulk of people will be using it for, it's 'good enough'.

Ultimately, the selection of an RNG comes down to Risk/Reward ratio. In some applications, for example a video game, there is no risk whatsoever. A Lehmer RNG is more than adequate, and is small, concise, fast, well-understood, and 'in the box'.

If the application is, for example, an on-line poker game or lottery where there are actual prizes involved and real money comes into play at some point in the equation, the 'in the box' Lehmer is no longer adequate. In a 32-bit version, it only has 2^32 possible valid states before it begins to cycle at best. These days, that's an open door to a brute force attack. In a case like this, the developer will want to go to something like a Very Long Period RNG of some species, and probably seed it from a cryptographically strong provider. This gives a good compromise between speed and security. In such a case, the person will be out looking for something like the Mersenne Twister, or a Multiple Recursive Generator of some kind.

If the application is something like communicating large quantities of financial information over a network, now there is a huge risk, and it heavily outweights any possible reward. There are still armored cars because sometimes heavily armed men is the only security that's adequate, and trust me, if a brigade of special ops people with tanks, fighters, and helicopters was financially feasible, it would be the method of choice. In a case like this, using a cryptographically strong RNG makes sense, because whatever level of security you can get, it's not as much as you want. So you'll take as much as you can find, and the cost is a very, very remote second-place issue, either in time or money. And if that means that every random sequence takes 3 seconds to generate on a very powerful computer, you're going to wait the 3 seconds, because in the scheme of things, that is a trivial cost.

David
I think you are wrong about your magnitudes; sending financial data needs to be extremely quick; if your trading algorithm can get to the result 0.1ms quicker than the competition, you end up better in the queue of buy/sell/stop-loss/quote commands. 3 seconds is an eternity. This is why traders invest in insanely good computers. See the previous answer; Crypt.RNG takes only 0,0028 ms per new number; 0.0000028 seconds, so you are off by 9 orders of magnitude in terms of how much processing it takes, and also on how important speed is.
Henrik
A: 

Different needs call for different RNGs. For crypto, you want your random numbers to be as random as possible. For Monte Carlo simulations, you want them to fill the space evenly and to be able to start the RNG from a known state.

quant_dev