帮我理解pack(),openssl_random_pseudo_bytes()和mt_rand()来保存密码

时间:2011-02-10 00:32:59

标签: php algorithm random salt

我正在构建一个拥有用户群的应用程序,而我正在确保登录安全。我是编程(和PHP)的新手,但到目前为止我的努力已经指向使用Crypt()和Blowfish哈希盐。

在我走得更远之前,让我在此时指明我对phpass 不感兴趣。

crypt()文档中,用户最近发布了这个:

<?php 
   $salt = substr(str_replace('+', '.', base64_encode(pack('N4', mt_rand(), mt_rand(), mt_rand(), mt_rand()))), 0, 22); 
?>
  

它适用于系统   其中mt_getrandmax()== 2147483647。

     

创建的盐将是128位   长度,填充到132位然后   表示为22个base64个字符。   (CRYPT_BLOWFISH仅使用128位   盐,即使有132   22个base64字符的位。如果你   检查CRYPT_BLOWFISH输入和   输出,你可以看到它忽略了   输入的最后四位和设置   它们在输出上为零。)

     

注意,高阶位   返回的四个32位双字   mt_rand()将始终为零(因为   mt_getrandmax == 2 ^ 31),所以只有124   128位将是伪随机的。一世   发现我可以接受   应用

我测试了我的服务器,确实mt_getrandmax()返回2147483647.我尝试了解文档以了解上面代码的真正作用 - pack()代码N4用于32位字符串(大端)字节顺序??重复4次...我假设这就是为什么有4个mt_rand()参数。

我不明白为什么他用+替换.以及22 base64字符的目的(不是我完全理解base64是什么。)

建议我查看openssl_random_pseudo_bytes()我的随机盐生成,因为我之前看到的方法仅限于1234567890abcdefghijklmnopqrstuvwxyz

据说有一个错误5.3.4导致openssl_random_pseudo_bytes()运行缓慢,偶尔会导致超时错误。我不确定是否应该尝试openssl_random_pseudo_bytes()使用Crypt()或类似上述方法使用mt_rand()pack()

我试图更多地了解所有这些元素是如何工作的,以及它们在概念上做了什么 - 而不是仅仅使用一个而不理解它来实现我的目标;我正在努力学习:P

有人可以帮助我理解这里工作的不同元素,或者至少指引我到知识库,在那里我可以阅读它吗?我认为最常见的组件是理解不同的格式/术语(base64,ascii,hexdec,bit,byte等),但最后还是如何实现与我的密码一起使用的相当安全的盐。

1 个答案:

答案 0 :(得分:11)

首先我要说的是,从生成的角度来看,盐没有什么特别之处。这只是另一个随机字符串。它的使用方式很特别,但没有生成。

您的具体问题

  1. 他为什么用+替换.

    我不知道。也许是因为+字符可能与网址中的空格混淆。但是盐永远不应该在网址中,所以很可能不是。

  2. base64 / hexdec做什么:

    Base64将原始字节流(每个字节的值从0到255)转换为基本64表示。它有很多资源,所以不值得深入研究。请阅读the wikipedia article以获取更多信息。

    hexdec将十六进制数(a-f0-9)转换为十进制数。它从基数16转换为基数10(只是表示数字的另一种方式)。

  3. 什么是位和字节:

    有点是一个单位的信息。它有2个状态,0或1.字节是一系列8位。所以一个字节可以有256个唯一的组合。阅读Wikipedia ...

  4. 什么是ascii

    这是一个字符集。它表示单个8位字节中的单个可打印字符。我再次建议阅读Wikipedia

  5. 一般盐类

    良好的盐生成功能的目标是大熵。这意味着可能的输出数量尽可能大。所以任何方法都应该产生大量的结果。

    现在,您需要定义salt的可接受字符(因为您需要存储salt以验证哈希)。最好的盐是全字节数字,而不仅仅是可显示的字符。现在,您将无法在有意义的庄园中显示它,但您无需显示它。另外,对于存储,您始终可以使用base64_encode

    接下来,您需要选择盐的浓度。盐越大越好。可以接受32个字符的盐,但是128个字符的盐更好。盐的大小和每个字符的选项数量将决定可能的数量。一些常见的组合:

    Hex, 32 characters: 2e38 possibilities
    Hex, 128 characters: 1e154 possibilities
    Full Byte, 32 characters: 1e77 possibilities
    Full Byte, 128 characters: 1e308 possibilities
    

    现在,您需要生成盐。关键是要根据需要进行多次随机调用以填写熵。您可以通过以下几种方式实现这一目标:

    • 系统相关(仅适用于* nix但最佳熵):

      $f = fopen('/dev/urandom', 'r');
      $seed = fgets($f, $characters); // note that this will always return full bytes
      fclose($f);
      
    • 依赖于库(很好,但需要安装OpenSSL)

      $seed = openssl_random_pseudo_bytes($characters);
      
    • 回退

      $seed = '';
      for ($i = 0; $i < $characters; $i++) {
          $seed .= chr(mt_rand(0, 255));
      }
      

    现在,您需要将其转换为所需的输出格式。

    • 十六进制(a-f0-9):

      $out = '';
      for ($i = 0, $len = strlen($seed); $i < $len; $i++) {
          $num = ord($seed);
          $out .= dechex(floor($num / 16)) . dechex($num % 16);
      }
      
    • Base36(a-z0-9):

      $out = '';
      for ($i = 0, $len = strlen($seed); $i < $len; $i++) {
          $num = ord($seed);
          $out .= base_convert($num, 10, 36);
      }
      
    • Base64(a-zA-Z0-9 + =):

      $out = base64_encode($seed);
      
    • 完整字节:

      没有必要,因为它已经采用这种格式。

相关问题