Skip to main content

4. The design on one page

Comment or suggest a change. Select any text to comment on it. Press Suggest edits to change the wording right on this page, then send your changes. Or comment at the end of the page with your GitHub account.

There is one key, one kind of token, and two algorithms: AES-256-GCM encrypts everything, and SHA-256 does the rest as a hash, as HMAC and as HKDF. Everything else follows from them.

Plaintext exists only on the desktop and inside an approved request

Figure 4.1. The whole design: one account key, one kind of token, a database and a blob store · Text version

Why this is current best practice: a full-strength random key from an approved generator (NIST SP 800-133 Rev. 2); one key per purpose, never one key for two jobs (NIST SP 800-57 Part 1 Rev. 5, key separation); and working keys derived with HKDF (RFC 5869), the extract-then-expand construction NIST approves in SP 800-56C Rev. 2 and the one TLS 1.3 uses for all its keys (RFC 8446).

Why this is current best practice: AES-256-GCM is the NIST-approved authenticated encryption mode (SP 800-38D, over AES in FIPS 197), so tampering is detected, not just hidden. Binding each ciphertext to its account and message id as associated data follows the AEAD design in RFC 5116, which stops a stored ciphertext being swapped into another row or account. HMAC-SHA256 is the approved keyed hash (FIPS 198-1), and keyed tags over fragments are the classic construction for search over encrypted data (Song, Wagner and Perrig, IEEE S&P 2000). Its known limit, that equal fragments produce equal tags, is question 1, and GCM’s nonce limit is question 2.

Why this is current best practice: high-entropy bearer tokens are the OAuth standard (RFC 6750), and short lifetimes with refresh-token rotation follow the OAuth security best current practice (RFC 9700). Keeping only a hash of each token means a database copy yields no usable credential, the same rule NIST SP 800-63B sets for stored passwords. Locking one copy of the account key per holder with AES-256-GCM, an authenticated cipher that NIST also approves for wrapping keys (NIST SP 800-38F) is envelope encryption, the pattern cloud key-management services use.

Why this is current best practice: keyed tags are the standard construction for search over encrypted data (Song, Wagner and Perrig, IEEE S&P 2000). Filtering on trigrams and then checking the real match is how production regex search works (Russ Cox, Regular Expression Matching with a Trigram Index). The known cost is access-pattern leakage (Cash et al., Leakage-Abuse Attacks Against Searchable Encryption, CCS 2015), which is why this design names it as a limit and asks reviewers about it (question 1).

Why this is current best practice: revoking one holder deletes its only way to open the key through the service. Deleting every copy, as account deletion does, is cryptographic erase, a sanitization method NIST recognizes (SP 800-88 Rev. 1). Revoking a token server-side, effective on its next use, is what OAuth token revocation specifies (RFC 7009). Two gaps remain: backups hold old copies for up to 30 days, and the other copies of the same key stay valid (see What it does not protect).

The server never stores the account key, a token or plaintext. It holds the account key in memory only while it answers a request from an approved token.

One rule for every credential. Each credential has its own locked copy of the account key. Every hand-off opens the copy with the old credential, locks a new copy under the new one, and deletes the old. An OAuth authorization code, the web app’s connect code and a renewed token are all hand-offs of this kind, so the server never needs to store a token while one is in transit. A recovery code is the same thing on paper.