CipherFS
En desarrollo · sin publicar · el formato puede cambiar

Sincronización de archivos cifrada en el cliente, sin servidor de confianza

Los archivos se cifran antes de salir de tu dispositivo. Los dispositivos se sincronizan directamente entre sí, o a través de cualquier cosa que pueda guardar bytes: un bucket de S3, una carpeta local, un directorio que iCloud o Dropbox transporten. Ninguno ve nombres ni contenidos, y ninguno necesita bloqueos ni actualizaciones atómicas.

Escrito en Rust. CLI, montaje FUSE, interfaz web y enlaces para C, Python y Go.

Lo que ve el almacén

i/d7a1…/000412-9f3c…-18204
i/2b90…/000098-71e0…-6112
p/3f/3f8a…-6291456
p/c2/c2d4…-5833728
n/0007-e41b…-2097152
r/d7a1…-epoch3

Lo que ve un dispositivo

docs/
  contract-2026.pdf        2 versiones
  notes.md                 2 heads en conflicto
photos/
  2026-09/IMG_4471.heic    se obtiene al leer
projects/cipherfs/
  README.md
papelera: old-drafts/ (14 archivos)

A la izquierda, nombres de objeto formados por un id de dispositivo, un número de secuencia, una longitud y un hash del texto cifrado. A la derecha, el árbol de archivos que muestra un dispositivo tras descifrar, con el número de versiones, los conflictos y la papelera. Entre ambos no hay ningún servidor.

Diseño

Lo que promete

Cifrado en el cliente

El contenido, los nombres de archivo y los metadatos sensibles se cifran antes de salir del dispositivo. La lectura verifica la integridad; una contraseña incorrecta, una manipulación o un daño fallan de forma explícita. Las claves y el texto en claro nunca llegan a registros ni almacenes.

Sincronización fiable

Los cambios hechos sin conexión se sincronizan al recuperarla. Las transferencias interrumpidas se reintentan, y una transferencia repetida nunca vuelve a aplicar ni resucita una versión antigua. Las ediciones concurrentes eligen la versión actual con una sola regla; las demás se conservan.

Archivos pequeños y grandes por igual

Los archivos pequeños siguen siendo baratos. Los grandes se trocean, se transmiten en flujo y se obtienen por rango de bytes. El usuario nunca elige un modo, y cruzar un umbral de tamaño nunca cambia la semántica.

Núcleo y adaptadores

El cifrado, el modelo de archivos, las transacciones de almacenamiento y las reglas de sincronización viven en el núcleo. CLI, montaje, interfaz web y enlaces de lenguaje solo adaptan el acceso. No mantienen su propia base de datos ni inventan reglas.

Índice completo, contenido opcional

Cada dispositivo guarda el índice compartido completo. El contenido se sincroniza a todos los dispositivos por defecto; un teléfono o un portátil con poco espacio puede ser un dispositivo parcial que solo conserva las carpetas fijadas y lo leído recientemente.

Sin servidor de confianza

Los dispositivos se conectan entre pares. Los almacenes solo guardan objetos cifrados. El historial, la papelera y los conflictos son vistas de una misma cadena de versiones compartida, visible en todos los dispositivos. Cada dispositivo tiene identidad propia y puede revocarse.

Modelo

Historial, papelera y conflictos son la misma cadena

Cada archivo tiene una identidad estable; su ruta es solo un atributo. Cada dispositivo añade entradas a su propio registro firmado, y los demás verifican la pertenencia, la cadena de hashes y las dependencias causales antes de fusionar. Un borrado es una versión tombstone, un movimiento es una versión con otra ruta, y un conflicto son dos o más heads sin orden causal entre sí.

v1 notes.md dispositivo A 09-28 14:02 v2 notes.md dispositivo A 10-01 09:15 ← historial v3 notes.md dispositivo B 10-03 22:40 ← head (actual) v3' notes.md dispositivo C 10-03 22:41 ← head (conflicto) v4 padres = v3, v3' ← cualquier dispositivo que haya visto ambos heads escribe; el conflicto termina

Los directorios y los montajes muestran solo la versión actual; no se escriben copias de conflicto. Una versión sale del historial compartido únicamente por una purga explícita o por la política de retención del repositorio (365 días por defecto). Primero pasa 30 días en estado pendiente, durante los cuales cualquier dispositivo puede cancelarla.

Partes

Dispositivos, almacenes, claves

Dispositivos

Clientes que poseen las claves del repositorio y leen texto en claro. Cada uno tiene un par de claves de larga duración, un nombre legible y un rol completo o parcial. Un dispositivo nuevo se empareja con un código corto o un código QR; sin ningún dispositivo existente presente, se une con la clave de recuperación.

