5

所以我在试验bcrypt。我有一个类(如下所示,我从http://www.firedartstudios.com/articles/read/php-security-how-to-safely-store-your-passwords获得),其中有 3 个功能。第一个是生成随机 Salt,第二个是使用第一个生成的 Salt 生成散列,最后一个是通过将提供的密码与散列密码进行比较来验证提供的密码。

<?php
/* Bcrypt Example */
class bcrypt {
    private $rounds;
    public function __construct($rounds = 12) {
        if(CRYPT_BLOWFISH != 1) {
            throw new Exception("Bcrypt is not supported on this server, please see the following to learn more: http://php.net/crypt");
        }
        $this->rounds = $rounds;
    }

    /* Gen Salt */
    public function genSalt() {
        /* openssl_random_pseudo_bytes(16) Fallback */
        $seed = '';
        for($i = 0; $i < 16; $i++) {
            $seed .= chr(mt_rand(0, 255));
        }
        /* GenSalt */
        $salt = substr(strtr(base64_encode($seed), '+', '.'), 0, 22);
        /* Return */
        return $salt;
    }

    /* Gen Hash */
    public function genHash($password) {
        /* Explain '$2y$' . $this->rounds . '$' */
            /* 2a selects bcrypt algorithm */
            /* $this->rounds is the workload factor */
        /* GenHash */
        $hash = crypt($password, '$2y$' . $this->rounds . '$' . $this->genSalt());
        /* Return */
        return $hash;
    }

    /* Verify Password */
    public function verify($password, $existingHash) {
        /* Hash new password with old hash */
        $hash = crypt($password, $existingHash);

        /* Do Hashs match? */
        if($hash === $existingHash) {
            return true;
        } else {
            return false;
        }
    }
}
/* Next the Usage */
/* Start Instance */
$bcrypt = new bcrypt(12);

/* Two create a Hash you do */
echo 'Bcrypt Password: ' . $bcrypt->genHash('password');

/* Two verify a hash you do */
$HashFromDB = $bcrypt->genHash('password'); /* This is an example you would draw the hash from your db */
echo 'Verify Password: ' . $bcrypt->verify('password', $HashFromDB);
?>

现在,例如,如果我使用“密码”生成哈希,我会得到一个哈希密码,该密码采用随机生成的 Salt。接下来,如果我再次输入“密码”并使用验证功能,我会得到密码匹配的真实含义。如果我输入错误的密码,我会得到错误的。我的问题是这怎么可能?那么随机生成的 Salt 呢?怎么一点效果都没有?

4

1 回答 1

15

好好看看你正在处理的价值观。生成的随机盐将是:

abcdefg...

输入的内容crypt如下所示:

crypt($password, '$2y$10$abcdefg...')
                   |  |    |
                   |  |    +- the salt
                   |  +- the cost parameter
                   +- the algorithm type

结果如下所示:

$2y$10$abcdefg...123456789...
 |  |    |        |
 |  |    |        +- the password hash
 |  |    +- the salt
 |  +- the cost parameter
 +- the algorithm type

换句话说,结果哈希的第一部分与crypt函数的原始输入相同;它包含算法类型和参数、随机盐和哈希结果。

Input:  $password + $2y$10$abcdefg...
Output:             $2y$10$abcdefg...123456789...
                    ^^^^^^^^^^^^^^^^^
                   first part identical

当您确认密码时,您需要再次使用相同的原始盐。只有使用相同的盐,相同的密码才会散列到相同的散列。它仍然存在于散列中,其格式可以按crypt原样传递,以重复与生成散列时相同的操作。这就是为什么您需要将密码和哈希都输入验证函数的原因:

crypt($passwordToCheck, '$2y$10$abcdefg...123456789...')

crypt获取第一个定义的字符数,直到并包括abcdefg...其余字符(这就是为什么盐需要是固定数量的字符)。因此它等同于与之前相同的操作:

crypt($passwordToCheck, '$2y$10$abcdefg...')

并且将生成相同的哈希,当且仅当 $passwordToCheck是相同的。

于 2013-05-24T13:33:55.093 回答