Skip to content

AES Decryption Tool — OpenSSL & CryptoJS Compatible

Decrypt AES online — GCM/CBC/CTR, passphrase or raw key, auto-detects OpenSSL & CryptoJS "U2FsdGVkX1" format. 100% in-browser, keys never leave the page.

No Tracking Runs in Browser Free
Everything runs in your browser — your key and data never leave this page.
Recommended
Key size
Key type
Advanced options
Plaintext
Need the dedicated encrypt page?
Reviewed for cryptographic accuracy against FIPS 197, NIST SP 800-38D, OWASP, and the W3C Web Crypto specification — Go-Tools Security Team · Jul 16, 2026

How AES Decryption Works

AES decryption is the exact inverse of encryption: the same symmetric key that scrambled the data runs the cipher's rounds in reverse to recover the original bytes. Because AES is symmetric, there is no separate 'decrypt key' — you must supply the identical key or passphrase, mode, and IV that were used to encrypt. Get the parameters right and the plaintext comes back byte-for-byte; get one wrong and you get an error or garbage.

To decrypt correctly, four things must match the encryption exactly: the key (or the passphrase plus its key-derivation settings), the mode of operation (GCM, CBC, or CTR), the IV or nonce, and — for GCM — the authentication tag. Miss any of them and the result is either a hard error (a GCM authentication failure, a CBC padding failure) or silent garbage (CTR, or CBC with the wrong IV). This tool reads the salt, IV, and tag out of the ciphertext for you when they are packed in, and diagnoses the failure when something does not line up.

Ciphertext arrives in a few different shapes, and this tool understands three. Format 1 is our self-contained passphrase layout: a 16-byte salt, then the IV, then the ciphertext (with the GCM tag appended in GCM mode) — decrypt it with only the passphrase. Format 2 is the raw-key layout: the IV prepended to the ciphertext, or 'bare' ciphertext where you supply the IV separately. Format 3 is the OpenSSL layout, produced by the openssl enc command and by CryptoJS.

That OpenSSL format is worth knowing by sight. It begins with the 8 ASCII bytes Salted__, followed by an 8-byte salt and then the ciphertext, and when the whole thing is Base64-encoded those first bytes always render as the prefix U2FsdGVkX1. So if a ciphertext you were handed starts with U2FsdGVkX1, it was almost certainly produced by openssl enc or a CryptoJS AES.encrypt(text, passphrase) call. CryptoJS derives its key with the legacy EVP_BytesToKey function using a single MD5 pass, while modern openssl uses PBKDF2 — which is why picking the right key-derivation function is the whole game when decrypting these. If your input is Base64 and you just want to see the raw bytes, our Base64 decoder will show them. To create ciphertext in these formats, use the AES encryption tool.

// AES-256-GCM decrypt with a passphrase (PBKDF2-HMAC-SHA256, 600,000 iterations).
// Identical code runs in the browser and in Node.js 20+ via Web Crypto.
async function aesGcmDecrypt(base64, passphrase) {
  const enc = new TextEncoder();
  const packed = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
  const salt = packed.slice(0, 16), iv = packed.slice(16, 28); // salt(16) | iv(12)
  const ct = packed.slice(28);                                 // ciphertext + tag
  const baseKey = await crypto.subtle.importKey(
    'raw', enc.encode(passphrase), 'PBKDF2', false, ['deriveKey']);
  const key = await crypto.subtle.deriveKey(
    { name: 'PBKDF2', salt, iterations: 600000, hash: 'SHA-256' },
    baseKey, { name: 'AES-GCM', length: 256 }, false, ['decrypt']);
  const plain = await crypto.subtle.decrypt(
    { name: 'AES-GCM', iv }, key, ct);        // throws if the tag fails
  return new TextDecoder().decode(plain);     // recovered plaintext
}

Key Features

Auto-detects OpenSSL & CryptoJS output

