2009-08-21 2 views
15

암호로 강력한 난수 생성 프로그램을 사용하는 PHP의 rand() 기능을 대체해야합니다.rand()를 openssl_random_pseudo_bytes()로 대체하십시오.

openssl_random_pseudo_bytes() 함수는 강력한 난수 생성기에 액세스 할 수 있지만 데이터를 바이트 문자열로 출력합니다. 대신 0에서 X 사이의 정수가 필요합니다.

키가 openssl_random_pseudo_bytes()의 출력을 정수로 얻는 것이라고 상상해보십시오. 그런 다음 필요한 모든 연산을 수행 할 수 있습니다. 나는 바이트 문자열에서 정수로 변환하는 몇 가지 "무차별적인"방법을 생각할 수 있지만 뭔가를 기대하고 있었다 ... 우아한.

+0

에는, mt_rand를()() (. 당신은 즉, 업그레이드 한 가정)하지만 중 하나를 강력하게 암호화 아니다. – David

+0

조심해서 대답하십시오. 보다 구체적으로 "% $ range"부분이 올바르지 않습니다. 다음 시나리오를 고려하십시오. 1부터 4까지의 숫자를 생성하고 싶습니다 (최대 - 최소 시간을 수행하기 때문에). $ 범위 = 3. 이제 3 1 3. 매우주의보다 더 많이 될 것입니다 것을 2^8 의미로 균등하게 분할하지 않습니다, 당신은 안전한 난수 생성기를 만들고 싶어하지만 실수가 불안했다, 이것은 왜 기존 구현을 사용하는 것이 좋습니다. – chacham15

+0

는 chacham15 @ : 제대로 이해하고, 8 비트 범위에서 당신은 "보다 출현하는"1 "에 대한 1.17 %의 가능성이있어 남은 [1,2,3] 플러스 하나 [1]의 85 개 세트를 얻을 수 2 "또는"3 ", 맞습니까? 이 문제를 어떻게 풀려고합니까? 분명히 * 기존 구현 *을 사용하는 것은 옵션이 아니거나 질문하지 않았을 것입니다. – tylerl

답변

11

, 나는 드롭을 만들었습니다 - OpenSSL을 사용하여 rand()를 대체했습니다. 나는 여기에 후손을 포함시킬 것이다.

$ 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; 
} 
+0

대체품으로 사용하기 위해 CryptoLib을 사용하는 방법에 대한 지침이 포함 된 답변을 추가했습니다. 이것은 훨씬 안전하며 (더 효율적인 코드를가집니다) 반복성 검사기를 제공합니다. – mjsa

+0

@mjsa 암호화 라이브러리가 훌륭하다고 확신하지만이 질문은 다른 라이브러리를 작성하라는 요청이 아닌 코드 자체의 메커니즘에 관한 것입니다. – tylerl

+0

이것은 나쁜 해결책이 아닙니다. 저는 PHP 7의'random_int()'를 PHP 5 프로젝트로 백 포트하는 것을 돕고 있습니다. 우리의 접근법은'$ max - $ min> PHP_INT_MAX'에서도 작동합니다. 당신은 [random_compat] (https://github.com/paragonie/random_compat) 자신의 관점에 무게를 좋아하면 아래 Github에서의 우리의 노력을 찾을 수 있습니다. –

8

openssl_random_pseudo_bytes()의 설명서 페이지에는 원하는 것으로 생각되는 예제가 있습니다. 의 출력에서 ​​bin2hex()을 호출하여 16 진수로 변환 한 다음 그 값에 대해 hexdec()으로 변환하여 10 진수로 변환하면됩니다.

$rand_num = hexdec(bin2hex(openssl_random_pseudo_bytes($length, $strong))); 

그 시점에서 원하는 범위의 값을 얻고 자하는 수학을 무엇이든 할 수 있습니다. 당신이 가질 수있는 다른 (치터) 옵션은 시스템 명령을 실행하여 임의의 숫자를 생성하는 것입니다 - 온라인에서 사용할 수있는 다양한 운영 체제 용 난수 생성기에 대한 몇 가지 좋은 옵션이 있습니다.

+0

이것은 완전히 질문에 대답하지 않습니다, 아래의 다른 답변을 참조하십시오. – Andrew

1

물론, openssl_random_pseudo_bytes의 결과에 hexdec를 사용하면 정수를 얻을 수 있습니다. 그것은이수록 :

print hexdec('45261b8f'); 

> 1160125327 
+0

rand가 최소값과 최대 값을 취하기 때문에 연산에 응답하지 않습니다.이 값은 난수를 반환합니다. – nate

+0

직접적으로는 아니지만 op를 직접 제공하는 솔루션에서 볼 수 있듯이이를 추가하는 것은 상당히 간단합니다. –

2

가 Heres는 재귀 함수를 사용하지 않습니다 위의 솔루션의 버전이 호출로 우아한 : 제공 제안을 사용

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; 
} 
-1
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; 
} 
0

이 작업을 수행하는 가장 쉬운 방법 (여기에 모든 옵션 중 가장 안전한)는 드롭 인 (drop-in) 랜드에 대한 대체를 제공하는 randomInt 기능이 CryptoLib을 사용하는 것입니다.

먼저 다운로드에서 CryptoLib 및 프로젝트에 스틱은 : https://github.com/IcyApril/CryptoLib

두,이 코드에 놓습니다.

<?php 
    require_once('path/to/cryptoLib.php'); 

    $min = 1; 
    $max = 5; 

    $randomNum = CryptoLib::randomInt($min, $max); 
?> 

CryptoLib 전체 문서에 있습니다 : : cryptolib.php의 디렉토리와 최소 및 최대 숫자와 최소 최대로/경로 /로 대체 https://cryptolib.ju.je/

2

PHP 7은 지금 당장 때문에, 이 문제를 해결하는 가장 쉬운 방법은 mt_rand의 모든 인스턴스를 random_int으로 바꾸는 것입니다.

랜드보다 훨씬 더 나은 품질의 임의의 숫자를 줄 것이다

관련 문제