Authenticated encryption returns ciphertext with an integrity check. With AES-GCM, the nonce must be unique for every encryption under one key; repeating it can break confidentiality and integrity. A 96-bit random nonce is a common choice for modest volumes, with a rekey and volume limit set by policy. Additional authenticated data can bind the ciphertext to a record ID, owner, and envelope version without hiding those fields. The decrypting side must reconstruct the same bytes exactly, then reject a failed authentication tag rather than showing partial plaintext.
Authenticated Encryption, Nonce, and Record Binding
Working case
Case 62 has note revision 29 owned by reviewer 47. The browser encrypts its UTF-8 note with a fresh 12-byte nonce, and authenticated metadata identifies case 62, reviewer 47, and schema version 3. A copied ciphertext moved under case 63 fails to authenticate because the record binding differs. A changed tag also fails. The server may store the envelope but still checks the session and object permission on upload and download. If the app cannot unlock or authenticate the note, it keeps the original envelope for recovery rather than overwriting it with an empty draft.
Implementation boundary
const caseKey = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt']);
const noteBytes = new TextEncoder().encode('Case 62: seal split at region 29');
const nonce = crypto.getRandomValues(new Uint8Array(12));
const recordBinding = new TextEncoder().encode('case=62;owner=47;schema=3');
const sealedNote = await crypto.subtle.encrypt({ name: 'AES-GCM', iv: nonce, additionalData: recordBinding }, caseKey, noteBytes);
const openedNote = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: nonce, additionalData: recordBinding }, caseKey, sealedNote);
console.log(new TextDecoder().decode(openedNote) === 'Case 62: seal split at region 29');
// Output: trueGenerate the nonce using a cryptographically secure random source for each encryption, never a timestamp or Math.random. Persist it with the ciphertext. Encode authenticated metadata in a stable canonical representation; changing field order or text encoding breaks decryption. Fix a key ID and envelope version so a later rotation can select the right key. Catch decryption rejection and present a corrupt-or-wrong-key state without exposing decrypted fragments. Bound note size and encrypt on save rather than every keystroke. Test with a known approved implementation before shipping; a demo that round-trips once does not establish safe nonce management over years.
Cost and boundaries
Encryption work is O(n) in plaintext bytes and creates at least one additional buffer. A nonce and authentication tag add fixed overhead per note. If many tiny records use one key, nonce-collision risk grows with operation count; the product must cap use or choose a coordinated scheme and rotate before its bound. Canonical metadata serialization also costs O(metadata size). Avoid logging plaintext, keys, or full envelopes. Measure save latency for realistic note sizes and verify the app can stop an oversized write before allocating several full copies.
Failure trace
A developer derives a nonce from case ID so revision 29 and revision 30 reuse it with the same key. A second implementation encodes authenticated metadata in a different order and can no longer read old drafts. Simulate both cases. Tamper with one ciphertext byte, swap envelopes between cases, change the owner ID, and try the wrong key. Every unauthorized or corrupt attempt must fail authentication. On failure, the app should retain the original bytes, show a recoverable error, and avoid silently generating a replacement note that could later synchronize as a deletion.
Verification
- Every encryption under a key uses a unique nonce.
- Changing bound case or owner metadata fails authentication.
- A failed decrypt never becomes an empty saved note.
Practice drill
Encrypt a 47-kilobyte case note twice under one key and confirm the nonce bytes differ. Decrypt with matching record metadata, then alter the case ID and verify authentication fails. Restart the app and decode the stored envelope using its declared version. Count how many encryptions one key can perform under the chosen nonce policy and define when the key rotates before reaching that bound.
Decision note
The envelope carries enough versioned context to reject swapped or altered records without confusing failure with an empty note.
Common Mistakes
- Reusing an ID-derived nonce with the same key.
- Omitting envelope version and key ID.
- Treating an authentication failure as missing content.
Related lessons
Browser Cryptography and Key Custody; Browser Encryption Threat Model and Key Custody; Password Unlock, Derivation, and Recovery; Key Rotation, Envelopes, and Device Loss; Authorization: check permission for this record on every request; Undo History, Autosave, and Revision Conflicts.
Connected practice
Build Project: encrypted local draft lifecycle and review Web Development: offline and browser-key decisions quiz.
