Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Crypto Laravel Package

grafite/crypto

Grafite Crypto is a Laravel package that provides convenient cryptographic helpers for encrypting and decrypting strings and sensitive application data, making it easier to secure values with Laravel's built-in encryption features and a simple API for protecting data in PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register. The package is not actively maintained (repo archived, no dependents), so treat installation as a fork-and-pin decision rather than a composer require you can forget about:

composer require grafite/crypto

For Laravel, add the service provider to config/app.php (pre-5.5 style) or rely on package discovery if the composer.json declares it. For Lumen you must do it manually:

$app->register(Grafite\Crypto\CryptoServiceProvider::class);
$app->configure('crypto');
$app->withFacades();

Look here first, not at the README. With ~10 stars and an archived repo, documentation is thin and possibly stale relative to the code. Read the source in this order:

  1. src/CryptoServiceProvider.php — reveals the container binding, config merge, and whether a facade alias is registered.
  2. config/crypto.php (publish with php artisan vendor:publish --tag=config) — the key material source is the single most important thing to understand.
  3. The main class (typically Grafite\Crypto\Crypto) — its public method list is the API surface. Enumerate it before designing around it.

First use case. The most defensible day-one use is generating opaque tokens and hashing them for storage, e.g. API keys or password-reset tokens:

$plain = Crypto::random(40);          // hand to the user once
$stored = Crypto::hash($plain);       // persist only this

Validate with Crypto::check($plain, $stored) on the way back in. This is low-risk because it mirrors Laravel's own Str::random + Hash, so if you later rip the package out, the migration is a find-and-replace rather than a data migration.

Implementation Patterns

Isolate the dependency behind your own boundary. Given the archived status, never call the facade from controllers or models directly. Wrap it:

final class TokenService
{
    public function issue(int $bytes = 32): array
    {
        $plain = Crypto::random($bytes);
        return [$plain, Crypto::hash($plain)];
    }

    public function verify(string $plain, string $hash): bool
    {
        return Crypto::check($plain, $hash);
    }
}

Bind TokenService in a service provider and inject it. Swapping to Str::random() / Hash::make() later becomes a one-file change.

Encrypt sensitive model attributes with a cast or trait. For fields that must be reversible (e.g. a third-party API secret stored per-tenant), wrap accessors/mutators rather than scattering Crypto::encrypt() calls:

protected function providerSecret(): Attribute
{
    return Attribute::make(
        get: fn ($value) => $value === null ? null : Crypto::decrypt($value),
        set: fn ($value) => $value === null ? null : Crypto::encrypt($value),
    );
}

Combine with $hidden so the plaintext never leaks through JSON serialization.

Pair reversible encryption with a blind index for lookups. Encrypted columns are non-deterministic and cannot be where()-ed. If you need to look a record up by an encrypted value (email, external ID), add a separate deterministic hash column and query on that:

$model->email_hash = hash_hmac('sha256', $email, config('crypto.lookup_key'));
User::where('email_hash', $hash)->first();

Keep the lookup key separate from the encryption key so rotating one doesn't break the other.

Use it as a key-derivation helper, not a crypto engine. The realistic value in a package this size is convenience around random bytes, base64 handling, and hashing — not novel primitives. Use it to mint keys and tokens, and hand the actual payload protection to Laravel's Crypt (AES-256-GCM, authenticated) unless you've verified the package does the same.

Test with a fixed key and a swapped binding. In phpunit.xml, pin the package key to a known value so encrypted fixtures are deterministic across CI runs, and in feature tests swap the binding for a fake if you only care about wiring:

$this->app->bind(Crypto::class, fn () => new class extends Crypto { /* stubs */ });

Unit-test the wrapper directly against the real implementation so the crypto is exercised at least once.

Gotchas and Tips

The archive is the headline risk. No security patches, no dependency bumps, no PHP/Laravel version compatibility guarantees. Before adopting: check composer.json for the Laravel constraint, run composer audit, and read every line of the encryption path. If you need it long-term, fork it into your own namespace — you are now the maintainer either way.

Key configuration is where this class of package breaks. Watch for these in order of frequency:

  • config:cache — after changing the package key, run php artisan config:cache again or you'll decrypt with the old one and get MAC/base64 failures that look like data corruption.
  • Key encoding mismatch — a key stored base64-encoded but consumed raw (or vice versa) produces silent garbage or a MAC is invalid style error. Dump strlen() of the decoded key; AES-256 needs exactly 32 bytes.
  • APP_KEY vs. package key — if the package reads config('crypto.key') and it's empty, it may silently fall back or throw only on first use. Assert the config is non-null in a boot test.
  • Multi-environment drift — local/staging/prod keys differing means encrypted rows are not portable. Decide early whether dumps move between environments.

Serialization double-encoding. If you encrypt a field that is also cast (array, json, collection), you'll encrypt the JSON string, then the cast will try to decode the decrypted string — usually fine, occasionally a silent type flip if the package serializes internally. Test round-trips on non-string types explicitly.

Column length. Ciphertext plus IV plus MAC is materially longer than plaintext, and base64 inflates it another ~33%. A VARCHAR(255) column that held a 200-char plaintext will truncate. Use TEXT and, in MySQL, avoid strict-mode surprises by sizing deliberately.

Lumen specifics. No facades unless $app->withFacades() is called; no config loading unless $app->configure('crypto') is called; and env() inside package config files returns null under config:cache, so prefer $_ENV-safe reads or move values into config/crypto.php at deploy time.

Debugging decrypt failures. Bisect: (1) encrypt then immediately decrypt in tinker with the same process — isolates key/config from transport; (2) compare raw DB values — base64 or JSON transport layers (queues, HTTP) mangle payloads; (3) check for whitespace/trim applied by a mutator before the decryptor sees it. If tinker round-trips cleanly but the app fails, the problem is config caching or environment key drift, not the algorithm.

Extension points. The useful ones are the container binding (swap the implementation), the published config file (key + any cipher/rounds settings), and the service provider (register your own subclass). There is no plugin system, so anything beyond that means touching vendor code — which is the signal to fork.

Prefer native where the functionality overlaps. Str::random, Str::uuid, Hash::make/Hash::check, and Crypt::encryptString/decryptString cover most of what a package like this offers, are maintained by the framework, and won't be archived. Adopt grafite/crypto only for a specific capability it has that you've verified you need — and budget the exit.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource