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

# Crypto — criptografía de AT Protocol

> Módulo Crypto del paquete Laravel Bluesky. Explica los pares de claves P-256 / secp256k1, las claves DID, JWT, DPoP y las conversiones de firmas.

<Warning>
  Crypto es una implementación interna avanzada. No es necesaria para las operaciones habituales como publicar, obtener feeds o notificaciones. Consúltala cuando quieras construir verificaciones de firma o implementaciones de OAuth de bajo nivel del AT Protocol.
</Warning>

## Descripción general de la criptografía en AT Protocol

Para construir una red social descentralizada, AT Protocol adopta ampliamente la criptografía de curva elíptica (ECC). Sus usos principales son los siguientes.

```mermaid theme={null}
graph TD
    A["Par de claves<br>(P-256 / secp256k1)"] --> B["Firmar con clave privada"]
    A --> C["Codificar la clave pública en did:key"]
    B --> D["Token DPoP (OAuth)"]
    B --> E["Firma de commit (repositorio)"]
    B --> F["Firma de etiquetas (Labeler)"]
    C --> G["Registrar en el DID Document"]
    G --> H["Verificar firma con la clave pública"]
```

| Curva             | Algoritmo | Uso principal                                      |
| ----------------- | --------- | -------------------------------------------------- |
| secp256r1 (P-256) | ES256     | OAuth (DPoP, Client Assertion)                     |
| secp256k1 (K256)  | ES256K    | Verificación de firmas de Feed Generator y Labeler |

***

## Clases de par de claves

### AbstractKeypair

