On Sunday, 26 February 2017 at 22:56:14 UTC, Nick Sabalausky (Abscissa) wrote:
On 02/26/2017 01:23 PM, cym13 wrote:
Hi,

I found many times that people use unpredictableSeed in combination with normal PRNG for cryptographic purpose. Some even go as far as reseeding
at each call to try making it more secure.

It is a dangerous practice, most PRNG are not designed with security (and unpredictability) in mind, and unpredictableSeed was definitely not designed with security in mind (or it failed heavily at it). It's a good
tool when one needs randomness, not security.

I wrote a blog post to present exactly why this is a bad idea and how it
could be exploited [1].

The best would be to add a standard CSPRNG interface to Phobos but we
aren't there yet.

[1]: https://cym13.github.io/article/unpredictableSeed.html

FWIW, DAuth[1] uses, and offers, an implementation of Hash_DRBG, a well-known and established CSPRNG algorithm. It's entropy source (not exactly the same as a seed, but basically the CSPRNG equivalent) is customizable, but by default, it uses _RtlGenRandom on Windows (the same source used by the CryptGenRandom algorithms) and '/dev/urandom' on Posix:

https://github.com/Abscissa/DAuth/blob/master/src/dauth/hashdrbg.d

[1] Ugh, still haven't gotten around to finishing DAuth's new version, renamed "InstaUser".

And it is very interesting to note that you fall into the very exact problem I am describing in my post if it weren't that your default PRNG isn't seedable. Use any other PRNG and you are vulnerable (if I read it correctly, I haven't spent much time on that).

From random.d, the function randomToken calls randomBytes which inits a new PRNG which is seeded with unpredictableSeed which becomes the actual PRNG used:

string randomToken(Rand = DefaultCryptoRand)(size_t strength = defaultTokenStrength)
        if(isDAuthRandom!Rand)
{
        return TokenBase64.encode( randomBytes!Rand(strength) );
}

ubyte[] randomBytes(Rand = DefaultCryptoRand)(size_t numBytes)
        if(isDAuthRandom!Rand)
{
        Rand rand;
        rand.initRand();
        return randomBytes(numBytes, rand);
}

private void initRand(Rand)(ref Rand rand)
        if(isDAuthRandom!Rand)
{
        static if(isSeedable!Rand)
                rand.seed(unpredictableSeed);
}

The only thing that saves you here is that your DefaultCryptoRand isn't seedable. Note that I'm not saying that to bash you or anything, it just happens to show well why I think my article was necessary.

Reply via email to