How to use SHA1 encryption instead of BCrypt in Laravel 4?

It took me a lot of time to get something similar happening in Laravel 5.6 but this thread was invaluable. The accepted answer gets you very close but there are still some ambushes along the way (as can be seen in the comments) so instead of struggling with the comments I thought it would be helpful for others to have it presented as an answer.

In my case I needed to access an existing database and couldn't change the user file. The passwords were saved in SHA256 format with a hash key applied as well. So the objective for me was to really only get the check function working.

I'm really new to Laravel and I know there will be a better way around this issue but I couldn't get the app\Libraries area to register so I put both SHAHasher.php and SHAHashServiceProvider.php into app\Providers which I would assume is some sort of Laravel sacrilege but it was the only way I got it to work. :)

The steps I took (hijacking rmobis's excellent answer for Laravel 4) was:

The hash key used in the original app needed to be accessed by Laravel so I added this to the bottom of .env.

.env

...
HASH_KEY=0123_key_code_added_here_xyz

app/Providers/SHAHasher.php

namespace App\Providers;

use Illuminate\Contracts\Hashing\Hasher;

class SHAHasher implements Hasher
{

  /**
   * Get information about the given hashed value.
   * TODO: This was added to stop the abstract method error.
   *
   * @param  string  $hashedValue
   * @return array
   */
  public function info($hashedValue)
  {
    return password_get_info($hashedValue);
  }

  /**
   * Hash the given value.
   *
   * @param  string $value
   * @return array   $options
   * @return string
   */
  public function make($value, array $options = array())
  {
    // return hash('sha1', $value);
    // Add salt and run as SHA256
    return hash_hmac('sha256', $value, env('HASH_KEY'));
  }

  /**
   * Check the given plain value against a hash.
   *
   * @param  string $value
   * @param  string $hashedValue
   * @param  array $options
   * @return bool
   */
  public function check($value, $hashedValue, array $options = array())
  {
    return $this->make($value) === $hashedValue;
  }

  /**
   * Check if the given hash has been hashed using the given options.
   *
   * @param  string $hashedValue
   * @param  array $options
   * @return bool
   */
  public function needsRehash($hashedValue, array $options = array())
  {
    return false;
  }

}

app/Providers/SHAHashServiceProvider.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class SHAHashServiceProvider extends ServiceProvider {

  /**
   * Register the service provider.
   *
   * @return void
   */
  public function register() {
    $this->app->singleton('hash', function() {
      return new SHAHasher();
    });
  }

  /**
   * Get the services provided by the provider.
   *
   * @return array
   */
  public function provides() {
    return array('hash');
  }

}

app/config/app.php

remove or comment out // Illuminate\Hashing\HashServiceProvider::class,

Add App\Providers\SHAHashServiceProvider::class,

I didn't need to register the users (only to allow them to use their existing logins to get in) so I only tested it for access. I'm not sure why the app/Libraries area wouldn't take. I was getting an error

Class 'SHAHashServiceProvider' not found

when I ran the composer dump-autoload command until I moved both into app/Providers.

Hope this helps others trying to get the anser to work in Laravel 5.


There is actually a easier (or more simple, at least) solution for a case like this. you can 'fake' the hashing, by using this method in the user model:

public function getAuthPassword() {
    return Hash::make($this->password);
}

And hashing the input with your own hash function. For instance, if your passwords are currently hashed with sha1, you can validate the user with

Auth::attempt(array('email' => $email, 'password' => sha1($password))

It doesn't feel like good coding practice, to do it this way, but it will certainly be easier than rewriting the hash module.


You'll have to rewrite the Hash module. Thanks to Laravel's ideas of following IoC and Dependency Injection concepts, it'll be relatively easy.

First, create a app/libraries folder and add it to composer's autoload.classmap:

"autoload": {
    "classmap": [
        // ...

        "app/libraries"
    ]
},

Now, it's time we create our class. Create a SHAHasher class, implementing Illuminate\Hashing\HasherInterface. We'll need to implement its 3 methods: make, check and needsRehash.

Note: On Laravel 5, implement Illuminate/Contracts/Hashing/Hasher instead of Illuminate\Hashing\HasherInterface.

app/libraries/SHAHasher.php

class SHAHasher implements Illuminate\Hashing\HasherInterface {

    /**
     * Hash the given value.
     *
     * @param  string  $value
     * @return array   $options
     * @return string
     */
    public function make($value, array $options = array()) {
        return hash('sha1', $value);
    }

    /**
     * Check the given plain value against a hash.
     *
     * @param  string  $value
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function check($value, $hashedValue, array $options = array()) {
        return $this->make($value) === $hashedValue;
    }

    /**
     * Check if the given hash has been hashed using the given options.
     *
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function needsRehash($hashedValue, array $options = array()) {
        return false;
    }

}

Now that we have our class done, we want it to be used by default, by Laravel. To do so, we'll create SHAHashServiceProvider, extending Illuminate\Support\ServiceProvider, and register it as the hash component:

app/libraries/SHAHashServiceProvider.php

class SHAHashServiceProvider extends Illuminate\Support\ServiceProvider {

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register() {
        $this->app['hash'] = $this->app->share(function () {
            return new SHAHasher();
        });

    }

    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides() {
        return array('hash');
    }

}

Cool, now all we have to do is make sure our app loads the correct service provider. On app/config/app.php, under providers, remove the following line:

'Illuminate\Hashing\HashServiceProvider',

Then, add this one:

'SHAHashServiceProvider',

Tags:

Php

Laravel