如何解密bcrypt存储的哈希值

问题描述 投票:0回答:6

我有一个加密密码的脚本,但我不知道如何反转它并解密它。这可能是一个非常简单的答案,但我不明白该怎么做。

#!/usr/bin/perl
use Crypt::Eksblowfish::Bcrypt;
use Crypt::Random;

$password = 'bigtest';
$encrypted = encrypt_password($password);
print "$password is encrypted as $encrypted\n";

print "Yes the password is $password\n" if check_password($password, $encrypted);
print "No the password is not smalltest\n" if !check_password('smalltest', $encrypted);

# Encrypt a password 
sub encrypt_password {
    my $password = shift;

    # Generate a salt if one is not passed
    my $salt = shift || salt(); 

    # Set the cost to 8 and append a NUL
    my $settings = '$2a$08$'.$salt;

    # Encrypt it
    return Crypt::Eksblowfish::Bcrypt::bcrypt($password, $settings);
}

# Check if the passwords match
sub check_password {
    my ($plain_password, $hashed_password) = @_;

    # Regex to extract the salt
    if ($hashed_password =~ m!^\$2a\$\d{2}\$([A-Za-z0-9+\\.]{22})!) {
        return encrypt_password($plain_password, $1) eq $hashed_password;
    } else {
        return 0;
    }
}

# Return a random salt
sub salt {
    return Crypt::Eksblowfish::Bcrypt::en_base64(Crypt::Random::makerandom_octet(Length=>16));
}
perl bcrypt
6个回答
205
投票

您正在散列,而不是加密!

有什么区别?

区别在于哈希是一种单向函数,而加密是一种双向函数。

那么,如何确定密码是否正确呢?

因此,当用户提交密码时,您不会“解密”存储的哈希值,而是对用户输入执行相同的 bcrypt 操作并比较哈希值。如果它们相同,则您接受身份验证。


您应该对密码进行散列还是加密吗?

您现在所做的(对密码进行哈希处理)是正确的。如果您只是对密码进行加密,那么应用程序安全性的破坏可能会让恶意用户轻松获知所有用户密码。如果您对密码进行散列(或者更好,

盐和散列

),用户需要破解密码(这在bcrypt上的计算成本很高)才能获得这些知识。


由于您的用户可能在多个地方使用他们的密码,这将有助于保护他们。


4
投票

换句话说,您将运行一个程序来读取大量潜在密码(密码字典),然后使用

bcrypt

以及您尝试破译的密码的盐值和复杂性对每个密码进行哈希处理。如果幸运的话,您会找到匹配项,但如果密码强度较高,那么您可能找不到匹配项。


Bcrypt

具有缓慢哈希的附加安全特性。如果您的密码已使用 md5 进行哈希处理(糟糕的选择),那么您每秒可以检查数十亿个密码,但由于它是使用

bcrypt
进行哈希处理,您每秒可以检查的次数要少得多。

事实上,

bcrypt

的哈希和加盐速度很慢,这使得它即使在今天也是密码存储的一个不错的选择。话虽这么说,我相信

NIST
推荐使用
PBKDF2
进行密码哈希处理。


4
投票
你根本做不到

bcrypt

用盐腌制,不同轮数,我一般用10个。

bcrypt.hash(req.body.password,10,function(error,response){ });

这 10 将随机字符串加盐到您的密码中。


0
投票

例如:

public function updateUser(Request $req) { $entityManager = $this->getDoctrine()->getManager(); $repository = $entityManager->getRepository(User::class); $user = $repository->find($req->get(id)); // get User from your DB if($user == null){ throw $this->createNotFoundException('User doesn\'t exist!!', $user); } $password_old_encrypted = $user->getPassword();//in your DB is always encrypted. $passwordToUpdate = $req->get('password'); // not encrypted yet from request. $passwordToUpdateEncrypted = password_hash($passwordToUpdate , PASSWORD_DEFAULT); // VERIFY IF IT'S THE SAME PASSWORD $isPass = password_verify($passwordToUpdateEncrypted , $password_old_encrypted ); if($isPass === false){ // failure throw $this->createNotFoundException('Your password is not valid', null); } return $isPass; // true!! it's the same password !!! }



-1
投票

password_verify ( string $password , string $hash ) : bool

更多详情:

https://www.php.net/manual/en/function.password-verify.php


-1
投票
© www.soinside.com 2019 - 2024. All rights reserved.