Skip to content
AZ Tools

AES-GCM Encrypt / Decrypt (key, nonce, AAD)

Encrypt and decrypt with AES-GCM in your browser: hex key and nonce, optional AAD, selectable tag length, and the ciphertext and tag kept apart.

How to use

  1. Choose encrypt or decrypt, then set the key as hex — 16 bytes for AES-128 or 32 for AES-256. The two buttons draw a fresh key from the browser CSPRNG if you need one.
  2. Give a nonce. Press the 96-bit button for a new random one every time you encrypt; the field warns if you paste a length other than 96 bits, and the page warns in red if you reuse a pair.
  3. Add additional authenticated data if the other end uses it. It is authenticated but not encrypted, and it has to match byte for byte on decryption or the tag check fails.
  4. Run it. Encryption gives the ciphertext and the tag separately, plus their concatenation in hex and base64; decryption takes the two apart, or splits them itself if you leave the tag field empty.

About this tool

Show

AES-GCM is the authenticated mode almost everything uses now, and it is unforgiving in one specific way: it is secure exactly as long as you never encrypt two different messages under the same key and nonce. Do it once and the XOR of the two ciphertexts is the XOR of the two plaintexts, so knowing either message hands over the other; worse, the authentication subkey leaks, and an attacker can forge valid tags for messages you never sent. This page keeps track of the key and nonce pairs you encrypt with and says so in red if you repeat one, because nothing else about the output looks wrong.

The tool also separates the two halves the Web Crypto API insists on joining. crypto.subtle.encrypt returns one buffer with the tag appended, while every library and wire format on the other side of your problem wants the ciphertext and the tag as distinct fields. You get both here, plus the concatenation in hex and base64, so you can hand whichever shape the other end expects.

Three details it exposes rather than hides. The nonce should be 96 bits: GCM will take any non-empty length, but only 96 bits is used as-is — every other length is hashed down to 96 first, which is slower and buys nothing. The tag can be 128, 120, 112, 104, 96, 64 or 32 bits and nothing else; 48 is refused by the browser outright. And AES-192 simply does not work: Chromium answers a 24-byte key with OperationError: 192-bit AES keys are not supported, which is a Chromium decision rather than a limit of AES, and the page reports it as the browser says it rather than silently falling back.

You can check the tool against the algorithm specification without leaving the page. Set the key to thirty-two zeros, the nonce to twenty-four zeros, and encrypt nothing at all: the tag is 58e2fccefa7e3061367f1d57a4e7455a, which is test case 1 of the original GCM proposal. Encrypt sixteen zero bytes under the same key and nonce and the ciphertext is 0388dace60b6a392f328c2b971b2fe78 with tag ab6e47d42cec13bdf53a67b21257bddf. A 256-bit zero key over an empty message gives 530f8afbc74536b9a963b4f1c4cb738b.

A failed decryption tells you nothing beyond that it failed, and that is the correct behaviour rather than a gap in this page: a decryptor that distinguished a wrong tag from wrong additional data would be an oracle an attacker could question a few thousand times. Everything here runs in your browser through the Web Crypto API and no key, nonce or message is sent anywhere.

Frequently asked questions

What actually happens if I reuse a nonce?

Two things, and the second is worse. The keystream repeats, so C1 XOR C2 equals P1 XOR P2 — with one plaintext known the other falls straight out, and even without one, English or JSON is usually recoverable from the XOR alone. Then the repetition exposes GCM authentication subkey H, which turns forgery from infeasible into arithmetic: an attacker can produce valid tags for messages you never wrote. This is why the nonce, not the key, is the thing to be careful with in GCM.

Why are the ciphertext and the tag separate here?

Because the Web Crypto API joins them and most other things do not. crypto.subtle.encrypt returns the tag appended to the ciphertext, so a 21-byte message with a 128-bit tag comes back as 37 bytes. Go, Java, OpenSSL command lines, JWE and most protocol formats treat the tag as its own field. This page shows both halves and the joined form so you can match whatever is on the other side.

Should the nonce be random or a counter?

Either, as long as it never repeats for a given key. A counter is safer when you control all the encryptors, because randomness has a birthday bound: with 96-bit random nonces the chance that any two collide reaches roughly one in 8.6 billion after 2^32 messages under one key, and it grows with the square of the count, which is why NIST SP 800-38D caps a key at 2^32 randomly generated nonces. A counter has no such limit but breaks the moment two machines share a key and both start at zero.

Can I use AES-192?

Not in Chromium, and therefore not in Chrome or Edge. A 24-byte key raises OperationError: 192-bit AES keys are not supported. The restriction is the browser implementation, not the algorithm — OpenSSL and Java handle AES-192 fine — and Firefox and Safari have differed here over time. If you need interoperability across browsers, use 128 or 256.

Why does decryption not say what went wrong?

Deliberately. A tag check either passes or fails, and a decryptor that reported which input was wrong would let an attacker probe it: padding-oracle and related attacks are built exactly out of a server that distinguishes one failure from another. The browser throws OperationError with an empty message. When you are debugging, change one input at a time — the additional authenticated data is the usual culprit, because an empty field and a field containing nothing are not always the same thing across libraries.

Related tools