Cómo funciona nuestro cifrado de extremo a extremo
Última actualización: junio de 2026
Resumen ejecutivo
- Tus datos se cifran en tu dispositivo y solo salen de él como texto cifrado ilegible. Nuestro servidor almacena únicamente blobs cifrados y no tiene acceso al texto plano.
- Todas las claves se derivan de un código de recuperación de 128 bits que nunca abandona tu dispositivo. No lo conocemos ni podemos recuperarlo.
- Cada registro individual se cifra con su propia clave y se verifica su autenticidad antes de descifrarse (Verify-before-Decrypt con Ed25519).
- E2EE no protege todo: ciertos metadatos (volumen de datos, tiempos de acceso) permanecen visibles, y un dispositivo comprometido o un código de recuperación perdido no pueden salvarse con criptografía.
Qué significa «extremo a extremo» para nosotros
Cifrado de extremo a extremo significa: el texto plano de tus datos existe solo en tus propios dispositivos. El cifrado y descifrado ocurren exclusivamente en local. Lo que se sincroniza entre dispositivos y se almacena en nuestro servidor siempre está ya cifrado antes de salir del dispositivo.
Concretamente: una fila de datos se codifica canónicamente a JSON en el cliente y luego se cifra con un procedimiento AEAD. El servidor recibe solo un blob opaco de bytes más algunos campos administrativos. No posee ninguna de las claves necesarias para descifrar. Es una propiedad arquitectónica, no una promesa: como las claves nunca llegan al servidor, este técnicamente no puede leer el contenido.
Haga clic en los componentes para ver detalles:
Dispositivo A (Remitente)
Los datos se cifran localmente con AES-256-GCM. El código de recuperación y las claves derivadas nunca salen del dispositivo.
Cómo se cifran tus datos
Utilizamos componentes probados y estandarizados de las bibliotecas @noble/ciphers, @noble/hashes y @noble/curves:
- AES-256-GCM cifra tus registros. AES-256-GCM es un procedimiento AEAD que simultáneamente asegura confidencialidad (nadie lee) e integridad (la manipulación se detecta). Cada registro utiliza un Nonce de 12 bytes aleatorio y un código de autenticación (MAC) de 16 bytes. Formato: nonce(12) ‖ ciphertext ‖ mac(16).
- XChaCha20-Poly1305 cifra el material clave durante el emparejamiento de dispositivos (Key-Wrapping). También es un procedimiento AEAD, pero utiliza un Nonce más largo de 24 bytes, lo que hace que los Nonces aleatorios sean indiferentes.
- AAD (Associated Data) vincula cada texto cifrado a sus metadatos — encabezado, Bucket, UUID del registro, revisión, Key-Epoch, versión del esquema y longitud rellena. Estos campos están autenticados conjuntamente: si se altera aunque sea uno, el descifrado falla. AAD vacío se rechaza duramente (protección Confused-Deputy).
- Padding oculta el tamaño exacto: cada registro se rellena a un tamaño de Bucket (256, 1024, 4096, 16384 o 65536 bytes; por encima, múltiplos de 65536). Así, el tamaño del blob solo revela una clase aproximada, no la cantidad exacta de datos.
- Firma Ed25519 (blob_sig) firma cada blob. Antes de cada descifrado, el cliente verifica esta firma contra las claves de dispositivo autorizadas (Verify-before-Decrypt). La verificación se ejecuta estrictamente RFC-8032 (zip215:false), lo que excluye falsificaciones mediante puntos de orden bajo. Los datos manipulados resultan en un error inmediato, no en un defecto silencioso.
Tus claves permanecen en tu dispositivo
La raíz de todo es una entropía de recuperación de 128 bits — el código de recuperación. A partir de estos 16 bytes aleatorios, con HKDF-SHA256 (una función de derivación de claves que genera muchas claves separadas por dominio a partir de un secreto) se deriva determinísticamente un Master-Secret y de este otros secretos: un ID de cuenta, una clave de cifrado de claves, la clave de autenticación (authSeed) y la clave de enrutamiento. Cada derivación utiliza su propio label versionado (p. ej. mypep/master/v1), de modo que las claves no se superponen.
Por colección hay una clave de colección propia, y por registro y revisión una clave de registro propia (rec/<uuid>/<rev>). Esta clave propia por (registro, revisión) proporciona separación completa de claves: ninguna clave AES-GCM se usa jamás dos veces — una protección fuerte contra ataques de reutilización de Nonce.
El Master-Secret se no almacena deliberadamente. Localmente solo residen los valores derivados y las claves de firma/envoltura propias del dispositivo — en el navegador en IndexedDB.
Haga clic en una clave para ver detalles:
Código de recuperación
Entropía aleatoria de 128 bits. La clave raíz absoluta. Generada al crear la cuenta. Nunca sale del dispositivo.
Recuperación — función y responsabilidad: todo el árbol de claves cuelga del código de recuperación. No lo almacenamos; una puerta trasera, depósito de claves o reinicio del lado del servidor están arquitectónicamente excluidos — no solo por política, sino porque las claves técnicamente nunca llegan al servidor. Este es el núcleo del E2EE genuino: nadie excepto tú — ni siquiera nosotros — puede restaurar tus datos sin el código de recuperación o un dispositivo emparejado. Si se pierde el código y no existe más ningún dispositivo acoplado, los datos son permanentemente inaccesibles.
Qué ve nuestro servidor — y qué no
El servidor almacena solo blobs cifrados. No ve: el contenido de tus registros, los nombres de tus colecciones (aparecen solo como un Bucket HMAC-SHA256 opaco) o tus claves.
Para ser honesto, sí ve algunos metadatos: los valores de Bucket opacos, las revisiones del registro, la clase de tamaño aproximada mediante Padding, la frecuencia de sincronización, IDs de dispositivo (como hash SHA-256 de las claves del dispositivo) y la posición del cursor en la sincronización. A partir de esto se puede deducir que una cuenta está activa y aproximadamente cuántos datos o cuáles de tamaño se mueven cuándo — pero no de qué se trata contenidamente.
La resolución de conflictos se ejecuta puramente sobre revisiones (la revisión más alta gana, "Last-Write-Wins"), porque el servidor no conoce el contenido y no puede fusionarlos basándose en el contenido. La autenticación ocurre mediante Challenge-Response con Ed25519 y un posterior token JWT; la lista de dispositivos se firma con tu clave de autenticación y se verifica exclusivamente del lado del cliente.
Múltiples dispositivos (Emparejamiento)
Un dispositivo nuevo, por ejemplo el navegador, se empareja con el teléfono mediante código QR. El código QR transmite las claves públicas del dispositivo del navegador directamente (fuera de banda), no a través del servidor — esto protege el intercambio de claves de ataques de intermediario. El teléfono empaqueta el bundle de identidad (claves de datos de cuenta, clave de autenticación, ID de cuenta, clave de enrutamiento) por X25519-ECDH y XChaCha20-Poly1305 exclusivamente para el navegador y lo transmite cifrado.
Después de descifrar, el navegador muestra una huella digital (SHA-256 del ID de cuenta, como grupos hexadecimales). Si coincide con la pantalla del teléfono, se asegura que has recibido el bundle correcto. Los clientes web no tienen su propio código de recuperación: si pierdes el almacenamiento del navegador, simplemente vuelves a emparejar con el teléfono.
Flujo de emparejamiento
El navegador genera claves temporales y las muestra como un código QR. El teléfono lo escanea directamente. Al hacerse directamente por cámara (fuera de banda), el intercambio es inmune a ataques Man-in-the-Middle.
Lo que ESTO NO protege
E2EE es fuerte, pero no una panacea. Siendo honestos sobre los límites:
- Dispositivo comprometido: malware en el contexto del navegador o acceso directo a IndexedDB puede leer las claves almacenadas localmente y así descifrar todo. La base de datos local se encuentra en texto plano.
- Código de recuperación perdido: sin código y sin dispositivo emparejado, no hay camino de regreso. No existe rotación de claves ni mecanismo de copia de seguridad.
- Metadatos: volúmenes de datos, clases de tamaño, patrones de acceso y puntos de tiempo permanecen visibles para el servidor.
- Blobs de fotos: las fotos se direccionan por contenido (
blob_id = sha256(blob)). Quien ya posea un texto plano puede comprobar si exactamente esta foto fue cargada. - Servidor malicioso: no puede leer o falsificar el contenido (Verify-before-Decrypt protege), pero podría retener datos o volver a entregar listas de dispositivos antiguas firmadas (Replay). El daño de tal Replay es limitado: el dispositivo se registra idempotentemente, de modo que una lista antigua reproducida no sobrescribe el estado actual. El servidor no puede inventar nuevos datos válidos.
- Clave de autenticación: quien obtenga la clave de autenticación puede cambiar la lista de dispositivos y re-autenticarse. Debe mantenerse secreta.
Los componentes criptográficos en perspectiva general
- AES-256-GCM — cifrado de registros (AEAD); Nonce de 12 bytes, MAC de 16 bytes.
- XChaCha20-Poly1305 — Key-Wrapping en emparejamiento (AEAD); Nonce de 24 bytes, MAC de 16 bytes.
- Argon2id v1.3 — derivación basada en contraseña, resistente a memoria (estándar: 64 MiB, 3 iteraciones, 4 carriles); disponible para futuras funciones basadas en contraseña, pero NO para el código de recuperación — este ya es entropía aleatoria de 128 bits y no necesita dureza de memoria.
- HKDF-SHA256 — derivación de todas las claves del código de recuperación, separadas por dominio mediante labels versionados; salida de 32 bytes.
- HMAC-SHA256 — enrutamiento opaco de colecciones (cálculo de Bucket).
- SHA-256 — hash para huellas digitales, IDs de dispositivo y direccionamiento de fotos.
- Ed25519 (RFC-8032-estricto, zip215:false) — firmas para registros, lista de dispositivos y autenticación.
- X25519-ECDH — intercambio de claves en emparejamiento de dispositivos.
- Buckets de Padding (256 B a 65536 B, por encima múltiplos de 65536) — ofuscación de tamaño.
- Longitud de clave consistentemente 32 bytes (256 bits).