Almacenes

Solo necesitan cuatro operaciones: escribir un objeto inmutable, leer por nombre, listar por prefijo, borrar. Los objetos se direccionan por contenido y solo se añaden, empaquetados de 4 a 8 MiB. Un objeto que no ha llegado por completo está «todavía no aquí», nunca «dañado».

Claves

Las claves de contenido derivan de una época de claves. Revocar un dispositivo abre una nueva época cuya clave se envuelve solo para los dispositivos restantes. La contraseña protege únicamente la máquina local; si se olvida, se restablece con la clave de recuperación y el dispositivo conserva su identidad.

Escenario

Sacar los archivos fríos de un Mac

Una máquina siempre encendida es el dispositivo completo. El Mac es un dispositivo parcial con un montaje. Conserva solo las carpetas fijadas y el contenido leído recientemente; todo lo demás sigue apareciendo en el Finder y se obtiene del dispositivo completo o de un almacén al abrirlo. Superado el presupuesto de caché, el contenido confirmado en otro lugar se libera automáticamente. Las escrituras locales sin sincronizar y los archivos abiertos nunca se liberan.

Verificado en macOS 27 con FUSE-T: el montaje lleva .metadata_never_index, está excluido de Time Machine, recorrer todas las carpetas en el Finder dejó la caché sin cambios, y leer un archivo no disponible sin conexión falla de inmediato en lugar de quedarse colgado.

Estado

¿Está listo para publicarse?

No como versión estable. Los requisitos confirmados están implementados y cada uno tiene evidencia de aceptación, pero el formato en disco y la API todavía pueden cambiar, no ha habido auditoría de seguridad externa y nunca se ha hecho una promesa de compatibilidad. Hoy sirve para el autor y unas pocas personas que acepten que el formato cambie.

Resultados de verificación a 12 de octubre de 2026. Los recuentos son ejecuciones reales por combinación de features.

ComprobaciónResultado
Pruebas Rust en el host, features por defecto672 pasan / 0 fallanpasa
Pruebas Rust en el host, todas las features700 pasan / 0 fallanpasa
Ejecución en contenedor, Rust754 pasan / 0 fallan / 2 ignoradaspasa
Runtime C / Python / Go race15 / 10 / paquete completopasa
Compilación del frontend, prueba de humo web24 comprobacionespasa
Montaje parcial FUSE-T real, navegación en Findercaché 54.288 → 54.288 Bpasa
Matriz de aceptación de requisitosR01–R62 asociados a pruebashecho

Pendiente

Primeros pasos

Línea de comandos

La contraseña se toma de CIPHERFS_PASSWORD o de una petición interactiva. Las credenciales de S3 se leen de variables de entorno y nunca se escriben en el índice compartido.

cipherfs init --path ~/vault
cipherfs put --vault ~/vault --source ./notes.txt --target docs/notes.txt
cipherfs store add directory --vault ~/vault --dir ~/Library/CloudStorage/Dropbox/cfs
cipherfs sync directory --vault ~/vault --store-dir ~/Library/CloudStorage/Dropbox/cfs

cipherfs role set partial --vault ~/vault --read-cache-bytes 2147483648
cipherfs pin add --vault ~/vault --path docs
cipherfs mount --vault ~/vault --mount-point ~/CipherFS --background

cipherfs devices list --vault ~/vault
cipherfs safe-to-remove --vault ~/vault
cipherfs history --vault ~/vault --path docs/notes.txt
cipherfs export --vault ~/vault --target ~/plain-copy --history

Las aplicaciones Rust usan SyncedVault: put, put_from_reader, get, get_to_writer, get_range, delete, list. Una escritura correcta significa que los datos son duraderos localmente; una tarea en segundo plano se encarga de la sincronización, la reconexión y los reintentos. El uso de memoria no depende del tamaño del objeto.

Valores por defecto

Algoritmos

PropósitoAlgoritmo
AEAD de contenidoXChaCha20-Poly1305 (opcional AES-256-GCM, ChaCha20-Poly1305)
TroceadoFastCDC, mín/med/máx 1 / 4 / 8 MiB, unidad máxima 16 MiB
Direccionamiento por contenidoBLAKE3
Identidad del dispositivofirmas ed25519, envoltura X25519, también es el id de nodo P2P
Contraseña localArgon2id envuelve el material de claves local; nunca se sincroniza
TransporteQUIC (Iroh); HTTPS hacia los almacenes cuando hace falta