Weave Code
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

spatie/crypto

Generate RSA key pairs and encrypt/decrypt (and sign/verify) data using private/public keys in PHP. Provides simple wrappers around OpenSSL for better DX, with support for loading keys from files and writing generated keys to disk.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require spatie/crypto
    
  2. Generate Key Pair:

    use Spatie\Crypto\Rsa\KeyPair;
    
    [$privateKey, $publicKey] = (new KeyPair())->generate();
    
    • Optionally, specify paths to save keys:
      (new KeyPair())->generate(storage_path('app/private_key.pem'), storage_path('app/public_key.pem'));
      
  3. First Use Case: Encrypt/Decrypt Data

    use Spatie\Crypto\Rsa\PrivateKey;
    use Spatie\Crypto\Rsa\PublicKey;
    
    $privateKey = PrivateKey::fromFile(storage_path('app/private_key.pem'));
    $publicKey = PublicKey::fromFile(storage_path('app/public_key.pem'));
    
    $data = 'Sensitive API token';
    $encrypted = $privateKey->encrypt($data); // Encrypt with private key (for signing)
    $decrypted = $publicKey->decrypt($encrypted); // Decrypt with public key
    

Where to Look First

  • KeyPair class: For generating and managing key pairs.
  • PrivateKey and PublicKey classes: Core methods for encryption/decryption and signing/verification.
  • openssl_* wrappers: Understand the underlying OpenSSL functions (e.g., openssl_private_encrypt, openssl_public_decrypt).
  • Tests: Test files show real-world usage patterns.

Implementation Patterns

Workflows

1. Key Management

  • Generate and Store Keys:
    $keyPair = (new KeyPair())->generate(
        storage_path('app/keys/private.pem'),
        storage_path('app/keys/public.pem')
    );
    
  • Load Keys Dynamically:
    $privateKey = PrivateKey::fromFile(storage_path('app/keys/private.pem'));
    $publicKey = PublicKey::fromFile(storage_path('app/keys/public.pem'));
    
  • Environment-Based Keys: Use Laravel's .env to define paths:
    PRIVATE_KEY_PATH=storage/app/keys/private.pem
    PUBLIC_KEY_PATH=storage/app/keys/public.pem
    
    $privateKey = PrivateKey::fromFile(config('crypto.private_key_path'));
    

2. Encrypting/Decrypting Data

  • Encrypt with Private Key (Signing):
    $signature = $privateKey->encrypt('data_to_sign');
    
  • Decrypt with Public Key (Verification):
    $verifiedData = $publicKey->decrypt($signature);
    
  • Encrypt with Public Key (Secure Transmission):
    $encryptedData = $publicKey->encrypt('sensitive_data');
    
  • Decrypt with Private Key (Receiver):
    $decryptedData = $privateKey->decrypt($encryptedData);
    

3. Signing and Verification

  • Sign Data:
    $signature = $privateKey->sign('data_to_sign');
    
  • Verify Signature:
    $isValid = $publicKey->verify('data_to_sign', $signature);
    

4. Integration with Laravel

  • Service Provider: Bind keys to the container for easy access:
    // app/Providers/AppServiceProvider.php
    public function register()
    {
        $this->app->singleton(PrivateKey::class, function () {
            return PrivateKey::fromFile(config('crypto.private_key_path'));
        });
        $this->app->singleton(PublicKey::class, function () {
            return PublicKey::fromFile(config('crypto.public_key_path'));
        });
    }
    
  • Middleware for API Security: Verify signatures for incoming requests:
    public function handle($request, Closure $next)
    {
        $publicKey = app(PublicKey::class);
        if (!$publicKey->verify($request->data, $request->signature)) {
            abort(403, 'Invalid signature');
        }
        return $next($request);
    }
    

5. Storing Encrypted Data

  • Encrypt Before Saving to Database:
    $user = User::create([
        'name' => 'John Doe',
        'encrypted_token' => $privateKey->encrypt($request->api_token),
    ]);
    
  • Decrypt Before Use:
    $token = $user->encrypted_token ? $publicKey->decrypt($user->encrypted_token) : null;
    

Gotchas and Tips

Pitfalls

  1. Key File Permissions:

    • Private keys must be readable only by the web server user (e.g., www-data or nginx).
    • Example:
      chmod 600 storage/app/keys/private.pem
      chown www-data:www-data storage/app/keys/private.pem
      
    • Gotcha: Forgetting permissions can expose private keys via HTTP requests.
  2. Key Rotation:

    • Rotate keys periodically (e.g., annually) and update all systems using the old keys.
    • Tip: Use a migration to update encrypted data with new keys:
      $oldPrivateKey = PrivateKey::fromFile('old_private.pem');
      $newPrivateKey = PrivateKey::fromFile('new_private.pem');
      $newPublicKey = PublicKey::fromFile('new_public.pem');
      
      User::whereNotNull('encrypted_token')->each(function ($user) use ($oldPrivateKey, $newPrivateKey, $newPublicKey) {
          $decrypted = $oldPrivateKey->decrypt($user->encrypted_token);
          $user->encrypted_token = $newPrivateKey->encrypt($decrypted);
          $user->save();
      });
      
  3. Data Size Limits:

    • RSA has a maximum data size for encryption (typically 117 bytes for 2048-bit keys).
    • Gotcha: Trying to encrypt larger data will throw an openssl_error_string exception.
    • Solution: Use hybrid encryption (e.g., encrypt data with AES, then encrypt the AES key with RSA):
      $aesKey = openssl_random_pseudo_bytes(32);
      $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
      $encryptedData = openssl_encrypt('sensitive_data', 'aes-256-cbc', $aesKey, OPENSSL_RAW_DATA, $iv);
      $encryptedAesKey = $publicKey->encrypt($aesKey);
      
  4. Key Format:

    • The package expects PEM-format keys.
    • Gotcha: Using DER-format keys will fail silently or throw cryptic errors.
    • Fix: Convert keys to PEM:
      openssl rsa -in key.der -inform DER -out key.pem -outform PEM
      
  5. OpenSSL Extensions:

    • The package relies on the PHP OpenSSL extension.
    • Gotcha: Missing extension causes Class 'Spatie\Crypto\Rsa\KeyPair' not found or openssl_* function errors.
    • Fix: Enable the extension in php.ini:
      extension=openssl
      

Debugging

  1. Check OpenSSL Errors:

    • Wrap operations in try-catch to log OpenSSL errors:
      try {
          $decrypted = $publicKey->decrypt($encryptedData);
      } catch (\Exception $e) {
          \Log::error('OpenSSL Error: ' . openssl_error_string());
          throw $e;
      }
      
  2. Validate Key Pairs:

    • Ensure keys are valid before use:
      if (!$privateKey->isValid() || !$publicKey->isValid()) {
          throw new \RuntimeException('Invalid key pair');
      }
      
  3. Test with Known Values:

    • Use a known plaintext/ciphertext pair to verify setup:
      $testData = 'test123';
      $encrypted = $privateKey->encrypt($testData);
      $decrypted = $publicKey->decrypt($encrypted);
      assert($testData === $decrypted, 'Key pair test failed');
      

Tips

  1. Use Config Files:

    • Centralize key paths in config/crypto.php:
      return [
          'private_key_path' => storage_path('app/keys/private.pem'),
          'public_key_path' => storage_path('app/keys/public.pem'),
      ];
      
  2. Environment-Specific Keys:

    • Use .env to switch keys between environments:
      CRYPTO_PRIVATE_KEY=storage/app/keys/local_private.pem
      CRYPTO_PUBLIC_KEY=storage/app/keys/local
      
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport