I'm going to post an answer because some of the existing answers are close but have one of:
- a smaller character space than you wanted so that either brute-forcing is easier or the password must be longer for the same entropy
- a RNG that isn't considered cryptographically secure
- a requirement for some 3rd party library and I thought it might be interesting to show what it might take to do it yourself
This answer will circumvent the count/strlen
issue as the security of the generated password, at least IMHO, transcends how you're getting there. I'm also going to assume PHP > 5.3.0.
Let's break the problem down into the constituent parts which are:
- use some secure source of randomness to get random data
- use that data and represent it as some printable string
For the first part, PHP > 5.3.0 provides the function openssl_random_pseudo_bytes
. Note that whilst most systems use a cryptographically strong algorithm, you have to check so we'll use a wrapper:
/**
* @param int $length
*/
function strong_random_bytes($length)
{
$strong = false; // Flag for whether a strong algorithm was used
$bytes = openssl_random_pseudo_bytes($length, $strong);
if ( ! $strong)
{
// System did not use a cryptographically strong algorithm
throw new Exception('Strong algorithm not available for PRNG.');
}
return $bytes;
}
For the second part, we'll use base64_encode
since it takes a byte string and will produce a series of characters that have an alphabet very close to the one specified in the original question. If we didn't mind having +
, /
and =
characters appear in the final string and we want a result at least $n
characters long, we could simply use:
base64_encode(strong_random_bytes(intval(ceil($n * 3 / 4))));
The 3/4
factor is due to the fact that base64 encoding results in a string that has a length at least a third bigger than the byte string. The result will be exact for $n
being a multiple of 4 and up to 3 characters longer otherwise. Since the extra characters are predominantly the padding character =
, if we for some reason had a constraint that the password be an exact length, then we can truncate it to the length we want. This is especially because for a given $n
, all passwords would end with the same number of these, so that an attacker who had access to a result password, would have up to 2 less characters to guess.
For extra credit, if we wanted to meet the exact spec as in the OP's question then we would have to do a little bit more work. I'm going to forgo the base conversion approach here and go with a quick and dirty one. Both need to generate more randomness than will be used in the result anyway because of the 62 entry long alphabet.
For the extra characters in the result, we can simply discard them from the resulting string. If we start off with 8 bytes in our byte-string, then up to about 25% of the base64 characters would be these "undesirable" characters, so that simply discarding these characters results in a string no shorter than the OP wanted. Then we can simply truncate it to get down to the exact length:
$dirty_pass = base64_encode(strong_random_bytes(8)));
$pass = substr(str_replace(['/', '+', '='], ['', '', ''], $dirty_pass, 0, 8);
If you generate longer passwords, the padding character =
forms a smaller and smaller proportion of the intermediate result so that you can implement a leaner approach, if draining the entropy pool used for the PRNG is a concern.
/dev/random
are enough as the question doesn't ask for a "secure" password (and shouldn't be edited to contain that as it would alter the meaning of the original question). Although I'm all for security, I think this carpet bomb wasn't thought through fully. Like usingmysql_*
, the answers are still valid, but should be marked as insecure. Perhaps this is something that SO needs to include as extra software - the ability to warn of insecure code? – TreasurePasswords come with different requirements - one person's "extremely complex and confusing" password is another person's secure password.
" And my advice for users is to use a password manager and only bother remembering one "extremely complex and confusing password". – Sumerology