Skip to main content

Module container

Module container 

Source
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 chunk

The 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
StreamBE32 spends 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_size plaintext bytes was sealed into.
chunk_offset
Where chunk index begins, 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 plaintext with caller-supplied key material.