Paste ciphertext beginning U2FsdGVkX1 and the tool recognizes the Salted__ format and offers a one-click switch to the matching decrypt flow, so you never fight a dead-end error.

Three key-derivation functions

Decrypt across every generation of the openssl enc format: PBKDF2 with a custom iteration count, EVP_BytesToKey with SHA-256, or the legacy MD5 single-pass that CryptoJS uses.

Explains why decryption failed

Instead of a generic error you get a diagnosis: wrong key versus wrong IV, a GCM authentication failure, a CBC padding error, base64 pollution, or 'this looks like an MD5-era ciphertext, try EVP-MD5'.

Equivalent openssl command shown live

See the exact openssl enc -d command that reproduces the decryption on the command line, iteration count and all, so you can verify the result outside the browser.

Passphrase or raw key, GCM/CBC/CTR

Handles self-contained passphrase ciphertext, raw-key ciphertext with a prepended or separately supplied IV, and all three Web Crypto modes.

100% in your browser

Ciphertext and keys are processed locally with the Web Crypto API and never uploaded — you can verify with the Network tab or by going offline.

AES Decryption Examples

Decrypt a self-contained passphrase ciphertext (GCM)

salt(16) ‖ iv(12) ‖ ciphertext ‖ tag(16), Base64 — from the encrypt page
The quick brown fox jumps over the lazy dog.

This is the reverse of the encrypt page's GCM example. Take the self-contained Base64 string it produced for the passphrase hunter2, paste it here with Mode GCM, Key size 256, Key type Passphrase and the same passphrase hunter2, and the original sentence comes back. You do not enter a salt or IV separately — the tool reads the 16-byte salt and 12-byte IV from the front of the string, derives the key with PBKDF2-HMAC-SHA256 (600,000 iterations), and verifies the appended 128-bit GCM tag before returning any text. Click Load example on the encrypt page to generate a fresh string, then decrypt it here.

Decrypt real OpenSSL / PBKDF2 output

U2FsdGVkX18AESIzRFVmd1PBwxIFQpF+VgIhTK0aDHQ=
Attack at dawn!

This is genuine openssl enc output. Paste it in, switch to OpenSSL mode (Mode CBC, Key type Passphrase), enter the passphrase correct-horse, choose the PBKDF2 key-derivation function, and set iterations to 10,000 — the plaintext is Attack at dawn!. The U2FsdGVkX1 prefix told the tool this was Salted__ format, and the 8-byte salt sits right after that header inside the Base64. You can reproduce the exact decryption on the command line: echo 'U2FsdGVkX18AESIzRFVmd1PBwxIFQpF+VgIhTK0aDHQ=' | openssl enc -d -aes-256-cbc -pbkdf2 -iter 10000 -pass pass:correct-horse -base64 -A. If a similar ciphertext fails with PBKDF2, it was likely made by CryptoJS — switch the KDF to EVP-MD5 and try again. Click Load OpenSSL example to fill these values automatically.

How to Decrypt AES Ciphertext

  1. 1

    Paste the ciphertext

    Drop your Base64 or Hex ciphertext into the input. If it begins with U2FsdGVkX1, the tool flags it as OpenSSL/CryptoJS format and offers to switch you to the right mode.

  2. 2

    Set the format and mode

    For a self-contained string from this tool, keep Passphrase mode and the matching GCM/CBC/CTR. For OpenSSL/CryptoJS output, accept the switch (CBC + passphrase). For raw-key data, choose Raw key and the encoding, and supply the IV if it is not prepended.

  3. 3

    Choose the key-derivation function

    In OpenSSL mode, pick PBKDF2 (and its iteration count), EVP-SHA256, or EVP-MD5 to match how the key was derived. EVP-MD5 is the one CryptoJS uses.

  4. 4

    Enter the passphrase or key

    Type the exact passphrase, or paste the exact raw key as hex or Base64. The plaintext appears on the right as soon as everything matches.

  5. 5

    Read the diagnosis if it fails

    If decryption errors, the panel names the likely cause — wrong IV, wrong key, padding error, base64 pollution, or a KDF mismatch — so you can adjust one setting at a time instead of guessing.

