What's the best way to generate a cryptographically secure 32 bytes salt in PHP, without depending on libraries seldom included in typical PHP installations?
After some googling I discovered that mt_rand
is not considered secure enough, but I haven't found a suggestion for a replacement. One article suggested reading from /dev/random
but not only this won't work on windows; it is also very slow.
I want a reasonable balance between security and speed (ie, it shouldn't take 20 seconds to generate 512 bytes, like /dev/random
usually does)
Note: mcrypt
has been deprecated in PHP 7.1. Skip to the up-to-date answer.
You might want to take a look at the documentation (and comments) for mcrypt_create_iv()
.
This is easier in PHP 7:
Just use $salt = random_bytes($numberOfDesiredBytes);
to generate a salt.
What do you need a salt for, anyway? If it's for passwords, just use password_hash()
and password_verify()
.
Note: mcrypt
has been deprecated in PHP 7.1. Skip to the up-to-date answer.
You can use the function mycrypt_create_iv()
, since PHP Version 5.3 it also uses the random source on a Windows server (not only on Unix). Before using it, you should check if the constant MCRYPT_DEV_URANDOM
is defined.
mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
Unlike random, urandom does not block the server, if there is not enough entropy available. Since the password salt should be unique (not necessarily random), urandom seems to be a good choice to me.
uniqueid
is not well suited for generating a random string as it too is microtime
based.
A CPU Cycle is generally much shorter than a microtime-tick, which may lead to possible constancy for a given variable within loops.
Setting the second parameter "entropy" to true,
uniqid('', true)
will provide increased randomness.
To get a random string that is well compatible with most character-sets,one may apply base64 encoding to the mcrypt initilization vector function mcrypt_create_iv
:
$length = 16;
base64_encode(mcrypt_create_iv(ceil(0.75*$length), MCRYPT_DEV_URANDOM))
//> hlZuRJypdHFQPtI2oSFrgA==
strlen(base64_encode(mcrypt_create_iv(ceil(0.75*$length), MCRYPT_DEV_URANDOM)))
//> 16
Reducing the character-alphabet to 2^6Bit increases the size, which is accounted for above.
Read from /dev/urandom
, or use openssl_random_pseudo_bytes()
.
uniqid() should be fine for this purpose.
I think microtime()
is enough.
Strangely, but I am still getting downvotes for this answer.
Though the only explanation I get is that microtime is predictable.
It sounds strange to me as salt always assumed as openly known - so, there is no use for prediction at all.