Cómo Funciona el Protocolo @@
Una guía visual completa de la arquitectura de correo dividido reforzada — desde el envío hasta el descifrado. Las 6 debilidades críticas identificadas en la auditoría de seguridad v0 han sido corregidas (AES-256-GCM, envolvente criptográfica, hashing de tokens, límite de frecuencia, blindaje de PIN, billetera de clave de sesión).
flowchart TB
subgraph SEND["📤 SEND"]
A["1. Compose email to
user@@domain.com"]
B["2. Fetch recipient's
RSA-4096 public key"]
C["3. Build .eml file
(RFC 822: headers + body + attachments)"]
D["4. Compress with gzip level 9"]
E["5. Hybrid encryption:
AES-256-GCM (data) + RSA-4096 OAEP (AES key)
🔐 Authenticated encryption"]
F["6. ⚡ ENVELOPE detachment
eHead = encrypted AES key
eBody = nonce + tag + ciphertext"]
G["7. Store eBody on server
(SFTP external or local storage)
Referenced by hashed token"]
H["8. Generate download token
(256-bit, stored as SHA-256 hash)"]
I["9. Encrypt token with
recipient's public RSA key"]
J["10. Send regular email:
📎 eHead.bin attachment
🔑 Encrypted token in body"]
end
subgraph TRANSIT["📡 IN TRANSIT"]
K["eHead travels via SMTP
through mail servers"]
L["eBody NEVER travels
⬅ stays on server ⬅"]
end
subgraph RECEIVE["📥 RECEIVE"]
M["11. Recipient opens email
saves eHead attachment"]
N["12. Decrypts token with
private RSA key
🔑 Session key wallet (enter once)"]
O["13. Download page:
Token via POST/session
(no URL leak, hashed in DB)"]
P{"PIN required?"}
Q["Enter 6-digit PIN
🛡️ Progressive delay:
1s→2s→4s→8s→lockout"]
R{"2nd-channel (PWA)
enabled by sender?"}
S["📱 Authorize via PWA
on mobile phone"]
T["5-minute download window
🛡️ Rate-limited: 5 att/5min"]
U["14. Download eBody.bin"]
end
subgraph DECRYPT["🔓 FINAL DECRYPTION"]
V["15. Upload 2 files:
eHead.bin + eBody.bin
🔑 Key from session wallet"]
W["16. Parse envelope:
eHead → extract AES key
eBody → extract nonce+tag+ciphertext"]
X["17. Hybrid decrypt:
RSA-4096 decrypts AES key →
AES-256-GCM authenticates + decrypts"]
Y["18. Decompress (gzip)"]
Z["✅ Original .eml file
Openable in any email client"]
end
A --> B --> C --> D --> E --> F
F --> G
F --> H
G --> J
H --> I --> J
J --> K --> M
L -.-|"eBody never leaves the server"| U
M --> N --> O --> P
P -->|"Yes"| Q --> R
P -->|"No"| R
R -->|"Yes"| S --> T --> U
R -->|"No"| U
U --> V --> W --> X --> Y --> Z
style F fill:#ffc107,color:#333,stroke:#e0a800
style L fill:#dc3545,color:#fff,stroke:#c82333
style S fill:#ff6b6b,color:#fff,stroke:#e55a5a
style Z fill:#28a745,color:#fff,stroke:#1e7e34
| Parámetro | Especificación |
|---|---|
| Intercambio de Claves y Cifrado Asimétrico | RSA-4096 con relleno OAEP (SHA-256). Claves públicas servidas por HTTPS (dominio/PK/usuario) con respaldo en base de datos local. |
| Cifrado Simétrico (Datos) | AES-256-GCM con clave de 256 bits aleatoria y nonce de 96 bits aleatorio. Cifrado autenticado (confidencialidad + integridad en una sola pasada). |
| Autenticación del Mensaje | Tag de autenticación GCM (128 bits). Verificado antes de cualquier descifrado — la manipulación del texto cifrado se detecta y rechaza. Sin superficie de ataque de padding oracle. |
| Compresión | gzip nivel 9 (máximo) aplicado al .eml antes del cifrado. Reduce el tamaño del payload y aumenta la uniformidad de la entropía. |
| Token de Descarga | Token CSPRNG de 256 bits, almacenado como hash SHA-256 en la base de datos. El token en texto plano nunca persiste en el servidor. Transmitido por POST/sesión — nunca en query strings de URL. |
| Protección por PIN | PIN numérico opcional de 6 dígitos con retardo progresivo (retroceso exponencial: 1s→2s→4s→8s→16s). Combinado con límite de frecuencia por IP (5 intentos/5 min, bloqueo de 15 min). |
| Formato de Envolvente (Envelope) | eHead = versión(1B) + unique_id(16B) + clave_AES_cifrada(512B). eBody = versión(1B) + unique_id(16B) + nonce(12B) + tag_GCM(16B) + texto_cifrado. El byte de versión permite evolución del formato compatible hacia adelante. |
1. Redactar el correo
El remitente compone un mensaje dirigido a usuario@@dominio.com. La doble @ indica que será un correo cifrado de cuerpo dividido.
2. Obtener clave pública
El sistema busca la clave pública RSA-4096 del destinatario. Primero intenta en el dominio remoto (https://dominio/PK/usuario), y si falla, busca en la base de datos local.
3. Generar archivo .eml
Se genera un archivo .eml estándar RFC 822 con cabeceras (From, To, Subject, Date), cuerpo del mensaje y archivos adjuntos en base64.
4. Comprimir
El .eml se comprime con gzip a nivel máximo (9) para reducir su tamaño antes del cifrado.
5. Cifrado híbrido (AES-256-GCM + RSA-4096 OAEP)
Una clave AES-256 aleatoria cifra los datos comprimidos usando AES-256-GCM (cifrado autenticado). GCM proporciona confidencialidad e integridad sin necesidad de un HMAC separado. Luego, esa clave AES se cifra con la clave pública RSA-4096 del destinatario (relleno OAEP).
6. Separación por envolvente (envelope detachment)
En lugar de una división binaria ciega, el sistema crea una envolvente criptográfica: eHead = versión + unique_id + clave AES cifrada, eBody = versión + unique_id + nonce + tag GCM + texto cifrado. Cada parte es inútil sin la otra. Este es el enfoque moderno y seguro para la separación de payload.
7. Almacenar el eBody
El eBody se guarda en el servidor (almacenamiento SFTP externo o disco local). Se referencia mediante un token de descarga en hash SHA-256 — no por identificadores en texto plano. El eBody nunca viaja por correo electrónico — este es el núcleo del protocolo @@.
8. Generar token de descarga
Se genera un token criptográfico aleatorio de 256 bits. El token se almacena como hash SHA-256 en la base de datos — el token en texto plano nunca persiste en el servidor. Este token es necesario para descargar el eBody.
9. Cifrar el token
El token de descarga se cifra con la clave pública RSA del destinatario y se muestra como texto base64 en el cuerpo del correo.
10. Enviar el correo
Se envía un correo normal por SMTP (o Gmail API). El eHead se adjunta como .bin, y el token cifrado aparece en el cuerpo del correo junto con las instrucciones.
11. Recibir el correo
El destinatario recibe un correo normal con el eHead adjunto (archivo .bin) y un token cifrado en el cuerpo. Guarda el eHead en su dispositivo.
12. Descifrar el token
En la página Descifrar Token, el destinatario pega el token cifrado y su clave privada RSA. La clave puede guardarse en una billetera de sesión ("Recordar para esta sesión") para no tener que reingresarla en cada página. El sistema descifra el token y lo guarda en el servidor en la sesión — nunca se expone en URLs.
13. Ir a la página de descarga
El token se transmite por POST/sesión (no en query strings — evitando fugas en logs, proxies e historial del navegador). El token se convierte en hash SHA-256 antes de cualquier consulta a la base de datos. El límite de frecuencia permite 20 intentos por 5 minutos (bloqueo de 15 minutos al exceder).
14. Descargar el eBody
Tras pasar la verificación de PIN y/o la autorización PWA de segundo canal (si el remitente las activó), el archivo eBody se descarga. Los intentos de PIN están protegidos con retroceso exponencial (1s → 2s → 4s → 8s → 16s de espera) más límite de frecuencia por IP (5 intentos cada 5 minutos, 15 minutos de bloqueo). El endpoint download_action.php aplica la autorización de segundo canal de forma independiente.
15. Subir 2 archivos (clave desde billetera de sesión)
En la página de Descifrar, el destinatario sube eHead.bin y eBody.bin. La clave privada se carga automáticamente desde la billetera de sesión si está desbloqueada — no es necesario subir el archivo PEM en cada descifrado. Un botón "Bloquear Clave" limpia la billetera.
16. Analizar la envolvente criptográfica
El sistema detecta automáticamente la versión del protocolo (V1 GCM o V0 CBC legacy) y analiza la envolvente: eHead proporciona la clave AES cifrada (con versión y unique_id), eBody proporciona el nonce, el tag de autenticación GCM y el texto cifrado.
17. Descifrado híbrido (AES-256-GCM)
La clave privada RSA-4096 del destinatario descifra la clave AES-256 (desenvolvimiento OAEP). Luego AES-256-GCM verifica el tag de autenticación (comprobación de integridad) antes de descifrar — si los datos fueron alterados, el descifrado se rechaza. Sin vulnerabilidades de padding oracle.
18. Descomprimir
gzdecode descomprime los datos descifrados, obteniendo el archivo .eml original — legible en cualquier cliente de correo (Thunderbird, Outlook, etc.).
1. Autenticidad de Claves Públicas (MITM / Suplantación de Claves)
El protocolo @@ utiliza un modelo TOFU (Trust On First Use): la primera vez que un remitente obtiene la clave pública de un destinatario desde el servidor, confía en que es auténtica. Un servidor comprometido podría teóricamente entregar una clave pública falsa, permitiendo un ataque de intermediario (MITM).
Mitigaciones implementadas: (a) Las claves públicas se sirven exclusivamente por HTTPS, protegiendo contra manipulación a nivel de red. (b) La verificación de segundo canal por PWA (Tarea F) implica que un atacante que haya sustituido la clave tampoco puede descargar el eBody sin el código de verificación enviado al dispositivo del destinatario.
Riesgo residual: Un operador del servidor o un atacante con acceso a nivel de servidor podría sustituir claves. Los usuarios que requieran alta seguridad deben verificar las huellas (fingerprints) de las claves mediante un canal externo (ej. llamada telefónica, mensaje de Signal). Hay una página de huella de clave disponible en ?page=key-fingerprint&email=usuario@dominio.com. Versiones futuras podrían añadir registro de cambios de clave estilo Certificate Transparency y alertas de cambio de clave visibles al usuario (similar a los números de seguridad de Signal).
2. Perfect Forward Secrecy (PFS)
El protocolo @@ utiliza pares de claves RSA-4096 de larga duración. Si la clave privada de un destinatario se ve comprometida en el futuro, todos los mensajes históricos cifrados con esa clave pueden ser descifrados. Esta es una propiedad inherente del intercambio de claves basado en RSA — la misma limitación existe en PGP clásico y S/MIME.
Por qué se eligió RSA: Los pares de claves RSA-4096 pueden ser generados por el usuario en su propia máquina y la clave pública puede servirse desde cualquier endpoint HTTPS. Esto permite directorios de claves autoalojados sin requerir que el servidor participe en la generación de claves — una decisión arquitectónica deliberada para mantener el servidor como no confiable para el material criptográfico.
Defensa en profundidad: La verificación de segundo canal por PWA y el PIN opcional añaden capas de protección que no dependen del par de claves RSA. Incluso con la clave privada, un atacante no puede descargar el eBody sin el segundo factor.
Hoja de ruta futura: Añadir intercambio efímero de claves ECDH (X25519) junto a RSA para sesiones con forward secrecy está bajo consideración para el protocolo v2.
3. Exposición de Metadatos
Aunque el protocolo @@ cifra el contenido del mensaje (cuerpo + adjuntos), no oculta los metadatos de comunicación: identidad del remitente, identidad del destinatario, marcas de tiempo, frecuencia de mensajes y tamaño aproximado del mensaje siguen siendo visibles a través de las cabeceras SMTP y los registros del servidor.
Por qué es difícil de corregir: Los metadatos del correo electrónico son inherentes a SMTP — los servidores de correo necesitan remitente/destinatario para enrutar mensajes. Ocultar metadatos requeriría reemplazar SMTP, lo cual está fuera del alcance de @@ (que está diseñado para funcionar CON la infraestructura de correo existente).
Mitigaciones: La separación eHead/eBody significa que el servidor solo ve blobs cifrados sin contenido. Los registros de descarga tienen límite de frecuencia y usan hashes. Para usuarios que requieran protección de metadatos, el protocolo @@ debe combinarse con una solución a nivel de transporte como Tor.
4. Confianza en el JavaScript Servido (Problema del Cifrado Web)
El cifrado y descifrado ocurren en el navegador usando JavaScript servido por el servidor web. Un servidor comprometido o malicioso podría servir JavaScript modificado que extraiga texto plano o claves privadas antes del cifrado.
Esta es una limitación fundamental de TODOS los sistemas criptográficos basados en navegador — incluyendo el cliente web de Proton Mail, el cliente web de Tutanota, y cualquier otra solución de cifrado de correo web. No existe una solución completa sin migrar a una aplicación nativa con binarios firmados.
Mitigaciones implementadas: (a) Todo el código de cifrado/descifrado está en JavaScript públicamente visible (no minificado ni ofuscado) — los usuarios pueden inspeccionar el código fuente. (b) La página de descifrado (decrypt.php) puede descargarse y ejecutarse localmente/sin conexión. (c) Versiones futuras añadirán hashes de Subresource Integrity (SRI) en todas las etiquetas de script.
✅ Defendido Contra
- Escucha pasiva de red (HTTPS + AES-256-GCM)
- Atacantes activos de red entre remitente y servidor de correo (HTTPS)
- Operador del servidor leyendo contenido de mensajes (cifrado en cliente, división eHead/eBody)
- Fuga de token de descarga por logs de URL (POST/sesión, hash SHA-256 en BD)
- Ataques de fuerza bruta al PIN o token (límite de frecuencia + retroceso exponencial)
- Ordenador cuántico derivando clave privada de clave pública (2º canal PWA + PIN)
⚠️ No Defendido Contra (Riesgo Residual)
- Suplantación de clave a nivel de servidor / servidor malicioso (limitación del modelo TOFU)
- Análisis de metadatos de comunicación (cabeceras SMTP en texto claro por diseño)
- Descifrado de mensajes históricos tras compromiso futuro de clave (sin PFS con RSA)
- Ataques a la cadena de suministro de JavaScript (inherente al cifrado en navegador)
- Compromiso del endpoint (malware, keyloggers, extensiones de navegador)