laravelmeteorhashbcrypt

Laravel & Meteor password hashing


I have two applications, one in Laravel 5.2 and one in Meteor. I want to collect hashes for passwords which are compatible with both platforms.

The database stores the hashes separately

Both platforms use bcrypt with 10 rounds by default, but Meteor appears to sha256 the plain password before bcrypt.

If Meteor creates password hash abc, I can sha256 the plain password, and compare it with abc using Laravel's internals, i.e. Auth::attempt()

$sha256 = hash('sha256', $request->get('password'), false);

This works. Laravel successfully authenticates the user.

However, if I register a new user in Laravel, and store the hash meteor_password, when authenticating against that hash in Meteor, it fails with the error message "Login Forbidden". This error appears to be mean incorrect credentials.

I'm creating the hash in the same way as I did when I verified it in Laravel.

$meteor_password = bcrypt(hash('sha256', $plain, false));

It seems strange that it'd work one way and not the other so I assume I'm missing something.


Solution

  • In 2011, a bug was discovered in PHP's BCrypt implementation, so they changed the original 2a version indicator to 2x and 2y, which is used today, to indicate that the password was hashed by the fixed version.

    Then, in 2014, a bug in GNU bcrypt caused it to change its version from 2a to 2b.

    Anyway, the salt/hash segments generated by PHP with the 2y version should generally be compatible with the 2b version generated by the npm bcrypt package that is used by Meteor (and also to the outdated 2a version that was created by bcrypt before 2014).

    The version segment should be changed in order to be correctly processed by the NPM module, as it does not acknowledge 2y.

    $meteor_password = bcrypt(hash('sha256', $plain, false));
    // replace it useing something like:
    $meteor_password = preg_replace('/^\$2y/', '\$2b', $meteor_password);
    // or
    $meteor_password[2] = 'b';