> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Cifrado (Encryption)

> Explicamos cómo cifrar y descifrar valores con AES-256-CBC utilizando la fachada Crypt de Laravel. Cubrimos desde la generación de APP_KEY y los model casts hasta el almacenamiento seguro de datos personales.

## ¿Qué es la fachada Crypt?

El servicio de cifrado de Laravel ofrece una interfaz sencilla para cifrar y descifrar valores usando el cifrado AES-256-CBC (o AES-128-CBC) de **OpenSSL**.

Todos los valores cifrados por Laravel se firman con un **código de autenticación de mensaje (MAC)**.
Con esto, si el valor cifrado se altera, ya no se puede descifrar.

```mermaid theme={null}
flowchart LR
    A["Datos en claro"] -->|"Crypt::encryptString()"| B["Valor cifrado<br>(firmado con MAC)"]
    B -->|"Crypt::decryptString()"| A
    B -->|Detección de alteración| C["DecryptException"]
```

***

## Configuración

### Generación de APP\_KEY

Antes de usar el cifrado, la clave `key` en `config/app.php` debe estar configurada.
Este valor se lee de la variable de entorno `APP_KEY`.

Genera una clave segura con el comando `php artisan key:generate`.
Usa el generador de números aleatorios seguros de PHP para producir una clave criptográficamente segura.

```shell theme={null}
php artisan key:generate
```

Suele generarse automáticamente al instalar Laravel. La clave generada se guarda en el archivo `.env`.

```ini theme={null}
APP_KEY=base64:J63qRTDLub5NuZvP+kb8YIorGS6qFYHKVo6u7179stY=
```

<Warning>
  Nunca hagas pública `APP_KEY`. Si se filtra, todos los datos cifrados podrían ser descifrados.
</Warning>

### Rotación de la clave de cifrado

Cambiar la clave de cifrado hace que se desconecten todas las sesiones de usuario autenticadas.
Es porque Laravel cifra todas las cookies, incluidas las de sesión.

Además, los datos cifrados con la clave anterior no podrán descifrarse.

Para mitigar este problema, puedes listar claves antiguas separadas por comas en `APP_PREVIOUS_KEYS`.

```ini theme={null}
APP_KEY="base64:J63qRTDLub5NuZvP+kb8YIorGS6qFYHKVo6u7179stY="
APP_PREVIOUS_KEYS="base64:2nLsGFGzyoae2ax3EF2Lyq/hH6QghBGLIq5uL+Gp8/w="
```

Para cifrar, Laravel siempre usa la clave actual; para descifrar, si falla con la clave actual, prueba las claves antiguas en orden.
Así los usuarios pueden seguir usando la aplicación durante la rotación de claves.

***

## Cifrado

Cifra un valor con el método `encryptString` de la fachada `Crypt`.
El valor se cifra con OpenSSL y AES-256-CBC, y se firma con MAC.

```php theme={null}
<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;

class DigitalOceanTokenController extends Controller
{
    /**
     * Guarda el API token del usuario
     */
    public function store(Request $request): RedirectResponse
    {
        $request->user()->fill([
            'token' => Crypt::encryptString($request->token),
        ])->save();

        return redirect('/secrets');
    }
}
```

<Tip>
  `encryptString` cifra la cadena **sin** serializarla. Si necesitas cifrar objetos o arrays, usa `encrypt`.
</Tip>

| Método                         | Uso                                                            |
| ------------------------------ | -------------------------------------------------------------- |
| `Crypt::encryptString($value)` | Cifra el string tal cual                                       |
| `Crypt::encrypt($value)`       | Serializa el valor antes de cifrarlo (admite arrays y objetos) |

***

## Descifrado

Descifra un valor con `decryptString` de la fachada `Crypt`.
Si no se puede descifrar correctamente (por ejemplo, MAC no válido), se lanza una `DecryptException`.

```php theme={null}
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Facades\Crypt;

try {
    $decrypted = Crypt::decryptString($encryptedValue);
} catch (DecryptException $e) {
    // Manejo del fallo de descifrado
    abort(400, 'Datos no válidos.');
}
```