Why AES Decryption Fails — and How to Fix It

GCM authentication failed

GCM refuses to return plaintext if the tag does not verify. The cause is a wrong passphrase or key, the wrong mode, a wrong IV, or altered/truncated ciphertext — GCM cannot say which. Recheck each against how the data was encrypted.

✗ Wrong
mode: CBC        // but the data was encrypted with GCM
=> Authentication failed
✓ Correct
mode: GCM, same passphrase and key size as encryption
=> plaintext

CBC: a garbled first block means the wrong IV

In CBC the IV only affects the first 16-byte block. If block one is garbage but the rest decodes cleanly, your IV is wrong; if everything is garbage, the key is wrong.

✗ Wrong
iv: 00000000000000000000000000000000   (wrong IV)
=> first block corrupt, rest readable
✓ Correct
iv: (the exact IV used to encrypt)
=> Attack at dawn!

CBC / PKCS#7 padding error

A padding error almost always means the key is wrong; it can also mean the ciphertext was corrupted, truncated, or was not PKCS#7-padded. Confirm the full ciphertext was copied and that the passphrase and KDF match.

✗ Wrong
passphrase: hunter3   // one character off
=> padding error
✓ Correct
passphrase: hunter2   // exact
=> plaintext

Base64 (or hex) pollution

Newlines, spaces, or smart quotes pasted along with the ciphertext break decoding. The tool strips whitespace automatically, but missing or extra characters still fail.

✗ Wrong
“U2FsdGVkX1...”   (curly quotes and trailing junk copied in)
✓ Correct
U2FsdGVkX18AESIzRFVmd1PBwxIFQpF+VgIhTK0aDHQ=   (clean Base64)

U2FsdGVkX1 detected but OpenSSL mode is off

If the input starts with U2FsdGVkX1 you are looking at OpenSSL/CryptoJS Salted__ output, which will not decrypt as a normal passphrase string. The tool shows a banner; click Switch to OpenSSL mode and pick the KDF.

✗ Wrong
OpenSSL compatible: off
input: U2FsdGVkX1...
=> cannot parse
✓ Correct
OpenSSL compatible: on, KDF chosen
=> plaintext

KDF mismatch (the CryptoJS trap)

A ciphertext that fails with PBKDF2 or SHA-256 but decrypts with EVP-MD5 was produced by CryptoJS or openssl 1.0.2 and earlier. On the command line those need -md md5.

✗ Wrong
KDF: PBKDF2       // CryptoJS ciphertext
=> padding error
✓ Correct
KDF: EVP-MD5      // matches CryptoJS
=> plaintext

What You Can Do with AES Decryption

Decrypt openssl enc output
Read a Salted__ blob produced by openssl enc -aes-256-cbc without dropping to a terminal: paste the Base64, enter the passphrase, pick the KDF, and get your plaintext.
Decrypt CryptoJS ciphertext
Recover data from a legacy app that used CryptoJS AES.encrypt(text, passphrase). Select EVP-MD5 to match its single-pass MD5 key derivation — the step most people miss.
Debug a decryption that keeps failing
When your own code cannot decrypt something, paste it here to isolate whether the problem is the key, the IV, the mode, the encoding, or the KDF, using the diagnosis panel.
Verify an encryption round-trip
Confirm that ciphertext from the AES encrypt page or from your app decrypts back to the exact original bytes.
Understand an unknown ciphertext
Identify a format from its shape — a U2FsdGVkX1 prefix, or a fixed-length prefix that looks like an IV — and work out how it was produced before you try a key.

AES Decryption Internals & Formats

