DevTools Hub

Search tools

Search for a developer tool

Encryption

AES Encrypt/Decrypt

Encrypt or decrypt text with AES-GCM or AES-CBC, using a key derived from a passphrase.

Part of the Encryption Toolkit

What this does

Encrypts or decrypts text with AES, using a key derived from a passphrase you provide — no key management, no separate key file. Everything runs through the browser's own crypto.subtle Web Crypto API, not a hand-rolled JavaScript implementation, so the actual encryption is the same native code your browser uses for everything else that needs it.

See Encoding vs Encryption vs Hashing for where this fits relative to the other two — this is the one of the three that's actually reversible with the right secret. And see AES vs RSA for why AES (this tool) and RSA Key Pair Generator solve genuinely different problems rather than being two options for the same job.

Why AES-GCM is the default, not AES-CBC

AES-GCM is authenticated — decryption fails loudly and cleanly if the ciphertext was altered, or if the passphrase is wrong, because GCM computes and checks an authentication tag as part of decryption. AES-CBC has no such check built in: a wrong key or tampered ciphertext can decrypt into garbled bytes without any error at all, silently. GCM is the modern default for exactly this reason — it turns an entire category of subtle failure into a hard, obvious one. CBC is included here for interoperability with older systems that only support it, not because it's the better choice for anything new.

How the passphrase becomes a key

A passphrase isn't a valid AES key by itself — AES needs a fixed-size 256-bit key, and a human-chosen passphrase is neither the right size nor random enough on its own. This tool runs the passphrase through PBKDF2-HMAC-SHA256 at 600,000 iterations — the same OWASP-recommended iteration count this site uses for password hashing, see Password Hashing Best Practices — with a fresh random salt generated on every encryption, so encrypting the exact same text with the exact same passphrase twice produces two completely different outputs.

The output format

Encrypting produces one base64 string containing everything decryption needs except the passphrase itself: a one-byte mode marker, a 16-byte salt, the IV (12 bytes for GCM, 16 for CBC), and the ciphertext. Pasting that same blob back in and switching to Decrypt reads the mode back out automatically — there's nothing else to track or remember beyond the passphrase.

To decrypt this format outside the browser, in Node.js:

const crypto = require("crypto");

function decrypt(base64, passphrase) {
  const buf = Buffer.from(base64, "base64");
  const mode = buf[0] === 1 ? "aes-256-gcm" : "aes-256-cbc";
  const ivLen = buf[0] === 1 ? 12 : 16;
  const salt = buf.subarray(1, 17);
  const iv = buf.subarray(17, 17 + ivLen);
  const rest = buf.subarray(17 + ivLen);

  const key = crypto.pbkdf2Sync(passphrase, salt, 600_000, 32, "sha256");
  const decipher = crypto.createDecipheriv(mode, key, iv);

  if (mode === "aes-256-gcm") {
    const tag = rest.subarray(rest.length - 16);
    decipher.setAuthTag(tag);
    return Buffer.concat([decipher.update(rest.subarray(0, -16)), decipher.final()]).toString("utf8");
  }
  return Buffer.concat([decipher.update(rest), decipher.final()]).toString("utf8");
}

What this doesn't do

No key-file mode — passphrase-derived keys only, which covers the common "encrypt this text with a password" case but not scenarios needing a specific raw key someone else already generated. Nothing is ever sent anywhere; encryption and decryption both run entirely in your browser, and closing the tab discards everything including the derived key.

FAQ

What happens if I forget the passphrase?

The encrypted text is permanently unrecoverable. There's no backdoor, no recovery option, and no way to derive the same key without the exact original passphrase — that's the entire point of encryption actually working.

Why did decryption fail?

Almost always a wrong passphrase, or a blob that got truncated or edited when copied. With AES-GCM you'll get a clear failure either way. With AES-CBC, a wrong passphrase sometimes produces garbled output instead of an error — see "Why AES-GCM is the default" above for why that difference exists.

Is 600,000 PBKDF2 iterations overkill for this?

It's deliberately matched to this site's own password-hashing recommendation rather than a lighter, encryption-specific number, so encrypting or decrypting a short message takes a noticeable but small fraction of a second — a reasonable tradeoff for making a weak, guessable passphrase meaningfully harder to brute-force.

Try it yourself

Hash Comparison covers PBKDF2 and the other password-hashing algorithms this tool's key derivation is built on, and Encoding vs Encryption vs Hashing covers the concepts this tool implements. Both are free to read alongside this page.

Related tools