| Método                         | Uso                                              |
| ------------------------------ | ------------------------------------------------ |
| `Crypt::decryptString($value)` | Descifra como string                             |
| `Crypt::decrypt($value)`       | Descifra y deserializa (admite arrays y objetos) |

***

## Casts en modelos

Usando el cast `encrypted` en un modelo Eloquent, el cifrado y descifrado del atributo son automáticos.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected function casts(): array
    {
        return [
            'secret_note'    => 'encrypted',           // Cifrado de string
            'profile_data'   => 'encrypted:array',     // Cifra un array
            'preferences'    => 'encrypted:collection',// Cifra una colección
            'metadata'       => 'encrypted:object',    // Cifra un objeto
            'settings'       => 'encrypted:json',      // Cifra como JSON
        ];
    }
}
```

Con el cast configurado, la asignación y la lectura del atributo cifran y descifran automáticamente.

```php theme={null}
// Se cifra automáticamente al guardarse en la BD
$user->secret_note = 'Nota secreta';
$user->save();

// Se descifra automáticamente al leer
echo $user->secret_note; // 'Nota secreta'
```

<Info>
  Los casts `encrypted:*` usan internamente `Crypt::encrypt` y `Crypt::decrypt`.
  Se recomienda usar el tipo de columna `text` o `longText` en la base de datos.
</Info>

***

## Ejemplo práctico: almacenamiento cifrado de datos personales

Patrón típico para guardar datos personales (número de identificación, tarjeta de crédito, etc.) de forma segura.

### Migración

```php theme={null}
Schema::create('profiles', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained();
    $table->text('my_number')->nullable();     // El valor cifrado se guarda como text
    $table->text('bank_account')->nullable();
    $table->timestamps();
});
```

### Modelo

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{
    protected $fillable = ['user_id', 'my_number', 'bank_account'];

    protected function casts(): array
    {
        return [
            'my_number'    => 'encrypted',
            'bank_account' => 'encrypted',
        ];
    }
}
```

### Controlador

```php theme={null}
use App\Models\Profile;
use Illuminate\Http\Request;

class ProfileController extends Controller
{
    public function store(Request $request)
    {
        $request->validate([
            'my_number'    => ['required', 'string'],
            'bank_account' => ['required', 'string'],
        ]);

        // El modelo cifra automáticamente al guardar
        Profile::create([
            'user_id'      => $request->user()->id,
            'my_number'    => $request->my_number,
            'bank_account' => $request->bank_account,
        ]);

        return redirect('/profile');
    }

    public function show(Request $request)
    {
        $profile = $request->user()->profile;

        // El modelo descifra automáticamente al leer
        return view('profile.show', ['profile' => $profile]);
    }
}
```

***

## Resumen

| Objetivo                                   | Método                                        |
| ------------------------------------------ | --------------------------------------------- |
| Generar APP\_KEY                           | `php artisan key:generate`                    |
| Cifrar un string                           | `Crypt::encryptString($value)`                |
| Descifrar un string                        | `Crypt::decryptString($value)`                |
| Cifrar array u objeto                      | `Crypt::encrypt($value)`                      |
| Cifrar atributos de modelo automáticamente | Cast `'column' => 'encrypted'`                |
| Rotar clave                                | Listar claves antiguas en `APP_PREVIOUS_KEYS` |

## Próximos pasos

<Columns cols={2}>
  <Card title="Hashing" icon="lock" href="/es/hashing">
    Aprende a hashear y verificar contraseñas de forma segura.
  </Card>

  <Card title="Autorización" icon="shield" href="/es/authorization">
    Descubre el control de acceso con políticas y gates.
  </Card>
</Columns>


## Related topics

- [Configuración](/es/configuration.md)
- [Redis](/es/redis.md)
- [Autenticación OAuth 2.0 - Google Sheets API for Laravel](/es/packages/laravel-google-sheets/oauth.md)
- [Enrutamiento](/es/routing.md)
- [Despliegue](/es/deployment.md)
