0

For several cases I would need to create random md5 hashes. Do you know what the best / most secure ways of doing this are?

Some use cases

  • Verifying an email address
  • Resetting passwords
  • Some kind of session id used for authentication, instead of password (eg: when someone hits "remember me", I would not like to store the pass in a cookie)

Background

I know that rand() should not be used for security relevant applications. For that reason I went with:

md5( uniqid(mt_rand(),true) );

Now I read in the php manual about uniqid(), that it must not be used for security purposes. Which kind of makes sense because it usually just gives something like a timestamp.

But is it fine when combined with a random prefix - mt_rand() - like I do, or is there something better that should be used in this case?

Thx in advance!

Community
  • 1
  • 1
Levite
  • 17,263
  • 8
  • 50
  • 50
  • 1
    See [this](http://stackoverflow.com/questions/401656/secure-hash-and-salt-for-php-passwords), if it helps. – Ravi Dhoriya ツ Jun 04 '14 at 12:30
  • You can use `base64_encode` http://www.php.net/manual/en/function.base64-encode.php to encode. – prava Jun 04 '14 at 12:30
  • @Log1cツ: Thx, there is a lot in there! Most of all probably the function `openssl_random_pseudo_bytes()` as alternative. – Levite Jun 04 '14 at 12:35
  • @Prava-MindfireSolutions: The encoding is not so much the problem, as is the data for it (also base64 could easily be decoded/"reversed"). – Levite Jun 04 '14 at 12:51

2 Answers2

4

You don't need "MD5 hashes", you simply need a random string of characters. These need not have anything to do with MD5 at all. So all you need is a good PRNG. For instance:

$token = mcrypt_create_iv($rawLength, MCRYPT_DEV_URANDOM);
// or
$token = openssl_random_pseudo_bytes($rawLength);
// or
$token = file_get_contents('/dev/urandom', false, null, 0, $rawLength);

Then base64_encode or bin2hex the raw value to get an ASCII character string.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • That is actually a pretty good answer!! Just the problem in my case, that my server runs on a windows machine, so no `/dev/urandom` there :-/ – Levite Jun 04 '14 at 12:38
  • Well, there are enough alternatives... :) Actually, have a look at this library, which has many fallbacks: https://github.com/ircmaxell/password_compat/blob/master/lib/password.php#L90 – deceze Jun 04 '14 at 12:40
  • That looks pretty good, will give it a more thorough look. Just out of interest, what do you think of my original code with `mt_rand()` in combination with `uniqid()`? The combination of exact microsecond plus a "kind of" random algorithm seems not too bad to me, or am I missing something? – Levite Jun 04 '14 at 12:47
  • 2
    It's probably going to be okay in practice. However, IMO it's approaching it from the wrong side. You're generating a value with *some* entropy from an okay-but-not-great PRNG and feed that as seed into another okay-but-not-so-great PRNG which then gets hashed with a not-really-great hash, all of which just serves to gradually decrease the entropy, if anything. You should just use a high-entropy source to begin with and be done with it. – deceze Jun 04 '14 at 12:52
  • Well that sounds like a really good answer! Thx!! Especially "*... which then gets hashed with a not-really-great hash*" ^^ ... but true! – Levite Jun 04 '14 at 12:55
  • One more thing, in that context, since all those functions deliver random BYTES, do you think it would be "safe" to use md5/sha to wrap it, since it has to be in the url and just `urlencode()` makes it rather inconvenient to compare to the dbs. Or would you do/store it differently? Thx again! Eg.: `md5(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM));` – Levite Jun 04 '14 at 13:49
  • 1
    Again, just `bin2hex` or `base64_encode` those bytes. The bytes are already random, you simply want to present them in a different base. You essentially get them as raw base 256, and you want to represent them in base 16 (hex) or base 64 to make them readable/transportable. – deceze Jun 04 '14 at 13:55
0

I just finished devloping a fairly robust Bash script that generates decent quality md5sum's. You can find it https://code.google.com/p/gen-uniq-id/source/browse/gen_uniq_id.bsh

It has the following features:

A time stamp down to nanoseconds,

A user-modifiable amount of collected data from /dev/urandom (default is .25 seconds),

A user-modifiable amount of collected mouse-movement data (default is .25 seconds, just use xinput --list and run it once with -M<your_mouse_device_id>),

A dynamically modifiable text statement that may be set as a default or sent in dynamically with each call e.g. -s"$(history | tail -5)".

You can probably easily port over to PHP or just call it from PHP via shell_exec:
$random_md5sum = shell_exec('/path/to/gen_uniq_id.bsh -m1 -r1 -s"favorite quote$(history | tail -5)"');