In your code, you have to fill $legal_characters
with the list of characters that you accept as part of a password. E.g.:
$legal_characters = "abcdefghijklmnopqrstuvwxyz";
This code is a bit weird; it uses mt_rand()
(an internal PRNG) seeded with the current time and the process ID to get the length of the password, between 15 and 60 characters. Then it uses /dev/urandom
for the password itself, which is smart since mt_rand()
is not cryptographically secure (especially since the process ID is not something which is very secret, and neither is the current time).
The actual password generation work thus: it produces 500 random bytes (from /dev/urandom
), then removes all those which are not in the set of accepted characters (that’s the “tr
“), and finally truncates again the remaining sequence of characters to the desired length. This process generates uniformly random sequences, so that’s good, and /dev/urandom
is the appropriate PRNG for that. Note, though, a few caveats:
-
If the set of “legal characters” is small, you could end with a shorter password. E.g. if you want passwords with only digits from 1 to 6, there will be, on average, only 12 or so matching bytes in the 500 random bytes. The code has no failsafe for “too short”. If you set
$legal_characters
to all 26 lowercase letters, then about 1 byte in 10 will be legal (byte values range from 0 to 255, and 26/256 is close to 1/10) and, on average, the “tr
” part will yield about 50 characters, and it is extremely improbable that it will yield less than 20. Still, this is worth noting and there should be a failsafe. -
It makes little sense to have a variable length for the password. If a password of minimal length is acceptable security-wise, then all passwords could have that length. And if it is not acceptable, then why do you use that minimal length ? You’d better use a single, fixed length, rather than a range. This would allow you to remove
seed_random()
andmt_rand_custom()
, substantially simplifying the code. -
A “password” is something that a human being will be able to type an memorize — hence “word”. Will he memorize a 60-character sequence ? I am sure there is a medical name for such a condition.
-
You should set the length of the passwords to an “appropriate” value such that the entropy will be high enough. If there are x legal characters and the password length is n, then the entropy will be xn. What entropy is needed depends on the intended usage. For authenticating users on a Web site, through an appropriate SSL tunnel, 240 (“40 bits” of entropy) is more than enough, which translates to 9 lowercase letters (269 is greater than 240).
-
The code uses unixisms (
/dev/urandom
,head
,tr
…) and will have a hard time running on, say, a Windows server (and PHP runs on Windows, too).
Summary: the passwords will be strong, but the code is weird. You should drop the variable length, and if your users can swallow 60-character passwords, then please congratulate them for me. Or sell them to a zoo. Here is a simplified code which should be OK (warning: I do not use PHP so I am improvising here):
function generate_password() {
return shell_exec('head -c 500 /dev/urandom | tr -dc abcdefghijklmnopqrstuvwxyz | head -c 9; echo');
}