Замените rand() на openssl_random_pseudo_bytes()
Мне нужна замена для функции PHP rand()
, которая использует криптографически сильный генератор случайных чисел.
Функция openssl_random_pseudo_bytes()
получает доступ к генератору сильных случайных чисел, но выводит свои данные в виде байтовой строки. Вместо этого мне нужно целое число от 0 до X.
Я полагаю, что ключ состоит в том, чтобы получить вывод openssl_random_pseudo_bytes()
в целое число, тогда вы можете выполнить любую математику, в которой вы нуждаетесь. Я могу придумать несколько способов перебора из строки байтов в целое число, но я надеялся на что-то... элегантное.
Ответы
Ответ 1
Используя предоставленные предложения, я создал замену для rand() с помощью OpenSSL. Я включу его здесь для потомства.
Параметр $pedantic предоставляет результаты без смещения, начиная с момента, когда результаты не будут равномерно распределены в пределах возможного диапазона.
function crypto_rand($min,$max,$pedantic=True) {
$diff = $max - $min;
if ($diff <= 0) return $min; // not so random...
$range = $diff + 1; // because $max is inclusive
$bits = ceil(log(($range),2));
$bytes = ceil($bits/8.0);
$bits_max = 1 << $bits;
// e.g. if $range = 3000 (bin: 101110111000)
// +--------+--------+
// |....1011|10111000|
// +--------+--------+
// bits=12, bytes=2, bits_max=2^12=4096
$num = 0;
do {
$num = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes))) % $bits_max;
if ($num >= $range) {
if ($pedantic) continue; // start over instead of accepting bias
// else
$num = $num % $range; // to hell with security
}
break;
} while (True); // because goto attracts velociraptors
return $num + $min;
}
Ответ 2
На странице руководства для openssl_random_pseudo_bytes()
приведен пример, который, я думаю, вы хотите. Вы можете просто вызвать bin2hex()
на выходе openssl_random_pseudo_bytes()
для преобразования в шестнадцатеричное число, а затем hexdec()
для этого значения, чтобы преобразовать в десятичный.
$rand_num = hexdec(bin2hex(openssl_random_pseudo_bytes($length, $strong)));
В этот момент вы можете делать любую математику, которую хотите получить, в нужном вам диапазоне. Другой вариант (мошенник), который у вас есть, - запустить системную команду для генерации случайного числа - есть несколько хороших вариантов для генераторов случайных чисел для различных операционных систем, доступных в Интернете.
Ответ 3
Вот версия вышеперечисленных решений, которая не использует рекурсивные вызовы функций:
function secure_rand($min,$max) {
$range = $max - $min + 1;
if ($range == 0) return $min;
$length = (int) (log($range,2) / 8) + 1;
$max = pow(2, 8 * $length);
$num = $max + 1; // Hackish, I know..
while ($num > $max) {
$num = hexdec(bin2hex(openssl_random_pseudo_bytes($length,$s)));
}
return ($num % $range) + $min;
}
Ответ 4
Поскольку PHP 7 сейчас отсутствует, самый простой способ решить эту проблему - заменить все экземпляры mt_rand
на random_int
.
(Предположим, что вы обновили, то есть.)
Ответ 5
ну, просто используйте hexdec для результата openssl_random_pseudo_bytes, и вы получите свое целое число. Это так же изящно, как и получается:)
print hexdec('45261b8f');
> 1160125327
Ответ 6
Самый простой способ сделать это (и самый безопасный из всех вариантов здесь) - использовать CryptoLib, который имеет функцию randomInt, которая предоставляет замену для rand.
Сначала загрузите CryptoLib и вставьте его в свой проект: https://github.com/IcyApril/CryptoLib
Два, запустите этот код. замените путь/на/с каталогом cryptolib.php и min max с минимальным и максимальным номерами:
<?php
require_once('path/to/cryptoLib.php');
$min = 1;
$max = 5;
$randomNum = CryptoLib::randomInt($min, $max);
?>
Полная документация CryptoLib: https://cryptolib.ju.je/
Ответ 7
function ($min,$max){
$range = $max-$min+1;
do{
$result = floor($range*(hexdec(bin2hex(openssl_random_pseudo_bytes(4)))/0xffffffff));
} while($result == $range);
return $result + $min;
}