GCM decryption — authenticated
GCM recomputes the 128-bit tag over the ciphertext and compares it before returning any plaintext; a mismatch throws instead of leaking corrupted data. It uses the 96-bit IV that was prepended. A GCM failure means the key, mode, IV, or ciphertext is wrong — the cipher cannot tell you which, only that authentication failed.
CBC decryption — watch the first block and the padding
CBC has two distinct failure signatures. If only the first 16-byte block is garbled and the rest looks right, the IV was wrong. If every block is garbage, the key is wrong. A PKCS#7 padding error usually means the key is wrong, or the ciphertext was corrupted or truncated. CBC has no tag (unlike an authenticated construction such as an HMAC), so a wrong key can even decrypt to plausible-looking bytes.
CTR decryption — silent on error
CTR never throws: a wrong key simply yields garbage, which usually surfaces as a 'not valid UTF-8' error once the bytes are decoded to text. Match the counter/IV exactly. Because there is no integrity check, treat any CTR output you did not authenticate separately with suspicion.
Ciphertext layouts (F1 / F2 / F3)
Format 1 (passphrase) is salt(16) then IV then ciphertext, with the 16-byte GCM tag appended in GCM mode. Format 2 (raw key) is IV then ciphertext, or bare ciphertext with a separately supplied IV. Format 3 (OpenSSL) is the ASCII header Salted__ then an 8-byte salt then ciphertext. Knowing which layout you have tells the tool where the salt and IV live, and a raw key itself should come from a CSPRNG — see the secret key generator.
Key derivation: matching what encrypted the data
For self-contained passphrase ciphertext this tool uses PBKDF2-HMAC-SHA256 at 600,000 iterations. For OpenSSL/CryptoJS ciphertext you must select the KDF that was used: PBKDF2 (the openssl -pbkdf2 default is 10,000 iterations — set your exact count), EVP_BytesToKey with SHA-256 (openssl 1.1+ without -pbkdf2), or EVP_BytesToKey with MD5 and a single pass (CryptoJS and openssl 1.0.2 and earlier). The classic 'it will not decrypt' bug is a CryptoJS or old-openssl ciphertext tried with SHA-256 — switch to EVP-MD5 and it works.

AES Decryption Best Practices

Start by identifying the format
Before touching settings, look at the ciphertext. A U2FsdGVkX1 prefix means OpenSSL/CryptoJS; a self-contained string from this tool is passphrase format; a bare blob usually needs a raw key and a separate IV.
Match the key-derivation function exactly
For OpenSSL/CryptoJS ciphertext the KDF is as important as the passphrase. If PBKDF2 fails, try EVP-MD5 (CryptoJS, old openssl); the iteration count must match too, not just the algorithm.
Paste the ciphertext cleanly
Stray newlines or spaces from copying can corrupt Base64. This tool strips whitespace, but if decoding still fails, check for smart quotes, missing characters, or a truncated copy. Our Base64 tool can help you inspect a suspect string.
Treat a wrong-key result honestly
With CTR or CBC a wrong key can produce bytes rather than an error. If the output looks like garbage or fails the UTF-8 check, the key or IV is wrong — do not trust partial-looking output.
Never send secret ciphertext or keys to a server
The point of decrypting in the browser is that nothing leaves the page. Avoid tools that upload; this one uses Web Crypto locally, and you can verify with the Network tab or by going offline. AES-256 is strong — CNSA 2.0-approved for TOP SECRET — so if you cannot decrypt, the problem is the parameters, not the cipher.

AES Decryption FAQ

