Skip to content

Normative · Annex

Security, gates and prior art

The SOP/1 threat model (section 23) applies unchanged: honest-but-curious and malicious storage, malicious fleet peers, network observers, stolen media. Blob objects add no new key-management surface — DEK, KEK, access record, rewrap, and historical-entitlement behavior are byte-for-byte the tabular rules. This section covers only what is different because the payload is media.

Media magnifies the size-fingerprint problem padding exists for:

  • Thumbnails are countable. A grid of N photos fetches N small objects; their number and rhythm reveal library size and browsing activity even when each size is padded. Padmé bounds per-object size leakage; it does not hide object count or access pattern, and this extension does not claim otherwise (SOP/1 section 1.2 excludes ORAM explicitly).
  • Range-read patterns leak playback behavior. A blind replica serving 1 MiB ranges of one object observes a scrubbing pattern consistent with video playback, and the ranges’ positions are the seek positions. Readers MAY prefetch or over-read to blunt this; the protocol does not mandate it.
  • Transported length is unauthenticated. The reference transport prefixes each object with a provider-supplied 8-byte length that sits outside the verification of any served range. An SOP-BLOB-1 reader is unaffected: it derives every chunk index and ciphertext span from plaintext_size in the signed manifest, never from the transfer layer (format, section 7), so a misdeclared length does not reach plaintext. The residual is denial of service against a reader that has already resolved the manifest.
  • Derivative linkage is catalog state. derived_from, derivative_kind and asset_id live in encrypted manifests, so untrusted storage cannot group an original with its derivatives by metadata — but it can correlate by co-access timing. Fetching a thumbnail and its original in one round-trip pattern links them observationally. Implementations SHOULD NOT name derivative kinds in any cleartext transport field.
  • Truncation and reorder. The final-flag byte and the counter nonce make truncation, chunk reordering, and chunk duplication authentication failures, independent of content addressing. Content addressing already rejects any modified byte stream; the AEAD-level protection exists so that a decryptor holding only a DEK and a byte stream — the forensic and recovery paths — fails closed too.
  • No AAD. Context binding rests on the fresh per-object DEK, content addressing, and the signed manifest/access-record chain, matching the age design. Adding contextual AAD would bind ciphertext to catalog state and break the property that rewrapping never touches object bytes.
  • Decrypt-before-verify does not occur. Transfer-layer verification is incremental (1 KiB units), AEAD verification is per chunk (1 MiB), and readers release plaintext only after the chunk tag verifies (format, section 7). A streaming player therefore consumes only doubly-verified plaintext.
  • Plaintext handling. The at-rest invariant of SOP/1 section 17 applies: decrypted media is transient computation state. Decoded frames in a display pipeline are accepted as transient; persistent decrypted caches (a thumbnail cache on disk) MUST be encrypted at rest like any derived store.
  • EXIF is data, not envelope. Capture metadata inside the original’s bytes is encrypted with the original. The queryable copy in metadata tables is protected by the tabular plane. Implementations MUST NOT emit cleartext sidecar files during ingestion or export (section 21.6’s explicit-export rule covers deliberate plaintext export).

Statements SOP/1 makes that bear repeating for media, because user expectations are strongest here:

  • A device that ever held the photo domain’s keys may hold plaintext copies forever (section 9.6). Revocation is forward-looking.
  • “Deleted everywhere” is four distinct states (section 14.8) and a product MUST NOT collapse them into one checkmark.
  • A compromised entitled device is full exposure of what it could decrypt; the plane encrypts transport and storage, not endpoints.

Promotion of this extension follows the same gate discipline as SOP/1 (the status page). Three gates. GB1 is closed; GB2 and GB3 are open:

GB1 alignment and range access
an SOP-BLOB-1 object imported into the transfer layer; a plaintext
range served via one verified range request from a non-decrypting
holder; decrypt of only the fetched chunks; tamper anywhere in a
served range and any chunk tag detected
GB2 streaming viability
seek-and-play of a large video derivative on a constrained device at
the profile's 1 MiB granularity, including cold-fetch over a lossy
link; measured decode-path overhead of chunked AES-GCM
GB3 padding and overhead accounting
Padmé padding implemented in the writer (no fail-open); measured
storage overhead across a realistic photo+video corpus, reported per
derivative kind
Gate State Verdict
GB1 alignment and range access closed verdict
GB2 streaming viability open target
GB3 padding and overhead accounting open target

GB1 is the extension’s load-bearing claim and SHOULD be prototyped with the transfer layer’s actual group size before any other implementation work; if group size or hashing behavior differs from the reference assumptions, the chunk constant in format, section 6 is re-derived, not worked around.

What closed GB1, and what it left unchanged. An SOP-BLOB-1 object was imported into the reference transfer layer under the storage identity the specification derives. A holder that has no key served a plaintext range through one verified range request, which moved the ciphertext chunk and nothing around it, and the reader decrypted only the chunks it fetched. Tamper was detected on both layers: a single flipped bit anywhere in a served range fails verified streaming, and a flipped byte in a fetched chunk fails that chunk’s tag. The prototype ran against the transfer layer’s actual group size, as this section asks. The group size matched the reference assumption. The hashing behavior did not match, but it differed in the safe direction: the transfer layer serves verified ranges in units finer than its group, and that unit divides the 1 MiB chunk exactly. So the chunk constant in format, section 6 is confirmed, not re-derived. The serving unit that measurement found is the one format, section 7 states, and it is asserted by exact equality, so a transfer layer that drifted from it would fail the build. The prototype also found that the transported object length is not covered by range authentication. GB1 holds regardless, because a reader takes the length from the signed manifest; section 7 makes that a requirement.

GB2 and GB3 are open. Each closes when its own text is satisfied, and closing GB1 does not bring either of them closer. Until all three close, this extension remains a draft.

The constructions here are deliberately unoriginal:

  • Chunked AEAD with counter nonce and final flag — the STREAM shape as deployed by the age file-encryption format (64 KiB chunks; seekable because chunk keys/nonces are index-derived). SOP-BLOB-1 changes the chunk size for transfer alignment and the suite for specification consistency, nothing structural. Chained alternatives (libsodium secretstream) were rejected because nonce chaining forbids random access — the operational lesson of Ente, which encrypts with secretstream and consequently implements video seek by client-side HLS transcoding rather than by seeking the encrypted original.
  • Verified ciphertext ranges from untrusted storage — Tahoe-LAFS has served seekable, Merkle-verified ciphertext segments from untrusted servers since 2008; Signal added per-chunk incremental MACs to attachments for streaming playback. Hashing ciphertext and verifying ranges against the content address is the established composition.
  • Derivatives as sibling encrypted objects — Ente encrypts file, thumbnail, and metadata as separate objects under one per-file key; Peergos hides thumbnails inside encrypted metadata. No surveyed system embeds previews in the media object.
  • Index references blobs — Perkeep’s permanode/claim/indexer split: immutable content-addressed blobs, mutable metadata and search kept entirely outside them, referencing by hash.
  • Independent encrypted blocks over content-addressed storage with O(1) seek — WNFS private files (256 KiB-bounded XChaCha20-Poly1305 blocks, index-derived block names) and Peergos (5 MiB independently encrypted chunks).
  • Reuse-not-adopt for the sync layer — Syncthing’s untrusted-device encryption was evaluated and set aside: it is documented as beta, password-derived, and file-sync-shaped, with no group key management to bind to MLS domains. Its offset-keyed block-hash design is a useful cross-check that the blind-replica correlation concerns above are the right ones.