I am developing a site in php 5.4 and i was wondering which is better to use to gen a random salt for password security?
$salt = sha1(openssl_random_pseudo_bytes(23));
or
$seed = '';
$a = @fopen('/dev/urandom','rb');
$seed .= @fread($a,23);
$salt = sha1(seed);
or should i just go with:
$salt = openssl_random_pseudo_bytes(40);
or
$salt = '';
$a = @fopen('/dev/urandom','rb');
$salt .= @fread($a,23);
For security purposes you are better off using openssl_random_pseudo_bytes
. OpenSSL takes care of gathering enough entropy to serve you good randomness. /dev/urandom
is devised to never block and could be tricked into giving you not so random bytes.
With random bytes you do not need to run them through SHA1.
To sum it all, do:
$salt = openssl_random_pseudo_bytes(40, $cstrong);
if (! $cstrong) {
exit('This should not happen');
}
In practice, there is almost certainly no difference.
Both openssl_random_pseudo_bytes
and /dev/urandom
provide a cryptographically secure source of pseudorandom bytes. Neither is guaranteed to be truly random, but in practice, both are expected to be indistinguishable from true randomness by any known or foreseeable techniques.
Kmkaplan is technically correct in noting that /dev/urandom
could return theoretically predictable output under certain conditions, as noted in man unrandom
:
"A read from the /dev/urandom device will not block waiting for more entropy. As a result, if there is not sufficient entropy in the entropy pool, the returned values are theoretically vulnerable to a cryptographic attack on the algorithms used by the driver. Knowledge of how to do this is not available in the current unclassified literature, but it is theoretically possible that such an attack may exist. If this is a concern in your application, use /dev/random instead."
However, the same is actually true of openssl_random_pseudo_bytes
(which calls the OpenSSL function RAND_pseudo_bytes
internally), as noted in the OpenSSL documentation:
"RAND_pseudo_bytes()
puts num pseudo-random bytes into buf. Pseudo-random byte sequences generated by RAND_pseudo_bytes()
will be unique if they are of sufficient length, but are not necessarily unpredictable. They can be used for non-cryptographic purposes and for certain purposes in cryptographic protocols, but usually not for key generation etc."
Neither of these warnings should actually scare you from using these methods — the weaknesses they describe are only theoretical, except possibly under certain contrived circumstances (such as on a diskless embedded device with no hardware RNG immediately after boot-up), and should not be of practical concern in situations where PHP is normally deployed.
The upshot is, neither of these random number generation methods is going to be the weakest link in your cryptosystem, so you can safely choose either one. If you're feeling paranoid, you could even use both.
Ps. One advantage of openssl_random_pseudo_bytes
is that it works on Windows, too. On the other hand, /dev/urandom
is available on Unix even if the OpenSSL PHP extension is not installed. Thus, for maximum portability, you should indeed implement support for both.
Also, always check that you indeed received as many bytes as you expected; for example, the /dev/urandom
based code in your question above could silently return an empty string on systems like Windows where /dev/urandom
does not exist.