Can you decrypt AES without the key?
No — and be wary of anyone who says otherwise. AES has no known practical weakness, so without the key or passphrase the only option is brute force, and the numbers make that hopeless: AES-256 has 2^256 possible keys, a space so large that even astronomically fast guessing would take far longer than the age of the universe to make a dent. There is no 'forgot my password' recovery for AES, and no legitimate service that decrypts arbitrary AES ciphertext for you. If you have lost the key, the data is gone; if you have it, this tool will decrypt in your browser. When decryption fails despite having the key, the culprit is almost always the wrong mode, IV, or key-derivation function — not a broken cipher.
How do I decrypt openssl enc output?
Paste the Base64 ciphertext (it starts with U2FsdGVkX1) and accept the tool's prompt to switch to OpenSSL mode, or turn on OpenSSL-compatible mode manually with Mode CBC and Key type Passphrase. Enter the passphrase, then choose the key-derivation function openssl used: PBKDF2 if the file was made with -pbkdf2 (set the same iteration count — the default is 10,000), or EVP-SHA256 for a plain OpenSSL 1.1+ file with no -pbkdf2. The tool shows the exact openssl enc -d command it mirrors. For example, echo 'U2FsdGVkX18AESIzRFVmd1PBwxIFQpF+VgIhTK0aDHQ=' | openssl enc -d -aes-256-cbc -pbkdf2 -iter 10000 -pass pass:correct-horse -base64 -A prints Attack at dawn!.
What does U2FsdGVkX1 at the start of a ciphertext mean?
It is the fingerprint of the OpenSSL Salted__ format. OpenSSL and CryptoJS prepend the 8 ASCII bytes Salted__ followed by an 8-byte salt to their ciphertext, and when that is Base64-encoded the leading bytes always come out as U2FsdGVkX1. Seeing it tells you two things: the data was produced by the openssl enc command or a CryptoJS AES.encrypt(text, passphrase) call, and the key was derived from a passphrase — so you will need the passphrase plus the right key-derivation function, not a raw key. Paste it in and this tool detects the format automatically and offers to switch you into the matching flow.
How do I decrypt CryptoJS ciphertext?
CryptoJS's AES.encrypt(text, passphrase) uses the OpenSSL Salted__ format, but with a key derived by the legacy EVP_BytesToKey function using MD5 and just one iteration. So paste the ciphertext, switch to OpenSSL mode, and choose the EVP-MD5 key-derivation function — this is the setting almost everyone misses, and it is why CryptoJS ciphertext appears to 'not decrypt' when it is tried with PBKDF2 or SHA-256. Enter the same passphrase and your plaintext appears. On the command line the equivalent decryption needs -md md5.
GCM vs CBC — why does my ciphertext decrypt one way and not the other?
The mode has to match how the data was encrypted; the two are not interchangeable. GCM includes a 128-bit authentication tag and will refuse to decrypt (authentication failure) if you pick the wrong mode, key, or IV. CBC has no tag, so choosing it wrongly can silently produce garbage or a padding error rather than a clear failure. If GCM authentication keeps failing, confirm the data really is GCM; if CBC gives padding errors, recheck the passphrase and the key-derivation function. This tool's diagnosis panel points you at the most likely cause instead of a generic error.
Is my ciphertext or key uploaded when I decrypt here?
No. Decryption runs entirely in your browser through the Web Crypto API (crypto.subtle) — the same audited engine your browser uses for HTTPS. Your ciphertext, passphrase, and key are never sent anywhere; you can watch the Network tab stay empty, or disconnect from the internet and decrypt offline. That local-only design is what makes it reasonable to paste sensitive ciphertext here, though you should still avoid handling production secrets in any online tool.
What is the difference between a passphrase and a raw key when decrypting?
It decides how you enter the secret. If the data was encrypted from a passphrase (including anything in the U2FsdGVkX1 format), choose Passphrase and let the tool derive the key with the matching KDF and salt. If it was encrypted with an exact 128/192/256-bit key, choose Raw key and paste those bytes as hex or Base64 — and you may also need to supply the IV, either prepended to the ciphertext or entered separately. Trying to decrypt passphrase data with a raw key, or vice versa, is a common reason decryption fails. To create ciphertext in either shape, use the AES encrypt tool.

Related Tools

View all tools →