NONCE_CONTEXT
NONCE_CONTEXT = 'strata-nonce-derivation-v1'
Personalisation for the nonce-derivation subkey.
Keeps the derived subkey from colliding with any other use of the same master key.
XChaCha20-Poly1305 through `ext-sodium`, which ships with PHP 8.3+.
Measured at 391 MB/s sealing and 392 MB/s opening on the reference host - roughly half the speed of the BLAKE2b that addresses the frame, and about a hundred times faster than the network it is written over, so it is never the bottleneck.
The nonce derivation. CipherInterface requires sealing to be deterministic, or the content-addressed store loses deduplication. A random nonce would destroy that. A fixed nonce would be worse: reusing a nonce across two different plaintexts under one key breaks XChaCha20 completely.
So the nonce is derived from the plaintext itself, through a KEYED hash:
nonce = BLAKE2b(plaintext, key = KDF(master, "strata-nonce"), 24 bytes)
Three properties follow:
This is the synthetic-IV construction, applied so that a store addressed by content can also be encrypted. Random nonces would spend the dedup and delta gains that make second-granularity affordable.
Layout: the sealed frame is nonce || ciphertext, with the Poly1305 tag inside the ciphertext
where sodium puts it. The frame's own digest is passed as associated data, so a frame relocated
to another key in the bucket fails to open instead of opening as the wrong content.
__construct(string $key) : mixed
Constructs a cipher around a key.
| string | $key | Exactly 32 bytes of key material. Use KeyProviderInterface to obtain it rather than reading it from settings directly. |
When the key is not exactly 32 bytes. A short key is refused rather than stretched, because silently padding it would give a false impression of the strength in use.
When ext-sodium is not loaded.
seal(string $plain, string $associated = '') : string
Seals a frame.
| string | $plain | The bytes to seal. An empty string seals to an empty string, so an absent payload never becomes a non-empty frame. |
| string | $associated | Additional authenticated data - bound to the ciphertext but not encrypted. Strata passes the frame's own digest, which is what makes a frame moved to a different key in the bucket fail to open rather than open as the wrong content. |
The sealed bytes, including whatever nonce and tag the implementation needs to open them.
nonceFor(string $plain) : string
Derives the deterministic nonce for a plaintext.
Keyed, so the nonce is not computable without the key and a candidate plaintext cannot be confirmed against the bucket.
| string | $plain | The plaintext being sealed. |
Exactly SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES bytes.