Autor: C3r0d4y
Bóveda de cifrado de archivos donde todo el cifrado ocurre en el navegador (Web Crypto API). El servidor nunca recibe contraseñas ni archivos en claro: solo almacena, de forma temporal y opcional, el blob ya cifrado para la función de enlace de descarga única.
El repositorio contiene dos aplicaciones que hablan el mismo formato:
| Aplicación | Dónde vive | Para qué sirve |
|---|---|---|
| Cryptum (web) | raíz del repositorio | Cifrar y descifrar desde el navegador, en el servidor de la unidad |
| Cryptum Portable | portable/ |
Abrir ese mismo material en el destino, sin internet y sin instalar nada |
El caso de uso es el despliegue: el material se cifra en el servidor antes de salir, viaja en una memoria USB, y en destino se abre con la aplicación portátil en cualquier equipo Linux o Windows, sin necesidad de alcanzar el servidor.
https://cryptum.ciberdefensa.com.mx/
Instancia pública de demostración. Funciona igual que la instalación local, con dos diferencias: la detección automática de dispositivos USB (
/api/list-usb) está deshabilitada porque solo opera desdelocalhost, y los enlaces seguros de esa instancia expiran igual a los 5 minutos. No debe usarse para material sensible real: es un entorno de prueba.
| Función | Descripción |
|---|---|
| Cifrar archivo | AES-256-GCM en el navegador; produce un archivo .c3v |
| Enlace seguro | El blob cifrado sube a la bóveda; enlace de una sola descarga que expira en 5 minutos |
| Descifrar | Por enlace recibido o subiendo un .c3v local |
| Cifrado de carpeta | Cifra o descifra todos los archivos de una carpeta con una sola clave maestra |
| Cifrado USB | Igual que el de carpeta, más la detección de discos removibles y la guía de cifrado LUKS |
| App portátil | Enlace en la barra superior que entrega cryptum-portable.zip junto a un diagrama de uso de tres pasos |
El cifrado de carpeta y el de USB usan el mismo motor. El selector de carpetas lo abre el navegador en el equipo del visitante (File System Access API), así que el modo carpeta funciona igual en local y en producción; el panel de dispositivos detectados solo es útil en instalaciones locales.
cryptum/
├── config/config.php → constantes globales (versión, límites, rutas)
├── public/
│ ├── index.php → front controller: cabeceras de seguridad + rutas
│ └── assets/ → css/app.css · js/app.js (toda la criptografía)
├── app/
│ ├── core/Controller.php → clase base: render de vistas y respuestas JSON
│ ├── controllers/ → HomeController · VaultController (API)
│ ├── models/Vault.php → almacenamiento temporal de blobs cifrados
│ └── views/ → layouts (header/footer) + home
├── storage/vault/ → blobs cifrados (.enc) y metadatos (.meta); acceso web denegado
├── public/descargas/ → cryptum-portable.zip + su huella SHA-256
└── portable/ → aplicación de escritorio (ver portable/README.md)
| Ruta | Método | Función |
|---|---|---|
/api/upload |
POST | Sube el blob cifrado como binario crudo (application/octet-stream) |
/api/download?t=<token> |
GET | Sirve y elimina el blob — descarga única con reclamo atómico |
/api/status?t=<token> |
GET | Validez y tiempo restante del vault |
/api/list-usb |
GET | Lista discos removibles (solo desde localhost por defecto) |
- Cifrado: AES-256-GCM (tag de autenticación de 128 bits, IV de 96 bits único por archivo).
- Derivación de clave: PBKDF2-SHA-512 con 210 000 iteraciones y sal de 256 bits.
- Token de descarga: 128 bits de
random_bytes(32 caracteres hex).
Todos los archivos .c3v comienzan con la firma ASCII C3VL seguida de un
byte de versión:
| Versión | Uso | Estructura |
|---|---|---|
0x03 (actual) |
Archivo individual | [C3VL][03][SALT 32][IV 12][CIFRADO+TAG] |
0x04 (actual) |
Carpeta / USB (clave maestra) | [C3VL][04][IV 12][CIFRADO+TAG] |
0x01 (legado) |
Archivo individual | [C3VL][01][SALT 32][IV 12][NOMLEN 4][NOMBRE][CIFRADO+TAG] |
0x02 (legado) |
Carpeta / USB | [C3VL][02][IV 12][NOMLEN 4][NOMBRE][CIFRADO+TAG] |
En v3/v4 el contenido cifrado es [NOMLEN 4][NOMBRE][DATOS]: el nombre del
archivo viaja cifrado. Las versiones legadas lo guardaban en claro en el
encabezado (fuga de metadatos) y se mantienen solo para descifrar archivos
antiguos; ya no se generan.
El modo carpeta/USB guarda la sal del directorio en .cryptum_meta.bin
([C3VM][SALT 32]). Este archivo se escribe antes de cifrar el primer
archivo: si el proceso se interrumpe, la sal ya está en el disco y los .c3v
creados siguen siendo recuperables con la contraseña.
- El cliente cifra el archivo en el navegador y sube el blob (binario crudo).
- El servidor lo valida (firma
C3VL, tamaño) escribiéndolo a disco por bloques y asigna un token de 128 bits. - Al primer GET del enlace, la petición reclama el archivo con un
rename()atómico — dos descargas simultáneas no pueden ganar las dos — lo sirve y lo destruye. - Todo vault que supere los 300 segundos se elimina en la siguiente limpieza (se ejecuta en cada subida y en cada consulta de estado).
| Límite | Valor | Dónde |
|---|---|---|
| Tamaño máximo de archivo | 100 MB | MAX_FILE_MB |
| Expiración del enlace | 300 s | EXPIRY_SEC |
| Vaults activos totales | 500 | MAX_VAULTS |
| Vaults activos por visitante | 20 | MAX_VAULTS_PER_IP |
Cabeceras aplicadas: CSP estricta (script-src 'self', form-action 'none',
base-uri 'none'), X-Frame-Options: DENY, Referrer-Policy: no-referrer,
HSTS cuando hay HTTPS.
Aplicación de escritorio en Python que descifra y cifra los mismos archivos
.c3v, sin conexión y sin instalación. Está en portable/,
con su propia documentación.
EN LA BASE TRASLADO EN EL DESTINO
────────── ──────── ─────────────
Aplicación web Memoria USB Cryptum Portable
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ CIFRAR │ ───────► │ orden.c3v │ ───────► │ DESCIFRAR │
│ AES-256 │ │ mapa.c3v │ │ AES-256 │
└─────────────┘ └─────────────┘ └─────────────┘
contraseña material ilegible contraseña
del soldado para cualquiera del soldado
La contraseña NUNCA viaja con la USB. Solo la sabe el soldado.
El botón App portátil de la barra superior abre ese mismo diagrama y entrega
el paquete desde public/descargas/cryptum-portable.zip, con su huella SHA-256
publicada al lado para que quien lo descargue pueda verificarlo.
Es la pregunta correcta, y la respuesta está en el principio de Kerckhoffs: la seguridad de Cryptum no está en el algoritmo, está en la contraseña del usuario. El algoritmo y el formato ya eran públicos — están en el JavaScript que cualquiera descarga al abrir la página. La aplicación portátil no lleva ninguna llave incrustada: quien la capture obtiene un descifrador que sin la contraseña es tan inútil como el archivo cifrado.
El formato binario está probado en las dos direcciones: lo que cifra el
navegador lo abre Python, y lo que cifra Python lo abre el navegador. La prueba
no usa una reimplementación del motor — carga el public/assets/js/app.js real
en Node con un DOM simulado y usa sus objetos Crypto y USBCrypto tal cual
corren en el navegador.
cd portable
python3 tests/test_compatibilidad.py # 31 pruebas del formato y el cifrado
python3 tests/test_gui.py # 34 pruebas de la ventana gráfica
python3 tests/test_windows.py # 60 pruebas de compatibilidad Linux ↔ WindowsAl modificar la criptografía de la web hay que reflejarlo en
portable/app/config.py. Si las constantes de los dos lados dejan de coincidir, las aplicaciones dejan de entenderse y el material cifrado en el servidor no se podrá abrir en destino.
La carpeta .github/workflows/ define una construcción automática que compila
la aplicación portátil en máquinas Windows y Linux reales, ejecuta las 125
pruebas y comprueba que el ejecutable resultante descifra un archivo antes de
publicarlo. Gracias a eso no hace falta una máquina Windows con Python para
obtener el cryptum.exe que se entrega al personal desplegado.
Los ejecutables terminados se publican en el
Release del repositorio, cada uno
con su huella .sha256:
| Archivo | Sistema | Para qué |
|---|---|---|
cryptum.exe |
Windows | Ventana gráfica — doble clic |
cryptum-cli.exe |
Windows | Línea de comandos |
cryptum |
Linux | Ventana y línea de comandos en un solo archivo |
Los ejecutables pesan unos 58 MB entre los tres y no se versionan en Git: meterlos en el historial lo engordaría para siempre, y cada compilación nueva sumaría otro tanto. Para que el botón App portátil los entregue desde el propio servidor —imprescindible en redes sin salida a internet— se traen con:
bash portable/build/descargar_binarios.sh # baja el Release y verifica cada huellaMientras no se ejecute ese script, el botón sigue funcionando: los enlaces
apuntan al Release de GitHub y se marcan con la etiqueta GitHub para que quede
claro que esa descarga sí sale a internet. La lógica vive en
app/models/Descargas.php, que decide origen y tamaño de cada archivo.
Después de cualquier cambio en portable/:
bash portable/build/empaquetar_web.sh # actualiza el ZIP y su huella- PHP 8.0 o superior.
- Apache con
mod_rewritehabilitado (los.htaccessredirigen todo apublic/). - Navegador con Web Crypto API. Para los modos de carpeta y USB se necesita además la File System Access API (Chrome, Edge u Opera de escritorio); el cifrado de archivo individual y los enlaces seguros funcionan en cualquier navegador moderno.
git clone <url-del-repositorio> cryptum
cd cryptum
# Permisos de escritura para la bóveda temporal
mkdir -p storage/vault
chmod 775 storage/vault
chown -R www-data:www-data storageApunta el DocumentRoot del VirtualHost a la carpeta cryptum/ (el
.htaccess de la raíz reenvía a public/) y asegúrate de que
AllowOverride All esté activo para ese directorio.
Verifica la instalación abriendo http://localhost/cryptum/ — o el dominio que
hayas configurado.
APP_BASE_URLen el entorno para servir desde otra ruta. Vacío ("") = raíz del dominio; sin definir =/cryptum.CRYPTUM_USB_REMOTE=1en el entorno habilita/api/list-usbdesde clientes remotos (por defecto solo localhost).- Al publicar cambios de CSS/JS, subir
APP_VERSIONenconfig/config.phppara invalidar la caché de los navegadores.
Ejemplo de VirtualHost para producción en la raíz del dominio:
<VirtualHost *:443>
ServerName cryptum.ciberdefensa.com.mx
DocumentRoot /var/www/html/cryptum
SetEnv APP_BASE_URL ""
<Directory /var/www/html/cryptum>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>- Borrado con sobreescritura = mejor esfuerzo. En el servidor los archivos se sobrescriben con ceros en sitio antes de borrarse, pero en SSD y sistemas con journaling el disco puede conservar copias internas. En el navegador, la File System Access API escribe en un archivo temporal, por lo que la sobreescritura del original no está garantizada a nivel físico. No debe presentarse como borrado forense certificado.
- Contraseña perdida = archivo irrecuperable. No existe mecanismo de recuperación por diseño.
- PBKDF2 vs Argon2id: se usa PBKDF2 (210k iteraciones) por estar disponible de forma nativa en Web Crypto sin dependencias externas. Migrar a Argon2id (resistente a GPU) requeriría incorporar una librería WASM auditada y una versión 5 del formato; queda como trabajo futuro documentado.
Cryptum es una herramienta de cifrado; su seguridad depende de la fortaleza de la contraseña que elija el usuario y del equipo donde se ejecuta. El proyecto se entrega tal cual, sin auditoría externa formal. Si detectas una vulnerabilidad, repórtala de forma privada al autor antes de divulgarla.
Cryptum — desarrollado por C3r0d4y. Aplicación web y aplicación portátil, un solo formato de cifrado.