(Don't be) Insecure Randomness

(Don't be) Insecure Randomness

The OWASP Foundation identifies Randomness as potentially insecure. You can read more about it here.

So, Random generators are insecure?

In a nutshell, yes! - the general concept is that when you ask your underlying code framework (C# / Java / whatever) to generate a random number (i.e. new Random().Next()) it's not as random as you would think. Without getting into too much detail, by default they tend to use a statistical Pseudo-Random Number Generator (PRNG).

I might need a little more detail...?

The problem is that when you string together several random values (i.e. when generating a key of some sort) - that stream of random values is considered statistically 'highly predictable'. Maybe not so predictable by yours truly, but I'm sure with enough hours we could throw together an app to prove this.

Anyway, let's accept that OWASP is right, and statistical random number generation is bad practice if you want to stay secure. Who knows where that utility function you wrapped up will be used over the years? Maybe in some really sensitive areas.

So what do we do...?

Well, instead of using a statistical PRNG, we want to use a cryptographical one. In .NET Framework / .NET Core this is pretty easy to do with the System.Security.Cryptography.RandomNumberGenerator class. The thing about this class is that, out of the box, it's best at providing random byte[] data.

So, let's get a cryptographically random byte[] and use that to get an Int32 using the BitConvertor utility like so:

// Compliant for security-sensitive use cases
var randomGenerator = RandomNumberGenerator.Create(); 
byte[] data = new byte[16];
randomGenerator.GetBytes(data);
return BitConverter.ToInt32(data);

We can do the same to generate a double by simply using the ToDouble method on the BitConvertor:

return BitConverter.ToDouble(data, 4);

What about random strings?

Well, you can use our randomly generated byte stream to select characters. Be warned, this does lessen the randomness somewhat. In the example below I am only selecting from one of 52 different characters, where each random byte could be one of 128 different values.

char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
byte[] data = new byte[4 * length];

// Compliant for security-sensitive use cases
var randomGenerator = RandomNumberGenerator.Create(); 
randomGenerator.GetBytes(data);
StringBuilder result = new StringBuilder(length);
for (int i = 0; i < length; i++)
{
    var rnd = BitConverter.ToUInt32(data, i * 4);
    var idx = rnd % chars.Length;
    result.Append(chars[idx]);
}
return result.ToString();

Maybe if I just extended the char array to 128 different values that wouldn't be the case? I am certainly no David Zuckerman so I'd certainly be interested to hear from any die-hard crypto experts as to if my random guess (pun intended) is anywhere near mathematical reality??

Happy hacking!!!