6

I am developing a site in PHP 5.4. Which function is better to use to generate 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);
TRiG
  • 610
  • 5
  • 14
John
  • 173
  • 1
  • 6
  • 2
    [Oh You!](http://i.stack.imgur.com/RPMRb.jpg) [Don't be Dave.](http://security.stackexchange.com/questions/25585/is-my-developers-home-brew-password-security-right-or-wrong-and-why) – Lucas Kauffman Dec 30 '12 at 10:42
  • 1
    Salts don't need great quality randomness. Being unique is enough. – CodesInChaos Dec 30 '12 at 14:54
  • 1
    Rather than hashing the output of the openssl function you'd be better off using bin2hex if you need a string: $salt = bin2hex(openssl_random_pseudo_bytes(64)); – t j Oct 15 '14 at 06:57
  • @TomJowitt $salt = bin2hex(openssl_random_pseudo_bytes(32)); for 64 char length! – Nicolas Manzini Oct 29 '15 at 00:38

2 Answers2

7

The right way to generate a salt for password hashing is: do not do it yourself. Use a library which already does thing properly. See @Terry's answer for pointers.

For your exact question, it so happens that openssl_random_pseudo_bytes() relies on OpenSSL's internal PRNG, which itself feeds on what the underlying platform provides, i.e. dev/urandom, so it is safe. Strictly speaking, you should use the second parameter of that function to check whether OpenSSL did find a strong source of randomness on the local platform (see the documentation), but in practice, as long as OpenSSL runs on a Unix-like or Windows-like platform, things will be fine. So it does not really matter, for security, whether you call openssl_random_pseudo_bytes() or read /dev/urandom yourself. For maintenance reasons, I would prefer the former, which is simpler (only one call) and more portable (it will also work on Windows, whereas reading /dev/urandom will not).

Either way, applying SHA-1 on the output of openssl_random_pseudo_bytes() or /dev/urandom, is totally useless. Good PRNG already produce unpredictable uniformly random bytes (and if your PRNG is not good, then why are you using it ?).

Thomas Pornin
  • 322,884
  • 58
  • 787
  • 955
  • He might be using the hash function to convert binary output into human readable encoding. bin2hex() PHP function could be used to achieve the same, without hashing the output. – Matrix Dec 30 '12 at 15:27
  • doesnt have to be readable and thank you, and i was aware of of the second second parameter and had used it to test my system to see if it had enough randomness and entropy, i scoured the doc pages on both before i asked the question, i am writing this more to advance my knowledge than i am to do production development. – John Dec 30 '12 at 20:54
  • as a learning developer i feel that i should thoroughly explore the code i am learning, to give me a better grasp of it and what it does. so down the road when i am using libraries like phpass i will have a better command of what they are doing to handle debugging, and many other thing, what i learn doing this could lead to learning any number of other things. – John Dec 30 '12 at 21:19
3

Note: This doesn't answer the question exactly.

Try not to roll your own crypto. Since you are using PHP, a great bcrypt library - phpass, is readily available that will take care of the password hashing aspect, including generating salts.

  • 4
    PHP's new [password-related functions](https://wiki.php.net/rfc/password_hash) are also worth a look. They'll be available from 5.5, in the meantime there's a [compatibility lib](https://github.com/ircmaxell/password_compat). – Maerlyn Dec 30 '12 at 09:44