Я збираюся опублікувати відповідь, тому що деякі з існуючих відповідей близькі, але мають один із:
- менший простір символів, ніж ви хотіли, так що грубе форсування простіше або пароль повинен бути довшим для тієї самої ентропії
- ГСЧ , не рахується криптографічний безпечними
- вимога до якоїсь сторонньої бібліотеки, і я подумав, що може бути цікаво показати, що може знадобитися зробити це самостійно
Ця відповідь обійде count/strlen
питання, оскільки безпека згенерованого пароля, принаймні IMHO, перевершує те, як ви туди потрапляєте. Я також припускаю PHP> 5.3.0.
Розбимо задачу на складові частини, які є:
- використовувати якесь захищене джерело випадковості для отримання випадкових даних
- використовувати ці дані і представляти їх як деякий рядок для друку
У першій частині PHP> 5.3.0 забезпечує функцію openssl_random_pseudo_bytes
. Зауважте, що в більшості систем використовується криптографічно сильний алгоритм, ви повинні перевірити, щоб ми використовували обгортку:
/**
* @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;
}
У другій частині ми будемо використовувати, base64_encode
оскільки вона займає байт-рядок і створить ряд символів, які мають алфавіт, дуже близький до того, який зазначено в оригінальному запитанні. Якщо б ми не заперечували над тим +
, /
а =
символи з’являються в заключній рядку і нам потрібен результат хоча б $n
символів, ми можемо просто використовувати:
base64_encode(strong_random_bytes(intval(ceil($n * 3 / 4))));
3/4
Фактором є те, з - за того , що кодування base64 результатів у вигляді рядка , яка має довжину , щонайменше, третина більше , ніж рядки байтів. Результат буде точним, $n
якщо в іншому випадку кратно 4 та до 3 символів. Оскільки зайві символи є переважно символом прокладки =
, якщо ми з якихось причин мали обмеження, що пароль має бути точної довжини, то ми можемо скоротити його до потрібної довжини. Це особливо тому, що для даної дати $n
всі паролі закінчуватимуться однаковою кількістю таких, щоб зловмисник, який мав доступ до результату пароля, мав до 2 менших символів для здогадки.
Для додаткового кредиту, якби ми хотіли зустріти точну специфікацію, як у питанні про ОП, тоді нам доведеться зробити трохи більше роботи. Я тут відмовляюся від базового підходу до перетворення та йду з швидким та брудним. І те й інше потрібно створити більше випадковості, ніж все одно буде використано в результаті через 62 алфавіту довгого введення.
Для додаткових символів у результаті ми можемо просто відкинути їх від отриманого рядка. Якщо ми почнемо з 8-ти байт у нашому ряду байтів, то приблизно 25% символів base64 становитимуть ці "небажані" символи, так що просто відкидання цих символів призводить до рядка, не меншого, ніж хотів ОП. Тоді ми можемо просто усікати його, щоб прийти до точної довжини:
$dirty_pass = base64_encode(strong_random_bytes(8)));
$pass = substr(str_replace(['/', '+', '='], ['', '', ''], $dirty_pass, 0, 8);
Якщо ви генеруєте більш довгі паролі, символ прокладки =
утворює все меншу і меншу частку проміжного результату, щоб ви могли реалізувати менший підхід, якщо виснаження пулу ентропії, що використовується для PRNG, викликає занепокоєння.