Generating the key
Clicking "Generate AES-256 key" calls the browser's CSPRNG for 32 truly random bytes — the same entropy source covered in the Random Number Generation module. There's no separate "key schedule" step yet; AES derives its round keys from this value internally, only once you actually encrypt.
Encrypting: counter mode underneath
GCM builds a counter block J0 from the random 96-bit IV you see displayed, with a 32-bit counter appended starting at 1. Each 128-bit block of your plaintext is XORed with AES(K, J0 + i), and the counter increments for every block — exactly the CTR mode covered in the AES module. This is also why the ciphertext is exactly as long as the plaintext: GCM never pads.
Authenticating: GHASH and the tag
While the ciphertext is produced, GCM separately runs it through GHASH — built entirely from multiplication in the finite field GF(2¹²⁸), keyed by H = AES(K, 0¹²⁸). Each ciphertext block is folded in one at a time (Horner's method), so the final result depends on every bit of the ciphertext, in order.
The 16-byte tag appended to your ciphertext is this GHASH output XORed with AES(K, J0) — the same counter-mode building block used for encryption, applied once more to seal the tag.
What one click of "Encrypt" actually runs
- 1
Build J0
The random IV plus a starting counter of 1.
- 2
Encrypt via counter mode
Each block XORed with AES(K, J0 + i) to produce ciphertext.
- 3
Fold ciphertext through GHASH
Every ciphertext block multiplied into a running value in GF(2¹²⁸).
- 4
Seal the tag
GHASH output XORed with AES(K, J0) — the 16 bytes shown as the auth tag.
GHASH folds in one ciphertext block at a time.
The same thing, as a block diagram
The encryption path (top) and the authentication path (bottom) run side by side — the ciphertext produced on top feeds directly into the GHASH chain on the bottom, and the tag is what comes out the other end.
GCM: counter-mode encryption + GHASH authentication
Shown for a single plaintext block; longer messages chain more ciphertext blocks through the same GHASH multiplication before the final XOR that produces the tag.
Why the tamper button breaks decryption
"Tamper with 1 byte" flips 8 bits of ciphertext before decryption. Multiplication in GF(2¹²⁸) has the same avalanche property as a hash function — one changed input bit changes GHASH's output completely and unpredictably. Your browser recomputes the tag from the (now tampered) ciphertext, compares it to the 16 bytes that travelled alongside it, finds no match, and crypto.subtle.decrypt() throws rather than returning any plaintext at all, even a single correct byte.