You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
10 KiB
124 lines
10 KiB
# DateKeys, formato de cápsula 3: propuesta para revisión de seguridad
|
|
|
|
*30 de septiembre de 2026. Propuesta de ampliación del protocolo DateKeys v0.9, todavía sin implementar.*
|
|
|
|
## Para quien revisa
|
|
|
|
**Qué es.** Una ampliación del protocolo DateKeys: el formato de cápsula 3. Hasta la v0.9, una cápsula guarda un solo fichero, sin nombre ni fecha. El formato 3 guarda varios ficheros y carpetas, con sus nombres, tamaños, hashes y fechas de modificación. Añade además una firma de autor opcional y un sello de tiempo opcional, emitido por un servicio de DateKeys.
|
|
|
|
**Estado.** Es un diseño. El spec v0.9 existe, y sus dos implementaciones, la de referencia en Go y la de TypeScript para el navegador, están hechas y probadas byte a byte entre sí. Nada del formato 3 está programado todavía.
|
|
|
|
**Qué se pide.** Encontrar vulnerabilidades en el diseño, en particular:
|
|
- **Criptografía:** los enunciados que se firman y se sellan, los compromisos, el perfil Ed25519 estricto y los trasplantes entre cápsulas o formatos.
|
|
- **Privacidad:** qué se filtra antes de la fecha de apertura, qué ve el servicio de sellado y qué queda vinculado después.
|
|
- **El lector ante una cápsula maliciosa:** el análisis del CBOR, las reglas de rutas, la extracción a un ZIP o a una carpeta, y el consumo de memoria y de CPU.
|
|
- **El servicio de sellado:** la retrodatación, el robo de la clave y el registro auditable.
|
|
- **Ambigüedades** que dos implementaciones independientes podrían resolver de forma distinta.
|
|
|
|
**Cómo informar.** Para cada hallazgo:
|
|
- la gravedad: bloqueante, mayor o menor;
|
|
- un escenario concreto: qué entrada produce qué resultado;
|
|
- la sección afectada;
|
|
- una propuesta de arreglo.
|
|
|
|
**Ya revisado.** Una revisión adversarial interna encontró 28 problemas, todos corregidos; la lista va al final del documento. No hace falta repetirlos, pero sí comprobar que los arreglos son correctos.
|
|
|
|
Las referencias a ficheros y líneas (`framing.go:56`, `tempfile.ts:198`…) apuntan al código actual de las implementaciones. No hace falta abrirlas: el documento se entiende sin ellas.
|
|
|
|
## El protocolo base (v0.9) en una página
|
|
|
|
**Objetivo.** Cifrar hoy un fichero que nadie pueda abrir antes de una fecha, sin confiar en ningún servidor. La clave depende de una firma BLS que la red drand publica en esa fecha. drand Quicknet publica una ronda cada 3 segundos, y el cifrado usa tlock, un IBE sobre BLS12-381. Nadie tiene esa firma antes de la ronda, tampoco quien cifra.
|
|
|
|
**Estructura de una cápsula (`.dkc`)**, en este orden:
|
|
1. **PRELUDE**, 16 bytes en claro: la marca `DKC1`, `VERSION` (el formato de la cápsula), `PUBLIC_HEADER_LEN` y `SEALED_CONTROL_LEN`.
|
|
2. **PUBLIC_HEADER**, CBOR en claro: `capsule_id` (16 bytes aleatorios), la DateKey (el perfil del proveedor y la ronda), la política de acceso y extensiones públicas.
|
|
3. **SEALED_CONTROL = OUTER_TIME_AGE**, un fichero `age` con un único stanza `tlock` para la ronda. Dentro va una de dos cosas:
|
|
- con la política `time_only`, directamente `CONTROL_CBOR`;
|
|
- con `time_and_key`, `INNER_ACCESS_AGE`: un fichero `age` con exactamente 16 stanzas X25519, que contiene `CONTROL_CBOR`. Esos 16 stanzas son las credenciales (destinatarios `age1…` y, opcionalmente, una clave portable `.dkk`) más señuelos, en orden aleatorio.
|
|
4. **PAYLOAD_AGE**, un fichero `age` con un stanza X25519 para `R_PAYLOAD`. Su texto en claro es el contenido, L bytes, seguido de ceros hasta P = regla(L). Las reglas son `bloque256` y `reforzado`, que es max(bloque256, Padmé).
|
|
|
|
**`CONTROL_CBOR`** contiene:
|
|
- `header_binding`, el SHA-256 de PRELUDE ‖ PUBLIC_HEADER;
|
|
- `payload_identity`, que es `I_PAYLOAD`, la identidad X25519 cuya pública es `R_PAYLOAD`;
|
|
- las extensiones de control;
|
|
- `payload_length` (L);
|
|
- el código de la regla de relleno.
|
|
|
|
**Apertura** (§63, pasos 1 a 18):
|
|
- **Pasos 1 a 8:** estructura, sin red y sin secretos.
|
|
- **Paso 9:** la firma de la ronda (el release), que se da a mano o se descarga, y en `time_and_key`, la credencial.
|
|
- **Paso 10:** la firma BLS se verifica contra la clave pública del perfil, que va fijada en el software.
|
|
- **Paso 11:** se abre `OUTER_TIME_AGE`.
|
|
- **Paso 12:** estructura de la política.
|
|
- **Paso 13:** la credencial abre exactamente uno de los 16 stanzas de `INNER_ACCESS_AGE`.
|
|
- **Paso 14:** se decodifica `CONTROL_CBOR`.
|
|
- **Paso 15:** se comprueba `header_binding`.
|
|
- **Paso 16:** `I_PAYLOAD` y P.
|
|
- **Paso 17:** se abre `PAYLOAD_AGE` y se comprueba el relleno.
|
|
- **Paso 18:** se entrega.
|
|
|
|
Nada se presenta antes de autenticar el contenido entero (§56), y solo se entregan L bytes, nunca el relleno.
|
|
|
|
**Qué se ve antes de la fecha** (formato 2): la DateKey (la fecha), la política, `capsule_id` y el tamaño relleno. No se ve la longitud exacta ni el número de credenciales.
|
|
|
|
**La `.dkk`**, la clave portable, contiene:
|
|
- la identidad X25519 de acceso;
|
|
- `capsule_id`;
|
|
- el SHA-256 del `.dkc` exacto (`capsule_digest`).
|
|
|
|
No lleva MAC ni firma.
|
|
|
|
**Lo que v0.9 no garantiza** (§5, §36.1, §55.1):
|
|
- autoría: cualquiera puede cifrar hacia una fecha futura con la clave pública del perfil;
|
|
- fecha probatoria de creación;
|
|
- integridad frente a quien ya abrió la cápsula: puede cifrar otro `PAYLOAD_AGE` para `R_PAYLOAD` y volver a sellar el control;
|
|
- resistencia poscuántica.
|
|
|
|
**Implementaciones.** La de Go es la de referencia, con la CLI `datekeys`. La de TypeScript funciona en el navegador sin red: la página `/create` cifra y `/inspect` abre. Las dos son iguales byte a byte, con fixtures, vectores y mutaciones compartidas. Evitan dependencias nuevas: tienen su propio códec CBOR determinista. En criptografía usan noble (curves, hashes, ciphers) y `age-encryption` en TypeScript, y la biblioteca estándar, `filippo.io/age` y drand/tlock en Go.
|
|
|
|
## Decisiones del autor para el formato 3
|
|
|
|
Estas decisiones son el punto de partida del diseño, no algo a revisar. Un hallazgo puede, eso sí, mostrar que alguna es insegura.
|
|
|
|
1. **Formato 3.** El texto en claro de `PAYLOAD_AGE`, cifrado y bajo el relleno, pasa a ser tres bloques seguidos: `security | head | content`. Nada va en PUBLIC_HEADER, en `CONTROL_CBOR` ni en el nombre del fichero. Los formatos 1 y 2 siguen abriéndose, y un lector v0.9 rechaza el formato 3 en el paso 2.
|
|
2. **`head`** lleva:
|
|
- su propia versión;
|
|
- una sal aleatoria;
|
|
- un comentario opcional por cápsula;
|
|
- un autor declarado opcional, que es texto y nunca prueba nada;
|
|
- una entrada por fichero, con la ruta relativa (con carpetas), `size`, `start`, `end`, el SHA-256 y la fecha de modificación. `start`, `end` y `size` deben cuadrar entre sí.
|
|
|
|
No lleva tipo de contenido, hash global, permisos ni fecha de creación.
|
|
3. **La fecha de modificación** se toma sola al cargar cada fichero. Se incluye por defecto, con una casilla para quitarla, y es informativa.
|
|
4. **`security`** lleva una firma de autor Ed25519 y un sello de tiempo, los dos opcionales, sobre `head` y el contexto de la cápsula. Si van los dos, primero se firma y el sello cubre también la firma. Ninguno de los dos hace falta para abrir.
|
|
5. **El servicio de sellado** es de DateKeys, en el mismo origen que la página. Firma con una clave Ed25519 fijada en el protocolo. Lleva un registro de solo añadir, anclado periódicamente en OpenTimestamps. Sellar es opcional y pide consentimiento.
|
|
6. **Varios ficheros:** la página entrega un ZIP sin compresión que construye con código propio, y la CLI escribe el árbol en un directorio nuevo, nunca fuera de él.
|
|
|
|
## Modelo de amenazas
|
|
|
|
| Adversario | Qué tiene | Qué no debe conseguir |
|
|
|---|---|---|
|
|
| A1, observador antes de la fecha | El `.dkc`; quizá, el tráfico hacia el servicio de sellado | Nombres, número de ficheros, tamaños, hashes, fechas, si hay firma o sello, autor o comentario |
|
|
| A2, quien abre | Todo el contenido, después de la fecha | Hacer pasar una cápsula manipulada por la original, con firma o sello que lo respalden |
|
|
| A3, escritor malicioso | La libertad de fabricar cualquier cápsula | Que el lector escriba fuera de su carpeta o sobrescriba ficheros, agotarlo, o engañar con veredictos falsos, nombres que se confunden o un ZIP malicioso |
|
|
| A4, servicio de sellado deshonesto o comprometido | Su clave y su registro | Retrodatar sin que se note, o vincular las peticiones con quien crea la cápsula antes de la fecha |
|
|
| A5, red | El camino entre la página y el servicio | Alterar o suplantar el sello sin que se detecte |
|
|
| A6, tercero que verifica | El paquete de verificación, sin `I_PAYLOAD` | Obtener `I_PAYLOAD`, o un contenido que no está en el paquete |
|
|
|
|
## Preguntas concretas
|
|
|
|
1. ¿Atan `control_commit` y `head_digest` la firma y el sello a esta cápsula y solo a ella? ¿Se pueden trasplantar entre cápsulas, entre formatos o a un paquete de verificación?
|
|
2. ¿Es correcto el perfil «Ed25519 estricto» (§4 del diseño)? ¿Da el mismo resultado en Go 1.26 y en noble 2.4?
|
|
3. ¿Filtran algo antes de la fecha la trama `SECURITY_LEN ‖ HEAD_LEN`, el área de 512 bytes o la cota de ficheros que se deduce de P?
|
|
4. ¿Cierran R1 a R9 el escape de carpeta, las colisiones de nombres y los trucos de Windows (best-fit, alias 8.3, nombres reservados) al extraer a un ZIP y a una carpeta, en Windows, macOS y Linux?
|
|
5. ¿Garantizan la precedencia del paso 17 y la entrega atómica que nada se presenta antes de autenticarlo todo, y que Go y TypeScript dan el mismo código de error?
|
|
6. ¿Puede un escritor malicioso agotar memoria o CPU? Por ejemplo, con un head de 16 MiB, 65 535 ficheros, rutas largas o el plegado Unicode.
|
|
7. ¿Resiste el servicio de sellado la retrodatación como afirma el diseño, con ventanas de clave de un año, registro Merkle, anclaje horario en OpenTimestamps y `max_anchor_delay` de 26 h? ¿Qué pasa si roban la clave?
|
|
8. ¿Qué aprende el servicio, qué vincula después de la apertura, y basta con no guardar registros de acceso?
|
|
9. ¿Pueden inducir a error los textos de los veredictos? ¿Pueden suplantarlos el comentario o el autor declarado?
|
|
10. ¿Son seguras las claves de autor, con su formato `dkauthor1…`, el scrypt de logN 16 y la confianza en el primer uso condicionada al sello?
|
|
11. ¿Hay alguna ambigüedad de codificación que dos implementaciones resolverían de forma distinta?
|
|
|
|
---
|
|
|