Expand description
The v1 blob container: an authenticated header followed by length-prefixed AEAD chunks (ADR 0003).
magic 8 b"GWKBLOB\0"
format_version 2 u16 big-endian
digest 32 raw SHA-256 of the plaintext
byte_size 8 u64 big-endian, plaintext length
stream_nonce 19 XChaCha20-Poly1305 nonce minus the BE32 stream suffix
media_type_len 2 u16 big-endian
kek_id_len 2 u16 big-endian
media_type n UTF-8
kek_id n UTF-8
------------------- everything above is the AAD -------------------
[chunk_len u32 be][ciphertext] ... 1 MiB plaintext per chunkThe wrapped DEK is NOT in this file. It travels beside the container, in the row that describes the blob, and that placement is what makes the two operations ADR 0003 requires cheap and atomic: rewrap replaces one column, and crypto-shred deletes one column. Both would otherwise have to rewrite a multi-gigabyte file — non-atomically — to change 72 bytes near its front. The consequence is stated plainly because it is load-bearing for backups: a container without its row is unreadable ciphertext, by design.
Everything in the header is bound as associated data — into the DEK wrap AND into every chunk — so flipping a byte of the declared size, media type, or KEK label fails authentication rather than producing a differently-described blob. The final chunk is sealed with the stream’s explicit last-block flag, which is what makes truncation detectable: a reader that hits EOF early tries to open a middle chunk as the last one, and the tag does not verify.
Structs§
- Header
- The authenticated header, decoded.
- Sealed
- A sealed blob: the container bytes, plus the key material that belongs in the database rather than the file.
Constants§
- CHUNK_
LEN_ BYTES - Width of a chunk’s length prefix.
- DEK_
BYTES - Bytes of key material per blob (ADR 0003).
- FORMAT_
VERSION - The only container version v1 writes or reads. A future format is a new number here, never a parser that tolerates both.
- FRAMED_
CHUNK_ BYTES - Bytes one FULL chunk occupies on disk. Every chunk but the last is exactly this wide, which is what lets a ranged read compute where chunk N starts instead of walking the length prefixes to find out.
- MAGIC
- Identifies a GridWork blob on sight, including in a hex dump of a stray file that outlived its database.
- MAX_
CIPHERTEXT_ CHUNK_ BYTES - The largest a single chunk’s ciphertext can legally be.
- STREAM_
NONCE_ BYTES StreamBE32spends 5 of the 24 nonce bytes on its counter and last-block flag, so the caller supplies the other 19.- TAG_
BYTES - Poly1305 tag width, appended to every sealed thing.
- WRAPPED_
DEK_ BYTES - A wrapped DEK is the key plus the Poly1305 tag.
- WRAP_
NONCE_ BYTES - XChaCha20-Poly1305 nonce width, used whole for the DEK wrap.
Functions§
- chunk_
count - How many chunks a blob of
byte_sizeplaintext bytes was sealed into. - chunk_
offset - Where chunk
indexbegins, counted from the start of the container. - header_
len - How many bytes a header holding these two strings occupies.
- open
- Open a container, given the key material stored beside it.
- open_
chunk - Decrypt ONE chunk, without touching the ones before it.
- rewrap
- Rewrap this blob’s DEK under a new KEK without touching its ciphertext.
- seal
- Seal
plaintext, minting a fresh DEK and nonces from the system CSPRNG. - seal_
with - Seal
plaintextwith caller-supplied key material.