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

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',

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.


The Laravel 7 way

In Laravel 7 adding new hash methods to Laravel got a lot easier you can also still support the old Hash methods instead of basically overwriting them.

First we will create a subfolder in the app folder called Libs or Libaries or basically whatever you want to call it. In that folder I created a folder called CustomHash where I store all my custom hashers.

Through PSR-4 it is automatically detected and we do not need to add it anywhere.

The Namespace is based on the folder names I chose.

app/AppServiceProvider.php

First we use the namespace of the Sha1Hasher

use App\Libs\CustomHash\Sha1Hasher;

then in the boot() function of your AppServiceProvide.php

        Hash::extend("sha1", function($app)
        {
            return new Sha1Hasher();
        });

app/Libs/CustomHash/Sha1Hasher.php

<?php

    namespace App\Libs\CustomHash;

    use Illuminate\Contracts\Hashing\Hasher as HasherContract;
    use Illuminate\Hashing\AbstractHasher;

    class Sha1Hasher extends AbstractHasher implements HasherContract {

        /**
         * Hash the given value.
         *
         * @param  string  $value
         * @return array   $options
         * @return string
         */
        public function make($value, array $options = array()) {
            //I have custom encoding / encryption here//
            //Define your custom hashing logic here//
            return 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;
        }

    }



And that's basically it if you want to change the default hash algorithm for everything there is one more thing to do:

config/hashing.php

Change the default driver for hashing to the sha1 driver we implemented with the edits above.

    'driver' => 'sha1',