PHP种子,确定性,密码安全PRNG(伪随机数发生器).可能吗?

com*_*ral 7 php security random cryptography numbers

我需要在PHP中创建一个可证明公平(确定性和种子)加密安全(CS)随机数生成器.我们正在运行PHP 5,而PHP 7现在还不是一个真正的选择.但是,我找到了PHP 7的新CS函数的polyfill,所以我实现了该解决方案(https://github.com/paragonie/random_compat).

我认为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 = '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>";
Run Code Online (Sandbox Code Playgroud)

运行此代码时,Drawing($ draw_str)在每次运行时都应该相同,但事实并非如此.

为了证明绘图是公平的,在挑选和显示获胜号码之前选择种子(种子A).还生成另一个随机数(种子B).将种子B用作盐并与种子A组合,并将结果进行哈希处理.在绘图之前向用户显示该哈希.他们还将获得源代码,以便在挑选获胜号码时,揭示两个种子.他们可以验证哈希匹配并且所有内容都公平地完成.

Sco*_*ski 5

Duskwuff 问:

你打算如何证明种子是公平选择的?可疑用户很容易声称您选择了一个可以为特定用户带来有利结果的种子,或者您提前向特定用户透露了该种子。

在研究解决方案之前,您要解决的问题究竟是什么?你的威胁模型是什么?


听起来像你想SeedSpring(版本0.3.0支持PHP 5.6)。

$prng = new \ParagonIE\SeedSpring\SeedSpring('JuxJ1XLnBKk7gPAS');
$byte = $prng->getBytes(16);
\var_dump(bin2hex($byte));
Run Code Online (Sandbox Code Playgroud)

这应该总是返回:

string(32) "76482c186f7c5d1cb3f895e044e3c649"
Run Code Online (Sandbox Code Playgroud)

这些数字应该是无偏见的,但由于它基于预先共享的种子,因此根据严格的定义,它在密码学上并不安全。

请记住,SeedSpring 是作为玩具实现/概念证明而不是官方 Paragon Initiative Enterprises 开源安全解决方案创建的,因此请随意对它进行分叉和调整以适合您的目的。(我怀疑我们的分支永远不会达到“稳定的 1.0.0 版本”)。

(此外,如果您要接受/奖励这些答案中的任何一个,Aaron Toponce 的答案更正确。使用 ECB 模式加密 nonce 比使用 AES-CTR 加密长的 NUL 字节流更高效,因为大致相同的安全优势。这是 ECB 模式可以正常运行的极少数情况之一。