Auditable · Open Source · AGPL-3.0

Seguridad y criptografía

No te pedimos que confíes en nuestra palabra. Noctcom está hecho para que, aunque quisiéramos, no podamos leer tus archivos: tus claves nacen y se quedan en tu dispositivo, y al servidor solo le llega cifrado que no sabe abrir. Aquí te contamos exactamente cómo, sin rodeos. Y si algo de esta página no cuadra con el código, abre un issue — al final manda el código, no las promesas.

Primitivas criptográficas

FunciónAlgoritmoParámetros
KDFArgon2idOPSLIMIT_MODERATE, 256 MiB
AEADXChaCha20-Poly1305nonce 24B, tag 16B
HKDFBLAKE2b-keyedoutput 32B
FirmasEd25519RFC 8032
Key ExchangeX25519RFC 7748
Sealed BoxesX25519 + XSalsa20-Poly1305nonce derivado
HashBLAKE2b-256output 32B

Jerarquía de claves

// Derivación completa desde la contraseña

password

│ Argon2id(salt, opsLimit, memLimit)

Master Key (MK)

├── BLAKE2b("vault.wrap") → K_vault_wrap

│ └── Unwrap → vault_key → file_key → chunks

├── BLAKE2b("login.sign") → seed → Ed25519 keypair

└── Unwrap → sk_exchange (X25519)

// Rama paralela: la frase de recuperación (12 palabras BIP39)

mnemónica

│ BLAKE2b(key="recovery.v1")

recovery seed

├── Ed25519 → firma el challenge de recuperación

└── BLAKE2b("recovery.box.v1") → X25519 → abre los seals del kit

Recuperación de cuenta (kit v2)

Tu frase de 12 palabras (BIP39, 128 bits de entropía) no solo recupera el acceso: recupera también tus archivos. De ella se deriva un par X25519 cuya clave pública queda registrada en el servidor; con esa pública, tu navegador sella (crypto_box_seal) la clave de cada bóveda y tu clave de intercambio. Sellar solo necesita la pública — abrir los seals, solo la privada, que únicamente existe si tienes la frase.

Olvidaste la contraseña → nada se pierde

La frase firma un reto, el servidor entrega los seals, tu navegador los abre y re-cifra las claves de bóveda con tu nueva contraseña. Los archivos y lo que te han compartido siguen contigo.

El servidor solo guarda sobres cerrados

Los seals son ciphertext: ni Noctcom ni un atacante con la base de datos pueden abrirlos. La privada que los abre se deriva de tu frase y nunca viaja.

Pierdes frase Y contraseña → irrecuperable

No hay puerta trasera, ni 'contacta con soporte'. Es el precio del zero-knowledge real, y lo decimos sin letra pequeña.

Cifrado de archivos

Chunks de 4 MiB

Cada archivo se divide en chunks de 4 MiB, cifrados independientemente con XChaCha20-Poly1305. Cada chunk usa un nonce aleatorio de 24 bytes.

AAD anti-reorder

Cada chunk incluye su índice como Additional Authenticated Data (AAD = 'chunk:N'). Impide que un atacante reordene chunks.

Content hash

BLAKE2b-256 sobre todos los chunks cifrados. Verifica integridad en cada descarga.

Zero-knowledge email

// El servidor nunca ve tu email

email_hash = BLAKE2b(

message = normalize(email),

key = "noctcom.email.v1",

output = 32 bytes

)

Auditorías externas

Aún no se han realizado auditorías externas. Cuando se completen, los reportes completos se publicarán aquí y en el repositorio.

Mientras tanto, el código es 100% auditable en GitHub.

Audita el código tú mismo

Todo el código es público bajo AGPL-3.0. Las implementaciones de referencia están en backend/src/crypto/ y frontend/lib/crypto.ts