bbusschots / hsxkpasswd

A Perl module and terminal command for generating secure memorable passwords inspired by the fabulous XKCD web comic and Steve Gibson's Password Hay Stacks. This is the library that powers www.xkpasswd.net
http://www.bartb.ie/xkpasswd
BSD 2-Clause "Simplified" License
277 stars 48 forks source link

Insecure random number generator #6

Closed polof closed 9 years ago

polof commented 9 years ago

Hi,

The function basic_random_generator that is used by default to generate random numbers is insecure. It uses Perl's built-in "rand" function and the Perl docs state:

        "rand()" is not cryptographically secure. You should not rely on
        it in security-sensitive situations. As of this writing, a number
        of third-party CPAN modules offer random number generators
        intended by their authors to be cryptographically secure,
        including: Data::Entropy, Crypt::Random, Math::Random::Secure, and
        Math::TrulyRandom.
bbusschots commented 9 years ago

I would argue that while rand() is obviously not sufficient for cryptography, it is sufficient for password generation for most people.

However, precisely because rand() has known shortcomings, the module provides a built-in means for users to supply their own sources of randomness.

A new version of the module is nearly ready to be released, and it comes with two notable improvements in this regard. Firstly, it makes it a little easier to provide custom sources of randomness through polymorphism, and secondly, it will ship with a ready-to-use class that uses random.org's web service as it's source or randomness.

You can get a sneak-peak at the new version of the module, and, if you like, contribute the code to interface with another source of randomness, in the branch CPAN-prep: https://github.com/bbusschots/xkpasswd.pm/tree/CPAN-Prep

polof commented 9 years ago

Den 2015-05-16 19:42, Bart Busscots skrev:

I would argue that while |rand()| is obviously not sufficient for cryptography, it is sufficient for password generation for most people.

I don't know how rand() is implemented in Perl, but the docs clearly recommend against using it in security-sensitive situations. Why take the risk?

Also, how can you assume that users won't use the password as an encryption key?

However, precisely because |rand()| has known shortcomings, the module provides a built-in means for users to supply their own sources of randomness.

If they know about it, that is. I didn't, until I read the source code.

Why not use a good RNG by default? Just read /dev/urandom or some Perl module.

A new version of the module is nearly ready to be released, and it comes with two notable improvements in this regard. Firstly, it makes it a little easier to provide custom sources of randomness through polymorphism, and secondly, it will ship with a ready-to-use class that uses random.org's web service as it's source or randomness.

How is that better than /dev/urandom? Now I have to trust both my computer and some external web service that I know nothing about.

You can get a sneak-peak at the new version of the module, and, if you like, contribute the code to interface with another source of randomness, in the branch CPAN-prep: https://github.com/bbusschots/xkpasswd.pm/tree/CPAN-Prep

No thanks, I found a better program: https://github.com/redacted/XKCD-password-generator

I just don't want anybody else to use a bad RNG by accident.

Pelle

bbusschots commented 9 years ago

Firstly and most importantly, attackers trying to guess a password or reverse a hash have no way of knowing how it was generated, so the RNG is not something they can attack. The strength of passwords lies in their length and their alphabet, and on that count, the passwords generated by this module are very strong indeed.

The key question is, are passwords generated with this module stronger than those you could make up with your own imagination? The answer to that is definitely yes. What ever you can say about rand(), it plus a big dictionary file will produce a heck of a lot more randomness than the human brain ever could!

To answer your specific questions, why rand()? Because rand() is part of every standard perl distribution, and the other models are not. Until the code is in CPAN I wanted it to be installable without the need to install any non-standard modules.

Why not use /dev/urand? Simple, it is not cross-platform. I may not like Windows, but a lot of people use it all the same, and I wanted my module to work for them too.

Having said all that - I'm going to update the module to use Data::Entropy, Crypt::Random, Math::Random::Secure, or Math::TrulyRandom if they are installed, and only fall back on rand() when none of those modules are available. After all, in a contests between rand() and the human imagination, rand() is the clear winner!

polof commented 9 years ago

Den 2015-05-16 21:13, Bart Busscots skrev:

Firstly and most importantly, attackers trying to guess a password or reverse a hash have no way of knowing how it was generated, so the RNG is not something they can attack. The strength of passwords lies in their length and their alphabet, and on that count, the passwords generated by this module are very strong indeed.

Indeed, as long as the software doesn't get very popular...

The key question is, are passwords generated with this module stronger than those you could make up with your own imagination? The answer to that is definitely yes. What ever you can say about |rand()|, it plus a big dictionary file will produce a heck of a lot more randomness than the human brain ever could!

True :-)

To answer your specific questions, why |rand()|? Because |rand()| is part of every standard perl distribution, and the other models are not. Until the code is in CPAN I wanted it to be installable without the need to install any non-standard modules.

Why not use |/dev/urand|? Simple, it is not cross-platform. I may not like Windows, but a lot of people use it all the same, and I wanted my module to work for them too.

Right, but it could use /dev/urandom if available and otherwise fall back on rand().

Having said all that - I'm going to update the module to use |Data::Entropy|, |Crypt::Random|, |Math::Random::Secure|, or |Math::TrulyRandom| if they are installed, and only fall back on |rand()| when none of those modules are available. After all, in a contests between |rand()| and the human imagination, |rand()| is the clear winner!

Sounds fair :-) Please note it in the README also.

Pelle

bbusschots commented 9 years ago

I think this issue has been well addressed in the latest commit to the CPAN-Prep branch: https://github.com/bbusschots/xkpasswd.pm/commit/b8feb39a85fb0ec0b4fecc63137e0555d85ba2aa

Since the CPAN-Prep branch will be merged into the main branch any day now, I'm not going to back-port any of this to the current main branch.

polof commented 9 years ago

Great! :-)