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 móvil y el servidor de la empresa. Nosotros solo transportamos texto cifrado.
- Nunca generamos ni vemos las llaves privadas: la tuya nace en tu móvil; la de la empresa, en su infraestructura.
- Verificamos a las empresas y firmamos su llave pública; la app 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.
- No hay forward secrecy en esta versión.
- Somos el directorio de llaves de los dos lados: sin la protección extra del link, un operador malicioso activo (nosotros) podría sustituir una llave en el primer contacto.
Cómo se cifra un mensaje (sobre v1, sc1)
Usamos libsodium, una biblioteca criptográfica auditada y extendida. Las piezas:
| Pieza | Construcción |
|---|---|
| Identidad (tu dispositivo y la empresa) | Par de llaves X25519 |
| Clave de la conversación | 32 bytes aleatorios generados por tu móvil 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 id 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
Fotos y documentos se cifran en el dispositivo que los envía (tu móvil o el servidor de la empresa), igual que el texto:
- Cada fichero tiene su propia clave de 32 bytes, aleatoria, distinta de la de la conversación.
- Se cifra en trozos de 64 KiB con XChaCha20-Poly1305. Cada trozo va autenticado junto con el identificador del adjunto, su posición y si es el último: reordenar, recortar o añadir trozos hace fallar el descifrado.
- La clave del fichero, 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 cuadra, muestra "No se pudo descifrar este adjunto" y nunca un fichero a medias.
- Nosotros solo guardamos bytes opacos y un identificador. Vemos el tamaño del fichero 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 fichero. No generamos miniaturas (no podemos: no vemos el contenido); la app crea la vista previa después de descifrar.
Qué protege
- Una fuga 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.
- 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. Allí el mensaje se descifra. Si la empresa lo reenvía en claro a un helpdesk o CRM en la nube, ese proveedor lo ve. Si trabajas en un sector regulado, pregunta a la empresa dónde acaba el texto.
- Nosotros actuando de forma activa. Tu app recibe la llave de la empresa de nuestro servidor, y la empresa recibe la tuya también 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 link (abajo) cierra ese hueco cuando la invitación llega por link generado con el SDK.
- Un dispositivo comprometido. Si alguien controla tu móvil o el servidor de la empresa, puede leer los mensajes allí.
- Los metadatos. Ver 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 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 link.
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 privada pasara por nuestros servidores, la promesa dejaría de ser verificable.
Empresas sin verificar: entorno de 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 has activado Modo pruebas en Ajustes → Diagnóstico. Viene desactivado: un cliente normal nunca acaba en una conversación de pruebas por error, aunque le llegue el link.
- Esas conversaciones muestran siempre 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 hemos comprobado quién es la empresa.
La huella en el link de invitación
Cuando la empresa crea la invitación con el SDK, añade al link un fragmento #s=…&fp=…. El navegador no envía el fragmento al servidor, así que nosotros no lo vemos, pero el link viaja por WhatsApp, un canal que no controlamos. Al canjear:
- La app comprueba que la llave de la empresa que le damos tiene la huella
fpdel link. - 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 link, 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 a 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 suave ("la empresa renovó su llave de seguridad; lo ha firmado la propia empresa").
- Sin firma, o firmada con otra llave: aviso prominente. Conviene confirmar con la empresa por otro canal antes de seguir. Las empresas que no cargaron 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 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 los dos casos. En esta versión 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 claves en cada mensaje para evitarlo; lo hemos dejado fuera de la primera versión de forma deliberada y está en el plan.
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, direcciones IP y datos del dispositivo. Son suficientes para inferir bastante, y por eso los 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.