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.