9

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);
John
  • 497
  • 2
  • 6
  • 20
  • 4
    Using `sha1()` will greatly reduce the effectiveness of your random salt since it will convert it to a string that is 40 chars and only containing 0-9 and a-f characters. There would be a lot less combinations (meaning less random) than if you just used 40 bytes from `openssl_random_pseudo_bytes()` – kittycat Dec 30 '12 at 09:07
  • i am going with both of your suggestions – John Dec 30 '12 at 09:13

3 Answers3

10

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');
}
kmkaplan
  • 18,655
  • 4
  • 51
  • 65
  • 1
    Actually, `openssl_rand_pseudo_bytes` doesn't _guarantee_ true randomness either, any more than `/dev/urandom` does; that's what the `pseudo` in the name means. In practice, however, both produce output indistinguishable from random by any known means. – Ilmari Karonen Dec 30 '12 at 10:04
  • @IlmariKaronen Of course you do not get true randomness. I only wrote “good” ; what OpenSSL calls “cryptographically strong”. That is why I put in the test to check that the result is cryptographically strong. – kmkaplan Dec 30 '12 at 22:12
  • @ScottArciszewski what do you suggest as an alternative? AFAIK `/dev/urandom` also has problems if used incorrectly. Also, the issue you linked to only applies to certain server configurations and has been fixed in the latest release of PHP. I prefer to use something that has been tested and any problems sorted out, and avoid switching to an alternative with unknown problems. – Abhi Beckert Aug 03 '16 at 06:48
  • https://github.com/paragonie/random_compat - which is a PHP 5 polyfill for PHP 7's secure `random_bytes()` function. – Scott Arciszewski Aug 03 '16 at 15:49
10

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.

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • `RAND_pseudo_bytes` and `openssl_random_pseudo_bytes` returns a code that tells you “if the bytes generated are cryptographically strong”. – kmkaplan Dec 30 '12 at 22:17
0

I know this is an old post but if anyone stumbles into this here is an easy solution:

compat_random.php
https://gist.github.com/anzz1/29a787fac8ef6d693b41779911287505

<?php
  require_once(dirname(__FILE__) . '/compat_random.php');

  $salt = random_bytes(40);
?>

Done.

The compat_random.php is only 2KB, 62 lines of code.
You should be able to use it with any PHP version.

It checks for these functions in this order:

  • random_bytes (PHP >= 7) [Cryptographically secure]
  • openssl_random_pseudo_bytes (OpenSSL) [Cryptographically secure]
  • mcrypt_create_iv (php_mcrypt) [Cryptographically secure]
  • /dev/urandom (UNIX systems) [Cryptographically secure]

It's very likely you do have one of these available, but if you do not, it will fall finally fall back to

  • mt_rand() (PHP >= 4) [Not cryptographically secure, but fine for most cases]
  • rand() [Insecure]
anzz1
  • 91
  • 1
  • 4