---
name: seal_key_box
kind: function
lang: go
domain: cybersecurity
version: "1.0.0"
purity: impure
signature: "func SealKeyBox(recipientKexPub, secret []byte) ([]byte, error)"
description: "Cifra un secreto (típicamente una room key simétrica) para un destinatario identificado por su clave pública X25519, usando un sealed box anónimo (nacl/box). El emisor no se autentica; usar SignEd25519 por separado si se necesita autenticación del remitente."
tags: [messaging, e2e-crypto, crypto, nacl, x25519, sealed-box, key-distribution, e2e-messaging]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports:
  - crypto/rand
  - golang.org/x/crypto/nacl/box
params:
  - name: recipientKexPub
    desc: "Clave pública X25519 del destinatario (exactamente 32 bytes). Viene del campo KexPub de su Identity."
  - name: secret
    desc: "Bytes a cifrar. Típicamente una room key de 32 bytes, pero puede ser cualquier secreto."
output: "Sealed box cifrado (overhead: 32 bytes de ephemeral pubkey + 16 bytes de tag Poly1305), o error si recipientKexPub no tiene 32 bytes o falla el RNG."
tested: true
tests:
  - "round-trip con identidad generada"
  - "error con recipientKexPub de longitud incorrecta"
  - "error al abrir con clave equivocada"
  - "error con mensaje truncado"
test_file_path: "functions/cybersecurity/e2e_messaging_crypto_test.go"
file_path: "functions/cybersecurity/seal_key_box.go"
---

## Ejemplo

```go
// Distribuir room key al usuario al unirse a la sala
roomKey := make([]byte, 32) // generada por el servidor de sala
sealed, err := cybersecurity.SealKeyBox(user.KexPub, roomKey)
if err != nil {
    log.Fatal(err)
}
// Enviar sealed al usuario; solo él puede abrirlo con OpenKeyBox
```

## Cuando usarla

Al distribuir una clave simétrica de sala a un nuevo participante: cifra la room key con la KexPub del destinatario antes de transmitirla. El destinatario usa OpenKeyBox para recuperarla. Combinar con SignEd25519 sobre el sealed box si se necesita autenticar que el servidor distribuyó la clave.

## Gotchas

- El sealed box es anónimo: el receptor no puede verificar quién lo generó. Firmar el sealed box con SignEd25519 si la autenticación del emisor importa.
- Overhead fijo: 48 bytes adicionales sobre el secreto (32 ephemeral pubkey + 16 tag).
- El sealed box no puede abrirse sin la clave privada X25519 correspondiente: si el usuario pierde KexPriv, la room key es irrecuperable.
- `recipientKexPub` debe tener exactamente 32 bytes; la función valida y devuelve error claro si no.
