2016-02-06 4 views
7

मुझे PHP में क्रिप्टोग्राफ़िक रूप से सुरक्षित (सीएस) यादृच्छिक संख्या जेनरेटर बनाने के लिए एक प्रबल-निष्पक्ष (निर्धारक & बीजित) बनाने की आवश्यकता है। हम PHP 5 चला रहे हैं और PHP 7 अभी वास्तव में एक विकल्प नहीं है। हालांकि, मुझे PHP 7 के नए सीएस फ़ंक्शंस के लिए पॉलीफ़िल मिला है इसलिए मैंने उस समाधान को लागू किया है (https://github.com/paragonie/random_compat)।PHP बीजित, निर्धारक, क्रिप्टोग्राफ़िक रूप से सुरक्षित पीआरएनजी (छद्म यादृच्छिक संख्या जनरेटर)। क्या यह संभव है?

मैंने सोचा था कि srand() बीज random_int() के लिए इस्तेमाल किया जा सकता है, लेकिन अब मुझे यकीन नहीं है कि यह मामला है। क्या एक सीएसपीआरएनजी भी बीजित किया जा सकता है? यदि इसे बीज किया जा सकता है, तो क्या उत्पादन निर्धारक होगा (समान यादृच्छिक परिणाम, उसी बीज को दिया जाएगा)?

यहाँ मेरी कोड है:

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) प्रत्येक रन पर ही होना चाहिए, लेकिन यह नहीं है।

यह साबित करने के लिए कि ड्राइंग निष्पक्ष है, विजेता संख्या को चुनने और दिखाए जाने से पहले एक बीज (बीज ए) चुना जाता है। एक और यादृच्छिक संख्या भी उत्पन्न होती है (बीज बी)। बीज बी को नमक के रूप में प्रयोग किया जाता है और बीज ए के साथ जोड़ा जाता है और परिणाम धोया जाता है। यह हैश ड्राइंग से पहले उपयोगकर्ता को दिखाया गया है। उन्हें स्रोत कोड भी प्रदान किया जाएगा ताकि जब विजेता संख्या चुनी जाती है, तो दोनों बीज प्रकट होते हैं। वे सत्यापित कर सकते हैं कि हैश मैचों और सब कुछ काफी किया गया था।

+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" 

संख्या निष्पक्ष होना चाहिए, लेकिन क्योंकि यह एक पहले से शेयर की बीज पर आधारित है, यह नहीं, सख्त परिभाषा से, क्रिप्टोग्राफी द्वारा सुरक्षित है।

ध्यान रखें कि बीजिंग कार्यान्वयन एक आधिकारिक पैरागोन पहल उद्यमों के बजाय खुले स्रोत सुरक्षा समाधान के बजाय खिलौना कार्यान्वयन/अवधारणा के सबूत के रूप में बनाया गया था, इसलिए इसे अपने आप के लिए उपयुक्त बनाने के लिए स्वतंत्र महसूस करें। (मुझे संदेह है कि हमारी शाखा कभी भी "स्थिर 1.0.0 रिलीज" तक पहुंच जाएगी)।

(इसके अलावा, यदि आप इनमें से किसी भी उत्तर के लिए बक्षीस को स्वीकार/पुरस्कार देने जा रहे हैं, तो हारून टॉपोनस का जवाब अधिक सही है। ईसीबी मोड के साथ गैर-एन्क्रिप्ट करना एईएस के साथ एनयूएल बाइट्स की लंबी धारा को एन्क्रिप्ट करने से अधिक प्रदर्शनकारी है -सीटीआर, लगभग उसी सुरक्षा लाभ के लिए। यह अत्यंत दुर्लभ मौकों में से एक है कि ईसीबी मोड ठीक है।)

+0

यह देखने के लिए मेरे संपादन को देखें कि हम कैसे साबित करते हैं कि चित्रण काफी किया गया था। – compcentral

5

सबसे पहले, आपको अपना स्वयं का यूजर स्पेस सीएसपीआरएनजी लागू नहीं करना चाहिए। आपके पास PHP 5 स्थापित ऑपरेटिंग सिस्टम पहले से ही एक सीएसपीआरएनजी जहाज लगाता है, और आपको इसे अपने सभी यादृच्छिकता के लिए उपयोग करना चाहिए, जब तक कि आप जानते न कि आप इसका उपयोग कर सकते हैं, या प्रदर्शन एक चिंता है। आपको random_int(), random_bytes(), या openssl_random_pseudo_bytes() का उपयोग करना चाहिए।

हालांकि, यदि आपको उपयोगकर्ता स्पेस सीएसपीआरएनजी लागू करना होगा, तो यह केवल एईएस लाइब्रेरी (ईजी .: libsodium) का उपयोग करके किया जा सकता है, और काउंटर एन्क्रिप्ट कर सकता है। Psuedocode होगा:

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

वे कुंजी एईएस, इस मामले में, एक परिष्कृत आक्रमण का मुकाबला करने के लिए पर्याप्त एन्ट्रापी की जरूरत है, या अपने यूज़रस्पेस CSPRNG की सुरक्षा ज़ाहिर है, के अलावा गिर जाता है। कुंजी उपयोगकर्ता द्वारा प्रदत्त पासवर्ड के bcrypt() हो सकती है।

