KemalIdentity::MFA::SecretBox
Reversible encryption for the one secret in this shard that cannot be hashed.
Why this exists at all
Every other secret here is stored as a SHA-256 digest, because the server only ever has to recognise it. A TOTP secret is different in kind: the server has to recompute the code from it on every verification, so it must be able to read the secret back. Hashing is not an option, and pretending otherwise would mean shipping something that does not work.
What is left is the next-best property: a stolen database is not enough. Sealed secrets are useless without a key that lives in the application's configuration rather than in the table beside them, so a dump, a backup or a read-only SQL injection yields ciphertext. An attacker who has both has the second factor, and there is no arrangement of software that changes that.
Contrast recovery codes, which are ordinary bearer secrets and are stored as digests like everything else.
The contract
#seal must be non-deterministic: sealing the same secret twice produces different blobs,
so that equal ciphertexts do not reveal equal secrets. #open? returns nil rather than
raising for a blob that does not authenticate — a truncated column, a row from a different
key, a value someone edited — because that is a data problem the caller has to handle, not
an exception on the verification path.
Instance methods
The secret inside sealed, or nil if it does not authenticate under this key.