2016-02-06 25 views
7

我需要在PHP中創建一個證明性公平的(確定性的&種子)密碼安全(CS)隨機數生成器。我們正在運行PHP 5,而PHP 7現在不是真正的選擇。但是,我發現了PHP 7的新CS功能的填充,所以我實現了該解決方案(https://github.com/paragonie/random_compat)。PHP種子,確定性,密碼安全的PRNG(僞隨機數生成器)。可能嗎?

我認爲srand()可以用來種子random_int(),但現在我不確定如果是這種情況。 CSPRNG甚至可以播種嗎?如果可以播種,輸出是否是確定性的(相同的隨機結果,給定相同的種子)?

這裏是我的代碼:

require_once($_SERVER['DOCUMENT_ROOT']."/lib/assets/random_compat/lib/random.php"); 

$seed_a = 8138707157292429635; 
$seed_b = 'JuxJ1XLnBKk7gPASR80hJfq5Ey8QWEIc8Bt'; 

class CSPRNG{ 
    private static $RNGseed = 0; 

    public function generate_seed_a(){ 
     return random_int(0, PHP_INT_MAX); 
    } 

    public function generate_seed_b($length = 35){ 
     $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
     $randomString = ''; 
     for($i = 0; $i < $length; $i++){ 
      $randomString .= $characters[random_int(0, strlen($characters) - 1)]; 
     } 
     return $randomString; 
    } 

    public function seed($s = 0) { 
     if($s == 0){ 
      $this->RNGseed = $this->generate_seed_a(); 
     }else{ 
      $this->RNGseed = $s; 
     } 
     srand($this->RNGseed); 
    } 

    public function generate_random_integer($min=0, $max=PHP_INT_MAX, $pad_zeros = true){ 
     if($this->RNGseed == 0){ 
      $this->seed(); 
     } 
     $rnd_num = random_int($min, $max); 
     if($pad_zeros == true){ 
      $num_digits = strlen((string)$max); 
      $format_str = "%0".$num_digits."d"; 
      return sprintf($format_str, $rnd_num); 
     }else{ 
      return $rnd_num; 
     } 
    } 

    public function drawing_numbers($seed_a, $num_of_balls = 6){ 
     $this->seed($seed_a); 
     $draw_numbers = array(); 
     for($i = 0; $i < $num_of_balls; $i++) { 
      $number = ($this->generate_random_integer(1, 49)); 
      if(in_array($number, $draw_numbers)){ 
       $i = $i-1; 
      }else{ 
       array_push($draw_numbers, $number); 
      } 
     } 
     sort($draw_numbers); 
     return $draw_numbers; 
    } 
} 

$CSPRNG= new CSPRNG(); 

echo '<p>Seed A: '.$seed_a.'</p>'; 
echo '<p>Seed B: '.$seed_b.'</p>'; 
$hash = hash('sha1', $seed_a.$seed_b); 
echo '<p>Hash: '.$hash.'</p>'; 

$drawNumbers = $CSPRNG->drawing_numbers($seed_a); 
$draw_str = implode("-", $drawNumbers); 
echo "<br>Drawing: $draw_str<br>"; 

當這個代碼運行,繪圖($ draw_str)應在每次運行相同的,但事實並非如此。

爲了證明圖紙是公平的,在挑選和顯示獲獎號碼之前選擇種子(種子A)。還生成另一個隨機數(種子B)。種子B用作鹽並與種子A結合,結果被散列。該散列在繪圖之前向用戶顯示。他們也會被提供源代碼,以便在挑選中獎號碼時顯示兩個種子。他們可以驗證哈希匹配和一切都相當公平。

+1

你的意思是像https://github.com/paragonie/seedspring? –

+0

是的,但需要PHP 7.不是一個選項。 – compcentral

+0

我可以很容易地調整composer.json來要求^ 5.6 |^7.0和random_compat:\ –

回答

4

Duskwuff問:

你如何打算證明種子還算選擇?可疑用戶可以輕易聲稱您選擇了能夠爲特定用戶帶來有利結果的種子,或者您提前向特定用戶顯示種子。

在調查解決方案之前,您試圖解決的問題到底是什麼?你的威脅模型是什麼?


聽起來像你想SeedSpring(版本0.3.0支持PHP 5.6)。

$prng = new \ParagonIE\SeedSpring\SeedSpring('JuxJ1XLnBKk7gPAS'); 
$byte = $prng->getBytes(16); 
\var_dump(bin2hex($byte)); 

應該始終返回:

string(32) "76482c186f7c5d1cb3f895e044e3c649" 

的數字應該是公正的,但由於它是基於關閉預共享的種子,它不是通過嚴格的定義,密碼安全。

請記住,SeedSpring是作爲一個玩具實現/概念證明而不是官方的Paragon Initiative Enterprises開源安全解決方案創建的,所以請隨意分叉並調整以適應您的目的。 (我懷疑我們的分支會達到「穩定的1.0.0版本」)。 (另外,如果你打算接受/獎勵這些答案中的任何一個,那麼Aaron Toponce的答案會更加正確。使用ECB模式加密隨機數比使用AES加密長NUL字節流的性能更高效-CTR,幾乎具有相同的安全優勢這是ECB模式可以使用的極其罕見的場合之一

+0

看看我的編輯,看看我們如何證明繪圖是公平的。 – compcentral

5

首先,你不應該實現你自己的用戶空間CSPRNG。您安裝PHP 5的操作系統已經發布了CSPRNG,您應該將其用於所有的隨機性,除非您知道可以使用它,否則性能是一個問題。您應該使用random_int(),random_bytes()openssl_random_pseudo_bytes()。但是,如果您必須實現用戶空間CSPRNG,那麼可以通過簡單地使用AES庫(E.G .: libsodium)和加密計數器來完成此操作。僞代碼將是:

Uint-128 n = 0; 
while true: 
    output = AES-ECB(key, n); 
    n++; 

他們AES密鑰,在這種情況下,需要有足夠的熵承受複雜的攻擊,或者你的用戶空間CSPRNG的安全分崩離析,當然。密鑰可以是用戶提供的密碼的bcrypt()

如果您的計數器表示爲128位無符號整數始終是唯一的,那麼每當發生器使用新計數器「播種」時,您將始終獲得唯一的輸出。如果它使用先前使用的計數器播種,但使用不同的鍵,則輸出也會不同。最好的情況是,每次調用發生器時,它都是一個改變的鍵和一個不斷變化的計數器。

您可能很想在計數器中使用高精度時間戳,例如使用微秒精度。這很好,除非你冒着某人或某事操縱系統時鐘的風險。因此,如果時鐘可以被操縱,那麼CSPRNG發生器可能會受到影響。每次調用生成器時,最好提供一個新密鑰,並開始使用128位零進行加密。

此外,請注意我們正在使用ECB模式和AES。別嚇壞了。 ECB在維護明文提供的密文結構方面存在問題。一般而言,您不應該使用ECB模式。但是,對於128位數據,您只能對單個ECB塊進行加密,因此不會泄漏結構化數據。因爲您不必跟蹤密鑰,計數器對象和要加密的數據,所以ECB比用戶空間CSPRNG的CTR更受歡迎。只需要一個密鑰和數據。只要確保你永遠不會加密多於128位的數據,並且你永遠不會需要超過1個塊。

CSPRNG甚至可以播種嗎?

是的,它應該始終播種。如果你看看你的GNU/Linux操作系統,你可能會注意到一個文件/var/lib/urandom/random-seed。當操作系統關閉時,它將從CSPRNG創建該文件。在下次啓動時,這個文件被用來爲內核空間CSPRNG播種,以防止重複使用生成器的先前狀態。在每次關機時,該文件都應該改變。

如果它可以播種,輸出是確定性的(相同的隨機結果,給定相同的種子)?

是的。提供相同的種子,密鑰等,輸出是確定性的,所以輸出將是相同的。如果其中一個變量發生變化,那麼輸出將會不同。這就是爲什麼發電機的每次調用都應該重新生成密鑰。

+0

你完全錯過了這一點。此代碼用於繪製彩票號碼。唯一真正重要的是,給定的種子的輸出是相同的(證明繪圖是公平的)。如果可能的話,我需要知道如何做到這一點。我已經使用了random_int()填充(它在PHP5中本身不可用)。我很確定它在幕後使用openssl_random_pseudo_bytes(),但我沒有檢查。這沒有關係。只要PRNG是CS,安全性並不重要。 – compcentral

+1

@compcentral你打算如何證明種子選擇合理?可疑用戶可以輕易聲稱您選擇了能夠爲特定用戶帶來有利結果的種子,或者您提前向特定用戶顯示種子。 – duskwuff

+0

如果至少有一位參與者是誠實的,那麼公平彩票的加密協議是公平的。 –

相關問題