--- name: seal_aead kind: function lang: go domain: cybersecurity version: "1.0.0" purity: impure signature: "func SealAEAD(key, plaintext, aad []byte) (nonce, ciphertext []byte, err error)" description: "Cifra plaintext con ChaCha20-Poly1305 usando una clave simétrica de 32 bytes. Genera un nonce aleatorio por llamada. Admite datos autenticados adicionales (AAD) para vincular contexto al cifrado sin cifrarlo." tags: [messaging, e2e-crypto, crypto, aead, chacha20poly1305, symmetric, e2e-messaging] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: - crypto/rand - golang.org/x/crypto/chacha20poly1305 params: - name: key desc: "Clave simétrica de exactamente 32 bytes (256 bits). Típicamente la room key distribuida con SealKeyBox." - name: plaintext desc: "Bytes a cifrar. Puede ser vacío." - name: aad desc: "Datos autenticados adicionales (AAD): se autentican pero no se cifran. Útil para room ID, número de secuencia, etc. Puede ser nil." output: "nonce (12 bytes aleatorios), ciphertext (plaintext cifrado + 16 bytes de tag Poly1305), o error si la clave tiene longitud incorrecta o falla el RNG." tested: true tests: - "round-trip con aad" - "round-trip sin aad (nil)" - "error con clave de longitud incorrecta" - "error de autenticacion con ciphertext modificado" - "error de autenticacion con aad distinto" - "nonces distintos en llamadas sucesivas" test_file_path: "functions/cybersecurity/e2e_messaging_crypto_test.go" file_path: "functions/cybersecurity/seal_aead.go" --- ## Ejemplo ```go key := make([]byte, 32) // en producción: room key distribuida con SealKeyBox aad := []byte("room:sala-general:seq:42") nonce, ct, err := cybersecurity.SealAEAD(key, []byte("hola sala"), aad) if err != nil { log.Fatal(err) } // Almacenar nonce junto al ciphertext para descifrar después ``` ## Cuando usarla Al cifrar cada mensaje en una sala del bus: usa la room key de la sala como `key`, incluye el ID de sala y número de secuencia en `aad` para prevenir replay attacks entre salas, y transmite `nonce + ciphertext` juntos al destinatario. ## Gotchas - El nonce es aleatorio (12 bytes): con una misma key, la probabilidad de colisión de nonces es despreciable para <2^32 mensajes, pero en escenarios de alto volumen considera rotar la room key periódicamente. - El ciphertext es 16 bytes más largo que el plaintext (tag Poly1305). - `aad` no viaja cifrado: el destinatario debe reconstruirlo independientemente para verificar. Si aad difiere aunque sea 1 bit, OpenAEAD falla con error de autenticación. - Nunca reutilizar `(key, nonce)` para dos plaintexts distintos: rompe la confidencialidad de ChaCha20.