【问题标题】:How to get a cryptographically strong integer from 0-X in PHP?如何在 PHP 中从 0-X 获取加密强整数?
【发布时间】:2013-11-01 17:25:33
【问题描述】:

我想在 PHP 中生成随机的字母数字字符串。它们将用于随机数强度很重要的地方(URL 中公开可见的 ID 等)。

据我了解,在 PHP 中,加密强随机性的主要来源是 openssl_random_pseudo_bytes()。然而,这会返回一个字节数组,而不是字母数字字符。

要将它们转换为字母数字,我可以对它们进行哈希处理(这将产生一个长度超过必要的一组有限十六进制字符的字符串),或者base64_encode() 它们(这将产生一个带有+、@ 的字符串其中包含 987654324@ 和 = - 不是字母数字)。

所以我认为我可以使用随机字节作为熵源并生成我自己的字符串,该字符串仅包含字符 0-9a-zA-Z

然后问题就变成了 - 如何将 256 个不同的值(一个字节的输入)转换为 62 个不同的值(一个字符的输出)。在某种程度上,所有 62 个字符的可能性都相同。 (否则会有 8 个字符出现的频率高于其他字符)。

或者我应该完全使用另一种方法?我希望我的字符串尽可能短(比如说,20 个字符左右 - 更短的 URL 更好)并且只包含字母数字字符(这样它就不需要在任何地方特别转义)。

【问题讨论】:

    标签: php random


    【解决方案1】:

    您可以实现自己的 base64 编码。如果您可以允许两个特定符号 - 这些可以是任何符号,例如 .-,这并不重要。它甚至可以是其中一个的空间。无论如何,你会做的是:

    $alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-";
    // using . and - for the two symbols here
    $input = [123,193,21,13]; // whatever your input it, I'm assuming an array of bytes
    $output = "";
    foreach($input as $byte) {
        $output .= $alphabet[$byte%64];
    }
    

    假设随机输入,所有字符出现的概率相等。

    话虽如此,如果您不能允许除纯字母数字之外的任何内容,请从$alphabet 中删除符号并使用%62 而不是%64。虽然这确实意味着你对角色 07 有一点偏见,但我认为这并不重要。

    【讨论】:

      【解决方案2】:

      我在 php.net 的用户 cmets 中找到了这个函数。

           function crypto_rand($min,$max) {
               $range = $max - $min;
               if ($range == 0) return $min; // not so random...
               $length = (int) (log($range,2) / 8) + 1;
               return $min + (hexdec(bin2hex(openssl_random_pseudo_bytes($length,$s))) % $range);
           }
      

      然后做类似的事情

       for($i=0; $i<20; $i++)
        {
          $string.= chr(crypto_rand(1,26)+96); //or +64 for upper case
        }
      

      或类似的。

      【讨论】:

        【解决方案3】:

        注意:这是错误的!我留下这个尝试的答案仅供参考。

        (31 * 256) % 62 = 0

        对于每个输出的字母数字字符,生成 31 个随机值。将这 31 个值相加并取模 62。

        有点残酷,但这是我能想到的唯一“数学上正确”的选项:)

        【讨论】:

        • 如果遇到 248-255 范围内的字节,我会丢弃它们怎么办?这在数学上也正确吗?
        • @Vilx- 好吧,我无法确定,但似乎如此。这可能是一个更明智的选择:) 现在我意识到这可能是删除的答案的意思......
        • 嗯,我认为这实际上是非常错误的。想一想 - 如果你有两个骰子(标准 6 面),并且你掷出它们,最常见的总和将是 7。那是因为骰子有 6 种方式可以掷出“7”,而只有 1他们可以滚动获得“2”的方式。这里也一样。
        • 一个更好的类比是:一个骰子与两个骰子获得偶数的几率是多少(sum(dice)%2 = 0)。这两种情况的概率是相同的。不确定它是否仍然适用于三个骰子。我想我会在math.stackexchange.com 提问 :)
        • 我也有兴趣。 :) 你能给我一个链接到你的问题吗? :)
        猜你喜欢
        • 1970-01-01
        • 2011-11-10
        • 2011-06-28
        • 2021-05-30
        • 2011-03-20
        • 2020-02-29
        • 1970-01-01
        • 2021-10-17
        • 1970-01-01
        相关资源
        最近更新 更多