PHP Bcrypt Salt as of 7.0

Tags: , ,



I am working on an application in which I have to compare 2 hashed passwords in a database, one password is being generated in PHP with $Password = password_hash($RawPassword, PASSWORD_BCRYPT); While the other password that is being sent to the database to compare with the PHP hashed password is generated in Java with String hashedPassword = BCrypt.hashpw(password); As of PHP 7.0 the salting is automatically generated, how can i know what salt is being applied in PHP so i can apply it to my java code? Or is there a way to still specify the salt that is no longer in the documentation for PHP Hashing?

Answer

The standard idea behind the vast majority of bcrypt impls is that the thing that is in the database looks like $2y$10$AB where A is 22 characters and B is 31 characters for a grand total of 60. A is: left(base64(salt + 00 + 00), 22) and B is: left(base64(bcryptraw(salt + pass)), 31). (2y refers to the hash algorithm/ EDIT: 2y and 2a are more or less interchangible; most bcrypt impls treat them the same, and it is unlikely to matter which one is there. The 10 refers to the # of bcrypt rounds applied. 10 is common and usually what you want).

where:

  • base64(X) = apply base64 conversion, using . and / as the 63rd and 64th char.
  • + is concatenate, i.e. salt (a 16-byte byte array) gets 2 zero bytes added.
  • left(chars, size) means: Take the first size chars and discard the rest.
  • salt is the salt in bytes and pass is the password, converted to bytes via UTF_8. (if not converting via UTF-8, it’s generally $2a$ instead, and you should upgrade, folks with non-ascii chars in their password get pretty bad hashes in the older $2a$ mode!

This one string contains everything that a bcrypt impl needs to check if a given password is correct or not. Thus, all non-idiotic bcrypt library impls have just two methods and no others:

// This is for when the user creates an account or edits their password.
// send the password to this method, then take the string it returns,
// and store this in your database.
hash = crypto.hashPass(password);

// This is for when the user tries to log in. For 'hash', send the thing
// that the hashPass method made for you.
boolean passwordIsCorrect = crypto.checkPass(password, hash);

EDIT: NB: A truly well designed crypto library calls these methods processNewPassword and checkExistingPassword to avoid the kind of confusion that caused you to ask this question, but unfortunately, nobody out there seems to have had the wherewithal to think for 5 seconds about what their names suggest. Unfortunate. Security is hard.

if your BCrypt API doesn’t work like this, get rid of it, and find a standard implementation that works like this.

It sounds like you’re using the wrong method. To check passwords, don’t use hashPass. Use checkPass, or whatever goes for checkPass in your impl (it might be called checkPw or verifyPw or validate, etcetera. It take 2 strings).

Thus, you should never generate a salt, nor ever extract a salt from such a string. Let the bcrypt lib do it. Those ‘hashes’ that standard bcrypt libraries generate (the $2y$ string) are interchangible; your PHP library can make em and your java library can check em, and vice versa.

If you MUST extract the salt (but don’t):

  • take those 22 characters, after the $protocol$rounds$ part.
  • append ‘aa’ to this.
  • base64decode the result.
  • this gets you 18 bytes. toss the last 2 bytes, which contain garbage.
  • The remaining 16 bytes are the salt.

You should absolutely not write this – your bcrypt library will do this.



Source: stackoverflow