Anyone with read access to the bucket otherwise reads the entire database history, including
session state and API-key rows, so encryption is on by default rather than offered.
The contract has one unusual requirement: sealing must be DETERMINISTIC for a given key and
plaintext. Strata addresses every object by the digest of its content, so if the same frame
sealed twice produced different bytes the store would lose deduplication entirely - the measured
dedup and delta gains are what make second-granularity affordable, and a random nonce would
spend all of them. CipherInterface::seal() must therefore be a pure function of the key and the
plaintext. How an implementation achieves that without reusing a nonce across different
plaintexts is the implementation's problem, and XChaCha20Poly1305Cipher documents its answer.
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.
Throws
\RuntimeException
When the cipher is unavailable, or sealing fails.
Returns
string
—
The sealed bytes, including whatever nonce and tag the implementation needs to open them.
Must raise on any failure. A cipher that returned partial or unauthenticated output would
hand Drupal plausible-looking content that nothing downstream can tell from the real thing.
Parameters
string
$sealed
The sealed bytes.
string
$associated
The same additional authenticated data used to seal.
Throws
\Drupal\strata\Crypto\AuthenticationFailure
When the value is present but the tag does not verify or the associated data does not
match. Distinguished from the rest because refetching the same bytes cannot fix it.
\RuntimeException
When the cipher is unavailable or the input is malformed.