Encryption with bcrypt + random salt

3

I have a simple question about encryption using bcrypt with salt.

When in old projects I used md5, to verify in a login form if the user entered the correct password and to authenticate, it was usual to take the value that the user typed and to encrypt in md5 and to look for in the bd. >

But as in bcrypt using random salt does not do it, then I did the following:

I get the email or cpf that the user typed in the login field, I look for in the bd the corresponding record and I use the password stored in the bd (hash) as salt and the password entered by the user as the string in the crypt function ($ string, $ salt) and return the function compared with the password stored in bd, and by logic the function must generate exactly the hash itself.

Follow a piece of my code just so you can better understand what I'm talking about

 //Exemplo da busca com cpf
 $buscar = $con->prepare("SELECT * FROM usuarios WHERE cpf =:cpf");
 $buscar->bindValue(":cpf", $login);
 $buscar->execute();
 $row = $buscar->fetch();

 //Armazena a senha que esta no bd
 $senha_armazenada = $row['senha'];

 //Comparação que estou fazendo
 if(crypt($senha_digitada, $senha_armazenada) === $senha_armazenada)

And that's working, but I want to know if it's the right way to do it.

    
asked by anonymous 26.09.2017 / 19:59

2 answers

3

First, never do this:

if(crypt($senha_digitada, $senha_armazenada) === $senha_armazenada)

Any string is a secret should never be compared using == or === , this is not constant time and exposes timming-attack . This does not occur if you use password_verify() and hash_equals .

The salt is generated inside of the function itself, even they already inform you that setting a custom salt is" deprecated ". I will not even go into the merits of why they did it.

When you do:

password_hash('senha_legal', PASSWORD_BCRYPT, ['cost' => 15])

The function itself obtains a safe salt (from a secure PRNG) and derives the key based on the defined force. There is no need for you to generate a salt, because the chance of you doing it wrong (using rand() , mt_rand() or even time() ) is much higher.

In PHP 7.2 there is PASSWORD_ARGON2I , which uses Argon2i (winner of PHC) instead of BCrypt, in this case use:

password_hash('senha_legal', PASSWORD_ARGON2I, ['memory_cost' => 1<<18, 'time_cost' => 4, 'threads' => 4])

You can also use sodium_crypto_pwhash_str() which also uses Argon2i, it is already available since you install PECL.

In addition, make sure that the password entered by the user does not have 0x00 (null bytes), otherwise this var_dump(password_verify('a', password_hash(pack('H*', '6100626364'), PASSWORD_DEFAULT))); will return true , as I have already used as an example in other answers.

    
26.09.2017 / 21:12
1

From what I've seen, it's correct, yes, but it's better. I recommend you first look at what you did at this link:

link

and a more up-to-date solution is at this link, using an api of php :

link

Sorry, I did not explain it here yet, but I found these articles the other day and have not yet implemented.

    
26.09.2017 / 20:45