As the author asks: the rest of the envelope can be stored inside a host
file, an image, a video or any file, and each address of the locator says
at which byte it starts (44.1).
- The envelope is split: its age header, up to the MAC, goes in the
time-locked locator, and only the rest, nonce and STREAM, is stored
outside. Those bytes carry no mark: nobody can tell they are an age
file, let alone a capsule. The reader joins both and decrypts with
I_SOBRE.
- An address is a map with the URI and an optional offset; the reader
asks only for those bytes, with an HTTP range when it can, and checks
their SHA-256.
- Concealment, not steganography: an analysis of the host can see extra
bytes, not what they are. Only storage that keeps the file byte for
byte works; social networks and messaging applications spoil a host.
- The CDDL of the locator follows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ -2002,7 +2002,7 @@ Una identity X25519 solo podrá abrir el `INNER_ACCESS_AGE` para el que fue util
Si no existe metadata de verificación, la clave `verification_metadata` MUST omitirse. Un mapa vacío no es una representación canónica válida de ausencia en V1.
Si no existe metadata de verificación, la clave `verification_metadata` MUST omitirse. Un mapa vacío no es una representación canónica válida de ausencia en V1.
Con un localizador (§44.1), `capsule_digest` en claro no delata dónde está la cápsula: lo que se guarda fuera es un sobre cifrado, con otro hash.
Con un localizador (§44.1), `capsule_digest` en claro no delata dónde está la cápsula: lo que se guarda fuera es el resto de un sobre cifrado, con otro hash.
---
---
@ -2037,26 +2037,37 @@ La extensión `datekeys.capsule`, versión 1, registrada para el array no críti
- El localizador es un fichero `age` con un único stanza tlock para la ronda y la cadena de esa DateKey (§28.1, §35). Su plaintext es otro mapa CBOR con el perfil de §58:
- El localizador es un fichero `age` con un único stanza tlock para la ronda y la cadena de esa DateKey (§28.1, §35). Su plaintext es otro mapa CBOR con el perfil de §58:
```text
```text
0 → direcciones (array de 1 a 8 textos, de 1 a 1024 bytes cada uno)
0 → direcciones (array de 1 a 8 mapas de dirección)
1 → I_SOBRE (32 bytes: la identity X25519 cruda del sobre)
1 → I_SOBRE (32 bytes: la identity X25519 cruda del sobre)
2 → sobre_digest (32 bytes: el SHA-256 del sobre)
2 → cabecera del sobre (cadena de bytes de 1 a 1024)
3 → sobre_size (entero: la longitud del sobre en bytes)
3 → resto_digest (32 bytes: el SHA-256 del resto del sobre)
4 → capsule_digest (32 bytes, §43)
4 → resto_size (entero: la longitud del resto en bytes)
5 → relleno (cadena de bytes a cero, opcional)
5 → capsule_digest (32 bytes, §43)
6 → relleno (cadena de bytes a cero, opcional)
dirección:
0 → URI (texto de 1 a 1024 bytes)
1 → desplazamiento (entero, opcional: 0 si falta)
```
```
El plaintext mide exactamente 4096 bytes, o el menor múltiplo de 4096 en el que quepa: la clave 5 completa lo que falte, así que su longitud no delata cuántas direcciones hay ni de qué tipo.
El plaintext mide exactamente 4096 bytes, o el menor múltiplo de 4096 en el que quepa: la clave 6 completa lo que falte, así que su longitud no delata cuántas direcciones hay ni de qué tipo.
**El sobre.** Lo que se guarda fuera no es el `.dkc`, sino un sobre: un fichero `age` con un único stanza X25519 para la pública de `I_SOBRE`, una identity nueva de un CSPRNG, cuyo plaintext son los bytes exactos del `.dkc`. Quien encuentra el sobre ve un fichero `age` y su tamaño, nada de la cápsula: ni `capsule_id`, ni la fecha, ni la nota. Nadie, tampoco quien tiene la llave, lee el localizador ni el sobre antes de la fecha. En la fecha, el mismo release que abre la cápsula descifra el localizador.
**El sobre.** Quien crea la cápsula cifra el `.dkc` con `age` para la pública de `I_SOBRE`, una identity nueva de un CSPRNG, y parte ese fichero `age` en dos: la cabecera, hasta el salto de línea de su MAC incluido, que va en el localizador; y el resto, el nonce y los chunks de STREAM, que es lo único que se guarda fuera. El resto no lleva ninguna marca: sus bytes no se distinguen del azar, así que quien lo encuentra no sabe que es un fichero `age` ni una cápsula. Nadie, tampoco quien tiene la llave, lee el localizador antes de la fecha. En la fecha, el mismo release que abre la cápsula lo descifra, y el lector une la cabecera y el resto y descifra el `.dkc` con `I_SOBRE`.
**Direcciones.** Cada una es un URI ASCII de RFC 3986, con el esquema `https` o `ipfs` (un CID v1), sin userinfo. Un lector:
**Dentro de otro fichero.** El resto puede guardarse solo o dentro de otro fichero, el huésped: una imagen, un vídeo, un documento o un fichero de cualquier tipo, normalmente añadido al final, donde casi todos los programas lo ignoran. Su dirección dice entonces en qué byte del huésped empieza; su longitud es `resto_size`.
- Es ocultación, no esteganografía: quien analice el huésped puede ver que lleva bytes de más, pero no qué son ni de qué cápsula.
- Solo sirve un almacenamiento que conserva el fichero byte a byte, como un disco en la nube, IPFS o un servidor propio. Una red social o una aplicación de mensajería recomprimen las imágenes y los vídeos, o quitan lo que sobra, y el resto se pierde.
**Direcciones.** Cada URI es ASCII, de RFC 3986, con el esquema `https` o `ipfs` (un CID v1), sin userinfo. Un lector:
- MUST NOT descargar sin que la persona lo pida, y MUST mostrar antes el host o el CID: la descarga revela a quien controla la dirección cuándo y desde dónde se usa la llave, y en IPFS la ven la pasarela y los pares;
- MUST NOT descargar sin que la persona lo pida, y MUST mostrar antes el host o el CID: la descarga revela a quien controla la dirección cuándo y desde dónde se usa la llave, y en IPFS la ven la pasarela y los pares;
- MUST NOT seguir una redirección a otro esquema ni a una dirección de loopback, privada o de enlace local, y MUST cortar la descarga al pasar de `sobre_size` bytes;
- MUST pedir solo los bytes del resto, con un rango de HTTP si el servidor lo admite; si no, MUST dejar de leer al llegar al desplazamiento más `resto_size`;
- MUST comprobar que el SHA-256 del sobre es `sobre_digest`, descifrarlo con `I_SOBRE` y comprobar que el SHA-256 del `.dkc` es `capsule_digest` antes de usarlo, y SHOULD guardar una copia;
- MUST NOT seguir una redirección a otro esquema ni a una dirección de loopback, privada o de enlace local;
- MUST comprobar que el SHA-256 del resto es `resto_digest`, descifrar el sobre con `I_SOBRE` y comprobar que el SHA-256 del `.dkc` es `capsule_digest` antes de usarlo, y SHOULD guardar una copia;
- MUST tratar como inutilizable un localizador cuya ronda o cuya cadena no son las de `compact_datekey`.
- MUST tratar como inutilizable un localizador cuya ronda o cuya cadena no son las de `compact_datekey`.
`sobre_digest` y `capsule_digest` protegen frente a quien guarda el sobre, no frente a quien escribió la `.dkk`.
`resto_digest` y `capsule_digest` protegen frente a quien guarda el resto o el huésped, no frente a quien escribió la `.dkk`.
Como toda extensión de la `.dkk`, es informativa: nada la ata a la cápsula (§44). Un lector:
Como toda extensión de la `.dkk`, es informativa: nada la ata a la cápsula (§44). Un lector:
@ -2065,8 +2076,9 @@ Como toda extensión de la `.dkk`, es informativa: nada la ata a la cápsula (§
Un escritor:
Un escritor:
- MUST guardar fuera solo el sobre, nunca el `.dkc`, y conocer las direcciones antes de escribir la `.dkk`: primero crea el sobre y lo guarda, también en IPFS (§62.1, regla 24);
- MUST guardar fuera solo el resto del sobre, nunca el `.dkc` ni la cabecera del sobre, y conocer las direcciones antes de escribir la `.dkk`: primero guarda el resto, solo o en su huésped, también en IPFS (§62.1, regla 24);
- SHOULD avisar de que con un localizador la `.dkk` basta para encontrar la cápsula y abrirla en la fecha; de que quien solo tiene la llave no sabe dónde está la cápsula hasta la fecha, aunque quien guarda el sobre lo tiene; y de que una dirección que deja de existir pierde la cápsula para quien no tenga otra copia.
- con un huésped, SHOULD añadir el resto al final, y MUST comprobar antes de escribir la `.dkk` que el fichero que guarda tiene el resto en ese desplazamiento;
- SHOULD avisar de que con un localizador la `.dkk` basta para encontrar la cápsula y abrirla en la fecha; de que quien solo tiene la llave no sabe dónde está la cápsula hasta la fecha; de que una red social o una aplicación de mensajería estropean un huésped; y de que una dirección que deja de existir pierde la cápsula para quien no tenga otra copia.
---
---
@ -2375,7 +2387,7 @@ Ese supuesto no resiste a un adversario cuántico futuro (§7.7): quien conserve
### Fuera del `.dkc`
### Fuera del `.dkc`
- una `.dkk` lleva en claro la credencial, `access_material`, y además `capsule_id`, `credential_id`, el `capsule_digest` opcional, que la ata a los bytes exactos de un `.dkc`, y la `data` de sus extensiones (§41, §43, §44);
- una `.dkk` lleva en claro la credencial, `access_material`, y además `capsule_id`, `credential_id`, el `capsule_digest` opcional, que la ata a los bytes exactos de un `.dkc`, y la `data` de sus extensiones (§41, §43, §44);
- la extensión `datekeys.capsule` de una `.dkk` lleva en claro la nota y la fecha, y cifrado para la fecha el localizador. Lo que se guarda fuera es un sobre cifrado: quien lo aloja ve su tamaño y quién lo sube o lo baja, nada de la cápsula (§44.1);
- la extensión `datekeys.capsule` de una `.dkk` lleva en claro la nota y la fecha, y cifrado para la fecha el localizador. Lo que se guarda fuera es el resto de un sobre cifrado, sin cabecera, solo o dentro de otro fichero: quien lo aloja ve bytes al azar, su tamaño y quién los sube o los baja, nada de la cápsula (§44.1);
- pedir el release revela a la Release API y a los relays el perfil, la ronda y la dirección de quien pregunta, pero no `capsule_id` (§45, §48);
- pedir el release revela a la Release API y a los relays el perfil, la ronda y la dirección de quien pregunta, pero no `capsule_id` (§45, §48);
- el nombre del fichero `.dkc`, sus fechas en el sistema de ficheros y el canal de entrega no pertenecen al protocolo (§6). En formato 3, los nombres y las mtimes de los ficheros que guarda la cápsula sí van dentro, cifrados en el head (§29.4).
- el nombre del fichero `.dkc`, sus fechas en el sistema de ficheros y el canal de entrega no pertenecen al protocolo (§6). En formato 3, los nombres y las mtimes de los ficheros que guarda la cápsula sí van dentro, cifrados en el head (§29.4).
@ -2741,7 +2753,7 @@ Con firma o sello, además, MUST:
Con nota pública, llave de palabras o extensión de cápsula, MUST:
Con nota pública, llave de palabras o extensión de cápsula, MUST:
23. **Nota pública.** Escribir la extensión `datekeys.note` solo si la persona la pide, con un texto que cumpla las reglas del autor declarado de §29.6, y SHOULD avisar de que es pública y de que, con la fecha, puede identificar a alguien (§24.1).
23. **Nota pública.** Escribir la extensión `datekeys.note` solo si la persona la pide, con un texto que cumpla las reglas del autor declarado de §29.6, y SHOULD avisar de que es pública y de que, con la fecha, puede identificar a alguien (§24.1).
24. **Llaves.** Cumplir las reglas del escritor de §38.1 para una llave de palabras. Para una `.dkk` con localizador, crear el sobre, guardarlo fuera y escribir después la `.dkk` con sus direcciones; nunca guardar fuera el `.dkc` (§44.1).
24. **Llaves.** Cumplir las reglas del escritor de §38.1 para una llave de palabras. Para una `.dkk` con localizador, crear el sobre, guardar fuera su resto, solo o en un huésped, y escribir después la `.dkk` con sus direcciones; nunca guardar fuera el `.dkc` ni la cabecera del sobre (§44.1).
Con firma o sello, además, MUST:
Con firma o sello, además, MUST:
@ -3159,7 +3171,7 @@ Firma, sello, nota y llave de palabras (v0.11), además:
- el mismo contenido con firma y sin ella, en el área común: la misma P;
- el mismo contenido con firma y sin ella, en el área común: la misma P;
- la nota pública cambiada en `PUBLIC_HEADER`: `ERR_HEADER_BINDING` en el paso 15; con un salto de línea o un carácter que §29.6 prohíbe: inutilizable y sin mostrarse;
- la nota pública cambiada en `PUBLIC_HEADER`: `ERR_HEADER_BINDING` en el paso 15; con un salto de línea o un carácter que §29.6 prohíbe: inutilizable y sin mostrarse;
- la llave de palabras: el vector de §38.1; textos con mayúsculas, acentos y espacios que dan las mismas palabras; y un texto con U+200B, que el escritor rechaza;
- la llave de palabras: el vector de §38.1; textos con mayúsculas, acentos y espacios que dan las mismas palabras; y un texto con U+200B, que el escritor rechaza;
- la extensión `datekeys.capsule`: un localizador para otra ronda (inutilizable); una dirección `file:` o `http:` (no se descarga); un sobre cuyo SHA-256 no es `sobre_digest` (no se usa).
- la extensión `datekeys.capsule`: un localizador para otra ronda (inutilizable); una dirección `file:` o `http:` (no se descarga); un resto cuyo SHA-256 no es `resto_digest`, porque alguien recomprimió el huésped o el desplazamiento no es el suyo (no se usa); un recurso que sigue tras el resto, del que se lee solo hasta el desplazamiento más `resto_size`.
---
---
## 65. Test vectors Quicknet
## 65. Test vectors Quicknet
@ -3632,7 +3644,8 @@ word key
public note
public note
= datekeys.note en PUBLIC_HEADER, pública y atada en el paso 15; copia
= datekeys.note en PUBLIC_HEADER, pública y atada en el paso 15; copia
informativa en datekeys.capsule de la .dkk, con la fecha y un
informativa en datekeys.capsule de la .dkk, con la fecha y un
localizador cifrado para la fecha, que apunta a un sobre opaco
localizador cifrado para la fecha, que apunta al resto de un sobre
opaco, solo o dentro de otro fichero
recovery
recovery
= puede obtener release directamente del provider
= puede obtener release directamente del provider
@ -4013,7 +4026,7 @@ La v0.11 define la firma de autor y el sello de tiempo del área `security`, que
- Caso: la página `/create` de `datekeys-ts` y la CLI de Go la implementan, y la CLI abre una cápsula hecha en la página. Su primera versión no llevaba `capsule_id` en la sal: las mismas palabras daban la misma llave en todas las cápsulas de una ronda, y un diccionario las atacaba a la vez (revisión del borrador).
- Caso: la página `/create` de `datekeys-ts` y la CLI de Go la implementan, y la CLI abre una cápsula hecha en la página. Su primera versión no llevaba `capsule_id` en la sal: las mismas palabras daban la misma llave en todas las cápsulas de una ronda, y un diccionario las atacaba a la vez (revisión del borrador).
- Pruebas previstas: el vector y la normalización (§64).
- Pruebas previstas: el vector y la normalización (§64).
7. **Nota pública y extensión de cápsula** (§24.1, §43, §44.1, §72).
7. **Nota pública y extensión de cápsula** (§24.1, §43, §44.1, §72).
- Cambio: `datekeys.note` en `PUBLIC_HEADER`, y `datekeys.capsule` en la `.dkk`, con la nota, la fecha y un localizador cifrado para la fecha que apunta a un sobre opaco.
- Cambio: `datekeys.note` en `PUBLIC_HEADER`, y `datekeys.capsule` en la `.dkk`, con la nota, la fecha y un localizador cifrado para la fecha que apunta al resto de un sobre opaco, sin cabecera, solo o dentro de otro fichero.
- Motivo: una aplicación que lista cápsulas y llaves solo puede distinguirlas hoy por `capsule_id`, y una llave suelta no dice de qué cápsula es ni dónde está.
- Motivo: una aplicación que lista cápsulas y llaves solo puede distinguirlas hoy por `capsule_id`, y una llave suelta no dice de qué cápsula es ni dónde está.
- Caso: una `.dkk` de la v0.10 lleva `capsule_id` y `capsule_digest`, nada legible para una persona. Y en IPFS un `.dkc` es público: un rastreador indexaría `capsule_id`, la nota y la fecha, y quien tiene la `.dkk` encontraría la cápsula antes de la fecha; por eso se guarda un sobre.
- Caso: una `.dkk` de la v0.10 lleva `capsule_id` y `capsule_digest`, nada legible para una persona. Y en IPFS un `.dkc` es público: un rastreador indexaría `capsule_id`, la nota y la fecha, y quien tiene la `.dkk` encontraría la cápsula antes de la fecha; por eso se guarda un sobre.
- Pruebas previstas: la nota cambiada y la nota inválida, y los casos de `datekeys.capsule` (§64).
- Pruebas previstas: la nota cambiada y la nota inválida, y los casos de `datekeys.capsule` (§64).