`AbstractKeypair` es la clase base común para P256 / K256. Internamente utiliza [phpseclib3](https://phpseclib.com/).

```php theme={null}
// Genera un nuevo par de claves
$keypair = P256::create();
$keypair = K256::create();

// Carga desde una clave privada codificada en Base64 URL-safe
$keypair = P256::load($base64PrivateKey);

// Obtén en formato PEM
$privatePem = $keypair->privatePEM();
$publicPem  = $keypair->publicPEM();

// Convierte a JWK (JSON Web Key)
$jwk = $keypair->toJWK();
```

### P256 (secp256r1)

```php theme={null}
use Revolution\Bluesky\Crypto\P256;

$keypair = P256::create();
```

Se usa en OAuth (DPoP / Client Assertion). `OAuthKey` hereda de P256 y carga la clave privada desde `config('bluesky.oauth.private_key')`.

También existe un comando Artisan para generar una nueva clave privada OAuth.

```bash theme={null}
php artisan bluesky:new-private-key
```

### K256 (secp256k1)

```php theme={null}
use Revolution\Bluesky\Crypto\K256;

$keypair = K256::create();
```

Se usa para la autenticación del Feed Generator y el Labeler. El PDS / Relay de Bluesky verifica las firmas con esta curva.

***

## DidKey

La clase `DidKey` codifica y decodifica claves públicas al formato `did:key`.

### Qué es el formato did:key

En AT Protocol, las claves públicas se representan como una cadena `did:key:z...`. Consiste en un identificador de curva más la clave pública comprimida, codificados en multibase con Base58btc.

```mermaid theme={null}
graph LR
    A["Clave pública (PEM)"] --> B["Identificador de curva + clave pública comprimida"]
    B --> C["Codificación Base58btc"]
    C --> D["did:key:z..."]
```

### Codificar clave pública a did:key

```php theme={null}
use Revolution\Bluesky\Crypto\DidKey;
use Revolution\Bluesky\Crypto\K256;

$keypair = K256::create();
$publicPem = $keypair->publicPEM();

// Convierte al formato did:key
$didKey = DidKey::format($publicPem);
// => "did:key:zQ3s..."
```

### Parsear la clave pública desde el DID Document

```php theme={null}
use Revolution\Bluesky\Crypto\DidKey;
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Support\DidDocument;

$didDoc = DidDocument::make(
    Bluesky::identity()->resolveDID('did:plc:***')->json()
);

// Genera el objeto de clave pública de phpseclib3 desde el publicKey (multibase) del DID Document
$publicKey = DidKey::parse($didDoc->publicKey());
```

***

## JsonWebToken (JWT)

La clase `JsonWebToken` proporciona codificación y decodificación de JWT.

```php theme={null}
use Revolution\Bluesky\Crypto\JsonWebToken;

// Genera un JWT (firmando con clave privada PEM)
$token = JsonWebToken::encode(
    payload: ['iss' => 'did:plc:***', 'aud' => 'https://bsky.social', 'exp' => time() + 60],
    key: $privatePem,
    alg: 'ES256',
);

// Decodifica un JWT (sin verificar la firma)
$payload = JsonWebToken::decode($token);
```

***

## DPoP (Demonstrated Proof of Possession)

DPoP es un mecanismo de seguridad que vincula el token de acceso OAuth a un par de claves específico del cliente. Previene ataques de replay del token.

```mermaid theme={null}
sequenceDiagram
    participant App as Aplicación Laravel
    participant AS as Authorization Server
    participant RS as Resource Server

    App->>AS: Petición PAR (+ cabecera DPoP)
    AS-->>App: request_uri
    App->>AS: Petición de token (+ cabecera DPoP)
    AS-->>App: Token de acceso (DPoP bound)
    App->>RS: Petición a la API (+ cabecera DPoP + ath)
    RS-->>App: Respuesta
```

La clase `DPoP` se usa internamente y normalmente no necesitas invocarla directamente. El middleware de `OAuthAgent` añade automáticamente la cabecera DPoP.

```php theme={null}
// Generación de la prueba DPoP (para la petición de token OAuth)
$proof = DPoP::authProof(
    jwk: $jsonWebKey,
    url: 'https://bsky.social/oauth/token',
    method: 'POST',
    nonce: $nonce,
);

// Generación de la prueba DPoP (para peticiones API, incluye ath)
$proof = DPoP::apiProof(
    jwk: $jsonWebKey,
    url: 'https://api.bsky.app/xrpc/...',
    method: 'GET',
    token: $accessToken,
    nonce: $nonce,
);
```

***

## Signature (conversión de formatos de firma)

AT Protocol utiliza un formato de firma compacto de 64 bytes, pero phpseclib3 devuelve el formato ASN.1 DER. La clase `Signature` se encarga de esta conversión.

```php theme={null}
use Revolution\Bluesky\Crypto\Signature;

// ASN.1 DER → compacto (64 bytes)
$compact = Signature::toCompact($derSignature);

// Compacto → ASN.1 DER
$der = Signature::fromCompact($compactSignature);
```

***

## JsonWebKey

`JsonWebKey` es la clase que representa un JWK (JSON Web Key). Se usa para generar las pruebas DPoP.

```php theme={null}
use Revolution\Bluesky\Crypto\JsonWebKey;

// Genera un JWK a partir del par de claves
$jwk = $keypair->toJWK();

// O instancia directamente
$jwk = JsonWebKey::load(['kty' => 'EC', 'crv' => 'P-256', ...]);
```

***

## OAuthKey

`OAuthKey` es una clase de clave específica de OAuth que hereda de P256 y utiliza el valor de `config('bluesky.oauth.private_key')` como clave privada.

```php theme={null}
use Revolution\Bluesky\Crypto\OAuthKey;

// Carga la clave privada desde la configuración
$oauthKey = OAuthKey::load();

// Se usa para firmar el JWT del Client Assertion
$jwk = $oauthKey->toJWK();
```

Normalmente se gestiona automáticamente dentro de Bluesky Socialite.

***

## Enlaces de referencia

* [AT Protocol: Identity](https://atproto.com/guides/identity)
* [AT Protocol: Cryptography spec](https://atproto.com/specs/cryptography)
* [phpseclib3](https://phpseclib.com/)

<Info>
  Source: [src/Crypto/](https://github.com/invokable/laravel-bluesky/tree/main/src/Crypto)
</Info>


## Related topics

- [Core — operaciones core de AT Protocol](/es/packages/laravel-bluesky/core.md)
- [Laravel LSP — Extensión de funciones de IDE con Language Server Protocol](/es/blog/laravel-lsp-introduction.md)
- [Solicitudes de permiso](/es/packages/laravel-copilot-sdk/permission-request.md)
- [Tutorial de bots - Laravel Bluesky](/es/packages/laravel-bluesky/bot-tutorial.md)
- [Guía de actualización de Laravel 11 a 12](/es/blog/upgrade-11-to-12.md)
