usu/scrypt-password-encoder-bundle
Symfony bundle that adds scrypt password hashing to your security stack. It supplies a password encoder built on the memory-hard scrypt key derivation function, so you can store stronger hashes with minimal configuration and let Symfony's authentication flow handle the rest.
Read this first: this is a Symfony2 bundle, not a Laravel package. usu/scrypt-password-encoder-bundle (namespace Usu\ScryptPasswordEncoderBundle) provides a Symfony PasswordEncoderInterface implementation backed by scrypt, wired through the Symfony DI container and security.yml. It has 18 stars, zero dependents, and its last release was November 2014. Composer will likely refuse to install it on a modern Laravel app due to symfony/symfony ~2.x and PHP 5.x-era constraints — and even with --ignore-platform-reqs it will not plug into Laravel's hashing pipeline.
Where to look first in the source:
UsuScryptPasswordEncoderBundle.php — bundle entry pointDependencyInjection/ and Resources/config/services.xml — how the encoder service is registered and what parameters (salt, N, r, p) are exposedEncoder/ScryptPasswordEncoder.php (or similarly named class) — the actual encodePassword / isPasswordValid logic; this is the only part you'll realistically reuseREADME.md — document the encoder service id and the security.yml snippetMinimal Symfony2 usage (as originally intended, for reference):
# app/config/security.yml
encoders:
AppBundle\Entity\User:
id: usu_scrypt_password_encoder
// AppKernel.php
new Usu\ScryptPasswordEncoderBundle\UsuScryptPasswordEncoderBundle(),
First use case in a Laravel context: don't try to install the bundle — instead treat its encoder class as a reference implementation, copy the algorithm, and wrap it in a Laravel Hasher (see below). The first thing you verify is whether PHP's scrypt extension (ext-scrypt) is available; if not, the pure-PHP fallback is slow and will show up in profiling immediately.
Hasher (if you must run the exact code)If you composer require usu/scrypt-password-encoder-bundle and force it in, expose it as a custom hash driver so the rest of your app uses Hash::make() / Hash::check() normally:
// App\Providers\HashServiceProvider
use Illuminate\Support\Facades\Hash;
use App\Hashing\ScryptHasher;
public function boot(): void
{
Hash::extend('scrypt', fn () => new ScryptHasher(
config('hashing.scrypt')
));
}
// config/hashing.php
'scrypt' => [
'driver' => 'scrypt',
'N' => 16384, // CPU/memory cost
'r' => 8, // block size
'p' => 1, // parallelization
],
// App\Hashing\ScryptHasher
namespace App\Hashing;
use Illuminate\Contracts\Hashing\Hasher;
use Usu\ScryptPasswordEncoderBundle\Encoder\ScryptPasswordEncoder;
class ScryptHasher implements Hasher
{
private ScryptPasswordEncoder $encoder;
public function __construct(private array $config)
{
// Signature depends on the bundle version — read the encoder's constructor.
$this->encoder = new ScryptPasswordEncoder(
$this->config['N'],
$this->config['r'],
$this->config['p'],
);
}
public function make($value, array $options = []): string
{
return $this->encoder->encodePassword($value, $this->salt());
}
public function check($value, $hashedValue, array $options = []): bool
{
if (empty($hashedValue)) {
return false;
}
return $this->encoder->isPasswordValid($hashedValue, $value, null);
}
public function needsRehash($hashedValue, array $options = []): bool
{
// scrypt hashes produced by this bundle carry no algorithm/format marker.
return false;
}
private function salt(): string
{
return bin2hex(random_bytes(16));
}
}
Copy the encoder's encodePassword/isPasswordValid logic into a small internal class with no Symfony dependency. You get:
scrypt$N$r$p$salt$hash) so needsRehash worksThen register it as above via Hash::extend(). This is what most Laravel teams would actually do.
If you're onboarding users from an old Symfony2 app that used this bundle, you don't need the bundle at runtime — you need the exact verification path. Capture the encoder's output format from a production dump, write a verifier in Laravel, and run a login-time rehash:
if ($user->password_algo === 'scrypt' && $scryptVerifier->verify($plain, $user->password)) {
$user->password = Hash::make($plain); // argon2id/bcrypt
$user->password_algo = config('hashing.driver');
$user->save();
}
Test with fixtures: take 3–5 hashes generated by the 2014 bundle in production and assert your port verifies them. This is the single most valuable artifact of the whole exercise.
ext-scrypt (or the bundle's fallback). Check php -m | grep scrypt on every environment. The pure-PHP fallback is orders of magnitude slower and will show up as login-time latency — and as an accidentally weak cost parameter if the bundle defaults low.needsRehash. The bundle predates Laravel's needsRehash contract and likely doesn't embed N/r/p/salt in a self-describing way. You cannot tune cost parameters later without a manual migration. If you port the algorithm, define your own format string up front.Hasher contract stores everything in the single hash string. Don't naively call encodePassword($plain, null) and expect check() to work.isPasswordValid argument order is Symfony-style — ($encoded, $raw, $salt), the reverse of Hash::check($raw, $encoded). Getting this backwards is the most common integration bug and fails silently (returns false, not an exception).services.xml, tagged encoder). Laravel's container will not discover these; you must instantiate the encoder manually or port the logic. Do not try to boot the Symfony kernel inside Laravel.Hash::make() with argon2id ('driver' => 'argon2id') is the correct answer. It's maintained, memory-hard, has self-describing formats, and needsRehash just works. Scrypt via this bundle buys you nothing except a 2014 compatibility path.password_hash with PASSWORD_ARGON2ID or the paragonie/sodium_compat stack first. Scrypt specifically is rarely the right choice in 2024+ PHP.How can I help you explore Laravel packages today?