PHP Seeded, a deterministic, cryptographically secure PRNG (pseudo random number generator). Is it possible?

I need to create an evidence-fair (deterministic and seed) cryptographically secure (CS) random number generator in PHP. We are running PHP 5, and PHP 7 is actually not an option. However, I found polyfill for PHP 7 new CS features, so I implemented this solution ( https://github.com/paragonie/random_compat ).

I thought srand () could be used for seed random_int (), but now I'm not sure if that is the case. Can CSPRNG be seeded? If it can be seeded, will the output be deterministic (same random result, given the same seed)?

Here is my code:

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 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $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>"; 

When this code is run, Drawing ($ draw_str) should be the same every time it is run, but it is not.

To prove the validity of the drawing, the seed (seed A) is selected before the winning number is selected and displayed. Another random number is also generated (seed B). Seed B is used as a salt and in combination with A seeds, and the result is hashed. This hash is displayed to the user before the drawing. They will also be provided with the source code so that when choosing a winning number both seeds are shown. They can verify that the hash matches, and everything has been done fairly.

+7
security php random numbers cryptography
source share
2 answers

Duskwuff asks:

How are you going to prove that the seed was rightly chosen? A suspicious user can easily claim that you have selected a seed that will produce a favorable result for specific users, or that you have previously shown the seed to specific users.

Before exploring solutions, what exactly is the problem you are trying to solve? What is your threat model?


It looks like you want SeedSpring (version 0.3.0 supports PHP 5.6 ).

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

This should always be returned:

 string(32) "76482c186f7c5d1cb3f895e044e3c649" 

The numbers should be objective, but since it is based on a pre-shared seed, it is not, by strict definition, cryptographically secure.

Keep in mind that SeedSpring was created as a toy implementation / proof of concept, and not an official open source Paragon Initiative Enterprises security solution, so feel free to deploy and customize it to your goals. (I doubt our branch will ever reach "stable version 1.0.0").

(In addition, if you intend to accept / reward generosity for any of these answers, Aaron Toponts answer is more correct. Nonce mode encryption with ECB is more efficient than encryption of a long stream of NUL bytes using AES-CTR, for about the same security advantage. This is one of the extremely rare cases where ECB mode is OK. )

+4
source share

First, you should not implement your own CSPRNG user space. The operating system on which PHP 5 is installed already has CSPRNG, and you should use this for all your chance if you don’t know that you can use it, or performance is a problem. You should use random_int() , random_bytes() or openssl_random_pseudo_bytes() .

However, if you must implement the CSPRNG user space, this can be done simply by using the AES library (EG: libsodium) and encrypting the counter. Psuedocode will be:

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

The AES key in this case needs enough entropy to withstand a complex attack, or the security of your CSPRNG user space falls apart, of course. The key may be the bcrypt() password provided by the user.

Provided that your counter, presented as a 128-bit unsigned integer, is always unique, you will always get a unique result each time the generator is "seeded" with a new counter. If it is seeded with a previously used counter, but with a different key, then the output will also be different. The best scenario is to change the key and the changing counter each time the generator is called.

You may be tempted to use a high-precision timestamp, for example, accurate to the microsecond, in your counter. This is normal, except that you risk someone or manipulate the system clock with something. Thus, if the watch can be manipulated, then the CSPRNG generator can be compromised. It is best to provide a new key every time you call the generator, and start encryption with 128-bit zero.

Also note that we use ECB mode with AES. Do not worry. The ECB has problems preserving the structure in ciphertext that provides plaintext. In general, you should not use ECB mode. However, with 128-bit data, you will only encrypt one ECB, so there will be no leakage of structured data. An ECB is preferable to a CTR for the CSPRNG user space, as you do not need to track the key, counter object, and data that needs to be encrypted. Only a key and data are required. Just make sure you never encrypt more than 128 bits of data, and you don't need more than 1 block.

Can CSPRNG be seeded?

Yes, and he must always be sown. If you look at your GNU / Linux operating system, you will probably notice the file in /var/lib/urandom/random-seed . When the operating system shuts down, it creates this file from CSPRNG. At the next boot, this file is used to seed the CSPRNG kernel to prevent reuse of the previous state of the generator. Each time you disconnect, this file should change.

If it can be seeded, will the output be deterministic (same random result, given the same seed)?

Yes. Provided the same seed, key, etc. The output is deterministic, so the output will be the same. If one of your variables changes, the result will be different. This is why the generator must be programmed with every call.

+5
source share

All Articles