Seguridad
Un modelo de confianza que se explica se puede auditar; uno que se esconde, no. Esto es lo que hace SecureChat, y también lo que no hace.
En resumen
- Los mensajes se cifran de extremo a extremo entre tu teléfono y el servidor de la empresa. Nosotros solo transportamos texto cifrado.
- Nunca generamos ni vemos las llaves privadas: la tuya se genera en tu teléfono; la de la empresa, en su infraestructura.
- Verificamos a las empresas y firmamos su llave pública; la app te avisa si esa llave cambia.
- El cifrado termina en el backend de la empresa: lo que haga con el texto descifrado queda fuera de nuestro control.
- La versión actual del protocolo no ofrece forward secrecy.
- Somos el directorio de llaves de ambos lados: sin la protección adicional del enlace, un operador malicioso activo (nosotros) podría sustituir una llave en el primer contacto.
Cómo se cifra un mensaje (sobre v1)
Usamos libsodium, una biblioteca criptográfica auditada y ampliamente utilizada. Estas son las piezas del sobre v1 (sc1):
| Pieza | Construcción |
|---|---|
| Identidad (tu dispositivo y la empresa) | Par de llaves X25519 |
| Clave de la conversación | 32 bytes aleatorios generados por tu teléfono al canjear la invitación. Si la generáramos nosotros, la conoceríamos. |
| Reparto de esa clave | Se sella por separado (crypto_box_seal) para tu llave pública y para la de la empresa. Nosotros solo guardamos los dos sobres sellados. |
| Cifrado de cada mensaje | XChaCha20-Poly1305 con nonce aleatorio de 24 bytes |
| Datos asociados | Cada mensaje queda ligado a su conversación, a quién lo envía, a su identificador y a la versión de llave. Un servidor no puede moverlo de conversación, duplicarlo con otro identificador ni hacer pasar un mensaje tuyo por uno de la empresa. |
| Relleno | Hasta múltiplos de 256 bytes, para ocultar la longitud exacta |
| Firma de la llave de empresa | Ed25519, con la llave de plataforma |
| Firma de la rotación de llave | Ed25519, con la llave de firma de la propia empresa (más abajo) |
| Huellas | BLAKE2b-256 con separación de dominio |
Adjuntos cifrados
Las fotos y los documentos se cifran en el dispositivo que los envía (tu teléfono o el servidor de la empresa), igual que el texto:
- Cada archivo tiene su propia clave de 32 bytes, aleatoria y distinta de la de la conversación.
- Se cifra en fragmentos de 64 KiB con XChaCha20-Poly1305. Cada fragmento se autentica junto con el identificador del adjunto, su posición y si es el último: reordenar, recortar o agregar fragmentos hace fallar el descifrado.
- La clave del archivo, su nombre, tipo, tamaño y huella (BLAKE2b) viajan dentro de un mensaje cifrado normal. Al terminar, la app comprueba la huella; si algo no coincide, muestra “No se pudo descifrar este adjunto” y nunca un archivo a medias.
- Nosotros solo guardamos bytes opacos y un identificador. Vemos el tamaño del archivo cifrado, que es prácticamente el del original: los adjuntos no se rellenan como los mensajes. Solo los dos extremos de la conversación pueden subirlo y descargarlo, con enlaces temporales de 5 minutos.
- Máximo 25 MB por archivo. No generamos miniaturas (no podemos: no vemos el contenido); la app crea la vista previa después de descifrar.
Qué protege
- Una filtración de nuestra base de datos o de nuestras copias de seguridad: solo contiene texto cifrado.
- Un empleado curioso con acceso a los servidores.
- Un atacante pasivo en la red, o cualquiera que intercepte el tráfico.
- Las notificaciones push: no llevan el contenido, así que ni Apple ni Google lo ven.
- La manipulación de mensajes en tránsito o en nuestros servidores: el descifrado falla en lugar de mostrar un texto alterado.
Qué no protege
- El otro extremo es el backend de la empresa. Ahí se descifra el mensaje. Si la empresa lo reenvía sin cifrar a un helpdesk o CRM en la nube, ese proveedor lo ve. Si trabajas en un sector regulado, pregúntale a la empresa dónde termina el texto.
- Nosotros, actuando de forma activa. Tu app recibe la llave de la empresa de nuestro servidor, y la empresa también recibe la tuya de nosotros. Un operador malicioso podría sustituir cualquiera de las dos. La app fija la llave de la empresa en el primer contacto y avisa si cambia, pero eso no protege justo ese primer contacto. La huella del enlace (más abajo) cierra ese hueco cuando la invitación llega por un enlace generado con el SDK.
- Un dispositivo comprometido. Si alguien controla tu teléfono o el servidor de la empresa, puede leer los mensajes ahí.
- Los metadatos. Los explicamos más abajo.
Llave de plataforma y verificación de empresas
Antes de que una empresa pueda invitar, comprobamos su existencia legal, que controla su dominio (registro DNS) y el número de WhatsApp desde el que invita. Después firmamos su llave pública con nuestra llave de plataforma Ed25519. La app verifica esa firma y muestra la insignia de Empresa verificada.
Llave pública de plataforma (Ed25519, base64url):
qxh_sOak_wQVqZifJjDcoy-TeWIF3NADjqsjta0GPlw
Lo que se firma es exactamente SecureChat|v1|company-key|<companyId>|<keyVersion>|<llave pública>. Esto concentra el riesgo en nosotros: si alguien robara la llave de plataforma, podría suplantar a una marca. Por eso existe también la comprobación del enlace.
La empresa genera su propio par de llaves en su infraestructura con nuestro SDK (npx @securechat/sdk keygen) y solo nos sube la pública. El portal no ofrece generarla en el navegador: si la llave privada pasara por nuestros servidores, la promesa dejaría de ser verificable.
Empresas sin verificar y Modo pruebas
Para que una empresa pueda probar su integración mientras la revisamos, puede crear invitaciones de pruebas. Su llave no está firmada como verificada, así que cualquiera podría registrarse como “Banco X” y usarlas para suplantar a una marca. Por eso:
- La app solo abre una invitación de pruebas si activaste Modo pruebas en Configuración → Diagnóstico. Viene desactivado: un cliente normal nunca termina en una conversación de pruebas por error, aunque le llegue el enlace. No lo actives porque alguien te lo pida: una empresa real no lo necesita para hablar contigo.
- Esas conversaciones siempre muestran la franja “Empresa sin verificar · entorno de pruebas” y nunca la insignia de verificada.
- Tienen límites estrictos: 5 conversaciones activas por empresa, 200 mensajes de la empresa al día e invitaciones de 24 horas como máximo. Cuando verificamos a la empresa, sus conversaciones de pruebas se cierran.
El cifrado es el mismo que en una conversación normal. Lo que cambia es la garantía de identidad: en una conversación de pruebas no comprobamos quién es la empresa.
La huella en el enlace de invitación
Cuando la empresa crea la invitación con el SDK, agrega al enlace un fragmento #s=…&fp=…. El navegador no envía el fragmento al servidor, así que nosotros no lo vemos, pero el enlace viaja por WhatsApp, un canal que no controlamos. Al canjearla:
- La app comprueba que la llave de la empresa que le damos tiene la huella
fpdel enlace. - La app liga su propia llave al secreto
scon un MAC, y la empresa lo verifica.
Si sustituyéramos cualquiera de las dos llaves, uno de los dos extremos lo detectaría. Límites: solo cubre el canje por enlace, no el código corto tecleado, y las invitaciones creadas a mano desde el portal no llevan ese secreto.
Rotación de llave firmada por la empresa
Además de su llave de cifrado, la empresa genera con el SDK una llave de firma Ed25519 que también se queda en su infraestructura; solo nos sube la pública. La app la fija en el primer contacto, junto con la de cifrado. Cuando la empresa rota su llave de cifrado, firma el cambio con esa llave de firma: SecureChat|v1|company-key-rotation|<companyId>|<versión anterior>|<llave anterior>|<versión nueva>|<llave nueva>. Comprobamos la firma antes de aceptar la llave nueva y la app la vuelve a comprobar.
- Rotación firmada por la llave fijada: aviso discreto (“la empresa renovó su llave de seguridad; la propia empresa firmó el cambio”).
- Sin firma, o firmada con otra llave: aviso destacado. Conviene confirmar con la empresa por otro canal antes de continuar. Las empresas que no cargaron una llave de firma siempre rotan así.
Por qué importa: con solo nuestra firma de plataforma, una rotación legítima y una suplantación nuestra se verían igual. Con la firma de la empresa, suplantar a una empresa que ya tienes fijada exige su llave de firma, que nunca pasa por nosotros. La firma de plataforma sigue siendo obligatoria en ambos casos. Por ahora la llave de firma no rota: cambiarla se trata como una rotación sin firmar.
Sin forward secrecy en v1
Cada conversación usa una clave estable. Si en el futuro se filtrara tu llave privada o la de la empresa, junto con los mensajes cifrados guardados, se podrían descifrar también los mensajes anteriores de esa conversación. Protocolos como Signal renuevan las claves con cada mensaje para evitarlo; lo dejamos fuera de la primera versión del protocolo de forma deliberada y está en nuestra hoja de ruta.
Metadatos
Aunque no veamos el contenido, vemos quién habla con qué empresa, cuándo y con qué frecuencia, el tamaño aproximado de cada mensaje (redondeado a 256 bytes), el tamaño y la fecha de cada adjunto, las direcciones IP y datos del dispositivo. Con eso se puede inferir bastante, y por eso lo declaramos en la política de privacidad.
El historial está ligado a tu dispositivo: si lo pierdes, recuperas cada conversación con una nueva invitación de la empresa, que vuelve a sellar la clave para tu dispositivo nuevo.
Reportar una vulnerabilidad
Escríbenos a soporte@securechat-app.com con el asunto “Seguridad”. Te pedimos un plazo razonable para corregirla antes de publicarla.