代码之家  ›  专栏  ›  技术社区  ›  Exception e

salt包含在phpass哈希中还是需要对其输入进行salt?

  •  11
  • Exception e  · 技术社区  · 14 年前

    phpass 是一个广泛使用的哈希“框架”。

    $dynamicSalt   = $record['salt'];
    $staticSalt    = 'i5ininsfj5lt4hbfduk54fjbhoxc80sdf';
    $plainPassword = $_POST['password'];
    $password      = $plainPassword . $dynamicSalt . $staticSalt;
    
    $passwordHash = new PasswordHash(8, false);
    $storedPassword = $passwordHash->HashPassword($password);  
    

    参考phpsalt类:

    # Portable PHP password hashing framework.
    #
    # Version 0.2 / genuine.
    #
    # Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
    # the public domain.
    #
    #
    #
    class PasswordHash {
        var $itoa64;
        var $iteration_count_log2;
        var $portable_hashes;
        var $random_state;
    
        function PasswordHash($iteration_count_log2, $portable_hashes)
        {
            $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    
            if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
                $iteration_count_log2 = 8;
            $this->iteration_count_log2 = $iteration_count_log2;
    
            $this->portable_hashes = $portable_hashes;
    
            $this->random_state = microtime() . getmypid();
        }
    
        function get_random_bytes($count)
        {
            $output = '';
            if (is_readable('/dev/urandom') &&
                ($fh = @fopen('/dev/urandom', 'rb'))) {
                $output = fread($fh, $count);
                fclose($fh);
            }
    
            if (strlen($output) < $count) {
                $output = '';
                for ($i = 0; $i < $count; $i += 16) {
                    $this->random_state =
                        md5(microtime() . $this->random_state);
                    $output .=
                        pack('H*', md5($this->random_state));
                }
                $output = substr($output, 0, $count);
            }
    
            return $output;
        }
    
        function encode64($input, $count)
        {
            $output = '';
            $i = 0;
            do {
                $value = ord($input[$i++]);
                $output .= $this->itoa64[$value & 0x3f];
                if ($i < $count)
                    $value |= ord($input[$i]) << 8;
                $output .= $this->itoa64[($value >> 6) & 0x3f];
                if ($i++ >= $count)
                    break;
                if ($i < $count)
                    $value |= ord($input[$i]) << 16;
                $output .= $this->itoa64[($value >> 12) & 0x3f];
                if ($i++ >= $count)
                    break;
                $output .= $this->itoa64[($value >> 18) & 0x3f];
            } while ($i < $count);
    
            return $output;
        }
    
        function gensalt_private($input)
        {
            $output = '$P$';
            $output .= $this->itoa64[min($this->iteration_count_log2 +
                ((PHP_VERSION >= '5') ? 5 : 3), 30)];
            $output .= $this->encode64($input, 6);
    
            return $output;
        }
    
        function crypt_private($password, $setting)
        {
            $output = '*0';
            if (substr($setting, 0, 2) == $output)
                $output = '*1';
    
            if (substr($setting, 0, 3) != '$P$')
                return $output;
    
            $count_log2 = strpos($this->itoa64, $setting[3]);
            if ($count_log2 < 7 || $count_log2 > 30)
                return $output;
    
            $count = 1 << $count_log2;
    
            $salt = substr($setting, 4, 8);
            if (strlen($salt) != 8)
                return $output;
    
            # We're kind of forced to use MD5 here since it's the only
            # cryptographic primitive available in all versions of PHP
            # currently in use.  To implement our own low-level crypto
            # in PHP would result in much worse performance and
            # consequently in lower iteration counts and hashes that are
            # quicker to crack (by non-PHP code).
            if (PHP_VERSION >= '5') {
                $hash = md5($salt . $password, TRUE);
                do {
                    $hash = md5($hash . $password, TRUE);
                } while (--$count);
            } else {
                $hash = pack('H*', md5($salt . $password));
                do {
                    $hash = pack('H*', md5($hash . $password));
                } while (--$count);
            }
    
            $output = substr($setting, 0, 12);
            $output .= $this->encode64($hash, 16);
    
            return $output;
        }
    
        function gensalt_extended($input)
        {
            $count_log2 = min($this->iteration_count_log2 + 8, 24);
            # This should be odd to not reveal weak DES keys, and the
            # maximum valid value is (2**24 - 1) which is odd anyway.
            $count = (1 << $count_log2) - 1;
    
            $output = '_';
            $output .= $this->itoa64[$count & 0x3f];
            $output .= $this->itoa64[($count >> 6) & 0x3f];
            $output .= $this->itoa64[($count >> 12) & 0x3f];
            $output .= $this->itoa64[($count >> 18) & 0x3f];
    
            $output .= $this->encode64($input, 3);
    
            return $output;
        }
    
        function gensalt_blowfish($input)
        {
            # This one needs to use a different order of characters and a
            # different encoding scheme from the one in encode64() above.
            # We care because the last character in our encoded string will
            # only represent 2 bits.  While two known implementations of
            # bcrypt will happily accept and correct a salt string which
            # has the 4 unused bits set to non-zero, we do not want to take
            # chances and we also do not want to waste an additional byte
            # of entropy.
            $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    
            $output = '$2a$';
            $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
            $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
            $output .= '$';
    
            $i = 0;
            do {
                $c1 = ord($input[$i++]);
                $output .= $itoa64[$c1 >> 2];
                $c1 = ($c1 & 0x03) << 4;
                if ($i >= 16) {
                    $output .= $itoa64[$c1];
                    break;
                }
    
                $c2 = ord($input[$i++]);
                $c1 |= $c2 >> 4;
                $output .= $itoa64[$c1];
                $c1 = ($c2 & 0x0f) << 2;
    
                $c2 = ord($input[$i++]);
                $c1 |= $c2 >> 6;
                $output .= $itoa64[$c1];
                $output .= $itoa64[$c2 & 0x3f];
            } while (1);
    
            return $output;
        }
    
        function HashPassword($password)
        {
            $random = '';
    
            if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
                $random = $this->get_random_bytes(16);
                $hash =
                    crypt($password, $this->gensalt_blowfish($random));
                if (strlen($hash) == 60)
                    return $hash;
            }
    
            if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
                if (strlen($random) < 3)
                    $random = $this->get_random_bytes(3);
                $hash =
                    crypt($password, $this->gensalt_extended($random));
                if (strlen($hash) == 20)
                    return $hash;
            }
    
            if (strlen($random) < 6)
                $random = $this->get_random_bytes(6);
            $hash =
                $this->crypt_private($password,
                $this->gensalt_private($random));
            if (strlen($hash) == 34)
                return $hash;
    
            # Returning '*' on error is safe here, but would _not_ be safe
            # in a crypt(3)-like function used _both_ for generating new
            # hashes and for validating passwords against existing hashes.
            return '*';
        }
    
        function CheckPassword($password, $stored_hash)
        {
            $hash = $this->crypt_private($password, $stored_hash);
            if ($hash[0] == '*')
                $hash = crypt($password, $stored_hash);
    
            return $hash == $stored_hash;
        }
    }
    
    2 回复  |  直到 14 年前
        1
  •  32
  •   Exception e    14 年前

    这是原作者本人的回答:

    除了实际的散列,phpass透明地生成随机盐 键入、salt和密码并将其计数到 它返回的“哈希编码字符串”。当phpass验证 提取并使用哈希类型标识符、salt和迭代 用盐腌和伸展你自己-phpass照顾这些 你。

    底线:在“phpassing”之前先对密码加盐是没有意义的。

        2
  •  1
  •   Amber    14 年前

    你真的不需要两种盐(即静态盐是多余的;动态salt的主要目的是在hash被恶意方获取时防止rainbow表攻击,而动态salt的目的是进一步防止特殊情况下rainbow表生成同时破坏所有密码。

    除此之外,不管库是否内置了salt,salt都不会有什么坏处(尽管除非您向它传递的信息比要散列的项目更多,否则它实际上没有任何东西可以用作动态salt,所以很有可能是这样的 如果还不清楚的话,给你加盐)。