Generating cryptographically secure tokens

Here is the correct solution:

$token = bin2hex(openssl_random_pseudo_bytes(16));

# or in php7
$token = bin2hex(random_bytes(16));

If you want to use openssl_random_pseudo_bytes it is best to use CrytoLib's implementation, this will allow you to generate all alphanumeric characters, sticking bin2hex around openssl_random_pseudo_bytes will just result in you getting A-F (caps) and numbers.

Replace path/to/ with where you put the cryptolib.php file (you can find it on GitHub at: https://github.com/IcyApril/CryptoLib)

<?php
  require_once('path/to/cryptolib.php');
  $token = IcyApril\CryptoLib::randomString(16);
?>

The full CryptoLib documentation is available at: https://cryptolib.ju.je/. It covers a lot of other random methods, cascading encryption and hash generation and validation; but it's there if you need it.


If you have a cryptographically secure random number generator, you don't need to hash it's output. In fact you don't want to. Just use

$token  = openssl_random_pseudo_bytes($BYTES,true)

Where $BYTES is however many bytes of data you want. MD5 has a 128bit hash, so 16 bytes will do.

As a side note, none of the functions you call in your original code are cryptographically safe, most are harmful enough that using just one would break be insecure even if combined with secure other functions. MD5 has security issues(though for this application they may not be relevant). Uniqid not just doesn't generate cryptographically random bytes by default (since it uses the system clock), the added entropy you pass in is combined using a linear congruent generator, which is not cryptographically secure. In fact, it probably means one could guess all your API keys given access to a few of them even if they had no idea the value of your server clock. Finally, mt_rand(), what you use as the extra entropy, is not a secure random number generator either.