PHP crypt产生不同的结果

时间:2013-08-05 18:32:19

标签: php crypt

好吧,我坐在这里,因为几个小时在这个问题上摸不着头脑,我无法弄清楚出了什么问题。我试图通过随机盐加密密码加密密码,但当我尝试登录时,总是错误。

让我带您完成脚本:

$cost = 10;
$salt = strtr(base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM)), '+', '.');
$salt = sprintf("$2y$%02d$", $cost) . $salt;
$hash = crypt($password, $salt);

echo $hash;
echo crypt($password, $hash);

输出以下密码为'asdfgh':

$2y$10$865uru.sXJheD9TQKLDnZuTZfpAXv83UDuaSFfb.G2qIxBzEb1pOi
$2y$10$865uru.sXJheD9TQKLDnZuTZfpAXv83UDuaSFfb.G2qIxBzEb1pOi

数据库中的哈希值如下所示:

$2y$10$865uru.sXJheD9TQKLDnZuTZfpAXv83UDuaSFfb.G2qIxBzEb1pOi

对于登录脚本,我们有以下代码用于测试目的:

echo $data->hash . '<br>';
echo crypt('asdfgh', $data->hash) . '<br>';
echo crypt('asdfgh', '$2y$10$865uru.sXJheD9TQKLDnZuTZfpAXv83UDuaSFfb.G2qIxBzEb1pOi');

并输出以下内容:

$2y$10$865uru.sXJheD9TQKLDnZuTZfpAXv83UDuaSFfb.G2qIxBzEb1pOi
$2y$10$865uru.sXJheD9TQKLDnZuRRPJQwjWh2PGgtntpcsnRaGzvv5Sfte
$2y$10$865uru.sXJheD9TQKLDnZuRRPJQwjWh2PGgtntpcsnRaGzvv5Sfte

虽然数据库字符串仍然正确,但即使手动将正确的字符串传递给函数,生成的哈希也是不同的。我没有解决方案......

如果有人能帮助我,我会非常感激。

Windows上的PHP版本5.4.16

更新: 以下是盐的更新片段:

$cost = 10;
$salt = strtr(base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM)), '+', '.');
$salt = sprintf("$2y$%02d$", $cost) . $salt;
$hash = crypt($password, $salt);

$data = array(
    'id' => '',
    'username' => $username,
    'hash' => $hash,
    'email' => $email,
    'salt' => $salt,
);

$this->mdl_registration->_insert($data);
$this->load->view('registration_submit');

对于登录脚本:

function check_login($password) {
    $username = $this->input->post('username');
    $result = $this->get_where_custom('username', $username);
    foreach($result->result() as $data) {
        echo $data->hash . '<br>';
        echo crypt('asdfgh', $data->salt) . '<br>';
        $test = crypt($password, $data->salt);
        if($test == $data->hash) {
            return TRUE;
        }
        else {
            $this->form_validation->set_message('check_login', 'Invalid Username and / or Password');
            return FALSE;
        }
    }
}

用于测试目的的回声返回以下内容:

$2y$10$ZgbOXM18lArDu/u/Ftsdr.t7VPnLsqLJdC2Dum8pl/flW8LmnnUoS
$2y$10$ZgbOXM18lArDu/u/Ftsdr.s5N5juHB/zq/5SN/7oFAjn9CZKjI9H6

2 个答案:

答案 0 :(得分:0)

好吧,我的回答并没有真正解决为什么这段代码不起作用。我认为这是因为没有通过$ salt,但只要盐在提供的crypt()范围内,$hash显然是{...}}的原因...

无论如何,我可以建议一种替代方法来实现这一目标。随意忽略这一点,等待解决方案,或适应这一点。由你决定。

$password = 'asdfgh';
$salt = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647));
$hash = hash('sha256', $password . $salt);
for($round = 0; $round < 60000; $round++)
{
    $hash = hash('sha256', $hash . $salt);
}

这会稍微不同地创建salt,使用不同的散列算法并且还遍历散列60,000次(对于用户1-2秒来说相对较短)。

将$ salt与$ hash一起存储在数据库中。

现在,对于登录脚本,只需包含此代码段...

(假设$ password是&#39; asdfgh&#39;)

$newHash = hash('sha256', $password . $salt);
for($round = 0; $round < 60000; $round++)
{
    $newHash = hash('sha256', $newHash . $salt);
}
if($newHash===$data->hash){
  //Match!
}

我尝试使用几个不同的数据集,并且哈希总是匹配,所以你可以使用它。

或者您可以等待真正的安全专家来解释您的代码无法正常工作的原因:)

希望这有帮助!

答案 1 :(得分:0)

您的盐格式错误。

根据docs

  

CRYPT_BLOWFISH - 用下面的盐对河豚进行散列:“$ 2a $”,“$ 2x $”或“$ 2y $”,两位数的成本参数“$”,字母表中的22个字符“./ 0-9A-ZA-Z”。

你的盐有a)无效字符(=作为填充字符在base64的末尾)和b)太长(24个字符而不是22个字符)。

这可能是您遇到问题的原因。