प्रदान किया गया है कि आपका काउंटर 128-बिट हस्ताक्षरित पूर्णांक के रूप में दर्शाया गया है, हमेशा अनूठा होता है, जब भी जनरेटर एक नए काउंटर के साथ "बीजित" होता है तो आपको हमेशा एक अद्वितीय आउटपुट मिल जाएगा। यदि यह पहले इस्तेमाल किए गए काउंटर के साथ बीजित है, लेकिन एक अलग कुंजी है, तो आउटपुट भी अलग होगा। सबसे अच्छा मामला परिदृश्य, जेनरेटर कहलाता है हर बार एक बदलती कुंजी और बदलते काउंटर होगा।

आप अपने काउंटर में उच्च परिशुद्धता टाइमस्टैम्प का उपयोग करने के लिए प्रेरित हो सकते हैं, जैसे कि माइक्रोसॉन्ड सटीकता का उपयोग करना। यह ठीक है, सिवाय इसके कि आप किसी के जोखिम या सिस्टम घड़ी में हेरफेर करने का जोखिम चलाते हैं। इस प्रकार, यदि घड़ी का उपयोग किया जा सकता है, तो सीएसपीआरएनजी जनरेटर से समझौता किया जा सकता है। जब भी आप जनरेटर को कॉल करते हैं, तो आप एक नई कुंजी प्रदान करने से सबसे अच्छे होते हैं, और 128-बिट शून्य के साथ एन्क्रिप्ट करना प्रारंभ करते हैं।

इसके अलावा, ध्यान दें कि हम एईएस के साथ ईसीबी मोड का उपयोग कर रहे हैं। बाहर निकलना मत करो। ईसीबी में सिफरटेक्स्ट में संरचना बनाए रखने में समस्याएं हैं जो सादा पाठ प्रदान करता है। सामान्य शब्दों में, आपको ईसीबी मोड का उपयोग नहीं करना चाहिए। हालांकि, डेटा के 128-बिट्स के साथ, आप केवल एक ईसीबी ब्लॉक एन्क्रिप्ट कर रहे होंगे, इसलिए संरचित डेटा की कोई रिसाव नहीं होगी। ईसीबी को एक उपयोगकर्ता स्पेस सीएसपीआरएनजी के लिए सीटीआर पर प्राथमिकता दी जाती है, क्योंकि आपको किसी कुंजी, काउंटर ऑब्जेक्ट और एन्क्रिप्टेड डेटा को ट्रैक रखने की आवश्यकता नहीं होती है। केवल एक कुंजी और डेटा की आवश्यकता है। बस सुनिश्चित करें कि आप डेटा के 128-बिट से अधिक एन्क्रिप्ट नहीं कर रहे हैं, और आपको कभी भी 1 से अधिक ब्लॉक की आवश्यकता नहीं होगी।

क्या एक सीएसपीआरएनजी भी बीजित किया जा सकता है?

हां, और इसे हमेशा बीजित किया जाना चाहिए। यदि आप अपने जीएनयू/लिनक्स ऑपरेटिंग सिस्टम को देखते हैं, तो आपको /var/lib/urandom/random-seed में एक फ़ाइल दिखाई देगी। जब ऑपरेटिंग सिस्टम बंद हो जाता है, तो वह उस फ़ाइल को सीएसपीआरएनजी से बनाता है। अगले बूट पर, जेनरेटर की पिछली स्थिति का पुन: उपयोग रोकने के लिए इस फ़ाइल का उपयोग कर्नलस्पेस सीएसपीआरएनजी को बीज करने के लिए किया जाता है। प्रत्येक शटडाउन पर, उस फ़ाइल को बदलना चाहिए।

यदि इसे बीज किया जा सकता है, तो क्या उत्पादन निर्धारिती (समान यादृच्छिक परिणाम, एक ही बीज दिया जाएगा) होगा?

हां। उसी बीज, कुंजी, आदि प्रदान किया गया, आउटपुट निर्धारक है, इसलिए आउटपुट वही होगा। यदि आपके चर में से कोई एक बदलता है, तो आउटपुट अलग होगा। यही कारण है कि जनरेटर के प्रत्येक कॉल पर दोबारा लगाया जाना चाहिए।

+0

आप पूरी तरह से बिंदु को याद करते हैं। यह कोड लॉटरी नंबर ड्राइंग के लिए है। केवल एकमात्र महत्वपूर्ण बात यह है कि उत्पादन एक चयनित बीज दिया जाता है (यह साबित करने के लिए कि चित्र उचित है)। मुझे यह जानने की ज़रूरत है कि यह संभव होने पर यह कैसे किया जाना चाहिए। मैं पहले से ही एक random_int() पॉलीफिल का उपयोग कर रहा हूं (यह PHP5 में मूल रूप से उपलब्ध नहीं है)।मुझे यकीन है कि यह दृश्यों के पीछे openssl_random_pseudo_bytes() का उपयोग कर रहा है लेकिन मैंने जांच नहीं की है। यह कोई चिंता नहीं है। जब तक पीआरएनजी सीएस नहीं है तब तक सुरक्षा वास्तव में महत्वपूर्ण नहीं है। – compcentral

+1

@comcentral आप यह साबित करना चाहते हैं कि बीज को चुना गया था? एक संदिग्ध उपयोगकर्ता आसानी से दावा कर सकता है कि आपने एक बीज चुना है जिसके परिणामस्वरूप विशिष्ट उपयोगकर्ताओं के लिए अनुकूल परिणाम होगा, या आपने समय से पहले विशिष्ट उपयोगकर्ताओं को बीज का खुलासा किया था। – duskwuff

+0

निष्पक्ष लॉटरी के लिए क्रिप्टोग्राफिक प्रोटोकॉल हैं जो उचित हैं यदि कम से कम एक प्रतिभागी ईमानदार है। –

संबंधित मुद्दे

 संबंधित मुद्दे