AES Encryption & Decryption

Encrypt and decrypt text or files with AES-256-GCM in your browser. Password (PBKDF2, 600,000 rounds) or raw key, clear auth-failure errors, nothing uploaded.

  • Runs in your browser
  • Your data never leaves your browser
  • Free · No Sign-Up
Password: the password, exactly as typed and encoded as UTF-8, goes through PBKDF2-HMAC-SHA256 with 600,000 iterations and a new 16-byte salt to make a 256-bit key; the ciphertext starts with v2:. Raw key: 16, 24 or 32 bytes entered as hex, Base64 or text (its UTF-8 bytes) and used as the AES key as they are; the ciphertext has no prefix. Generate fills in a random 256-bit key as hex, or as Base64 when that key format is selected. Show reveals the password you typed.
Text is encrypted as UTF-8. Click File…, or drop a file on the box, to encrypt a file instead: up to 256 MB, read into memory, and the result is a download button named after the file with .enc added. Nothing runs while you type: click Encrypt, or press Ctrl+Enter (⌘+Enter on a Mac). Decrypted text also appears in this box. Ctrl+L (⌘+L) empties both boxes, the password, key, IV, AAD and the chosen files while the focus is in the tool.
Paste a ciphertext with or without the v2: prefix, as Base64 (standard or URL-safe alphabet, padding optional) or hex; spaces and line breaks are ignored. Without a prefix, password mode tries 200,000 PBKDF2 iterations, then 600,000. Click Decrypt, or press Ctrl+Enter (⌘+Enter) in this box, and the text appears in the Plaintext box; bytes that are not UTF-8 are offered as a download. File…, or a dropped file, decrypts an encrypted file of up to 256 MB. Output sets Base64 or hex for newly encrypted text. Copy copies this box.

AES-256-GCM (NIST SP 800-38D) · password: PBKDF2-HMAC-SHA256, 600,000 iterations, new 16-byte salt · new 12-byte IV per encryption · 16-byte tag · runs in this tab, nothing is uploaded

Read the full guide AES Encryption: Key Sizes, Modes, IVs and the Mistakes That Break It
Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.

Examples

Password: a short message

Text Meet at 10:30, gate B, password correct horse battery staple. One run produced:

v2:l0KuwwrqkW+qHiVFcSad83WDHoteU8LkBJ/dw3N3LGl2PMwh3n8Q9u6wTM1CzpoDINVwd/yy4RRdM7QPNwXfGdc=

The 88 Base64 characters after v2: are 65 bytes: 16-byte salt, 12-byte IV, 21 bytes of ciphertext and a 16-byte tag. Paste the line with the same password and the message comes back; encrypt again and the line changes, because the salt and IV are new.

Raw key with a fixed IV (reproducible)

Key type Raw key, key (hex) 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f, IV field cafebabefacedbaddecaf888, text hello from ZeroTool, output Hex:

e2c6cc4ac55a296929667d871e6fe66b624fac923b410258258a224f6319fb85f4a398

That is 19 bytes of ciphertext and the 16-byte tag, the same on every run, which is useful for checking another implementation. The tool warns that reusing an IV with the same key breaks GCM (NIST SP 800-38D, section 8); for real data leave the IV field empty and a new IV goes in front of the output.

What the error messages mean

InputMessage
The first example with password wrong passwordAuthentication failed: the password or key is wrong, or the ciphertext was changed or cut off. Nothing was decrypted.
U2FsdGVkX1+YOZ21…This is OpenSSL enc or CryptoJS output …
The first example with v2: changed to v3:Unknown ciphertext version “v3:”.
The first example with … pasted in at character 21”…” at character 21 is not a Base64 character.
A v2: ciphertext with key type Raw keyThis ciphertext starts with “v2:”, so it was made with a password.

If the decrypted bytes are not UTF-8 text, the tool offers them as a download instead of showing replacement characters.

Ciphertext Format

ModeLayout
Passwordv2: + Base64 (or hex) of salt (16) | IV (12) | ciphertext | tag (16). Key: PBKDF2-HMAC-SHA256, 600,000 iterations, 32 bytes, the value in the OWASP Password Storage Cheat Sheet.
Password, no prefixSame layout, written by this page before 2026-09-30 (200,000 iterations). The tool tries 200,000, then 600,000, so it also reads this layout from other programs.
Raw keyBase64 or hex of IV (12) | ciphertext | tag (16). With the IV field filled: ciphertext | tag only.
FilesThe same bytes without Base64: password mode writes v2: followed by the binary payload.

The raw key layout is what Go’s gcm.Seal(nonce, nonce, plaintext, nil) returns and what Python’s AESGCM.encrypt returns once you put the nonce in front. This Python code (cryptography 45) reads and writes the tool’s formats:

import base64, os
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

def _key(password: str, salt: bytes, iterations: int) -> bytes:
    kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=iterations)
    return kdf.derive(password.encode("utf-8"))

def encrypt(text: str, password: str) -> str:
    salt, iv = os.urandom(16), os.urandom(12)
    ct = AESGCM(_key(password, salt, 600_000)).encrypt(iv, text.encode("utf-8"), None)
    return "v2:" + base64.b64encode(salt + iv + ct).decode()

def decrypt(token: str, password: str) -> str:
    # "v2:" = 600,000 iterations; no prefix = made by the tool before 2026-09-30 (200,000)
    token = token.strip()
    iterations = 600_000 if token.startswith("v2:") else 200_000
    data = base64.b64decode(token.removeprefix("v2:"))
    salt, iv, ct = data[:16], data[16:28], data[28:]
    return AESGCM(_key(password, salt, iterations)).decrypt(iv, ct, None).decode("utf-8")

def decrypt_raw(token: str, key_hex: str) -> str:
    # raw key mode, IV field empty: Base64 or hex of iv (12) | ciphertext | tag (16)
    token = token.strip()
    is_hex = all(c in "0123456789abcdefABCDEF" for c in token)
    data = bytes.fromhex(token) if is_hex else base64.b64decode(token)
    return AESGCM(bytes.fromhex(key_hex)).decrypt(data[:12], data[12:], None).decode("utf-8")

For a file, drop the first three bytes (b”v2:”) and split the rest the same way. A wrong password raises InvalidTag, the check behind the tool’s “Authentication failed”.

OpenSSL and CBC Ciphertext

openssl enc cannot read this format. Its manual says the command “does not support authenticated encryption modes like CCM and GCM, and will not support such modes in the future”; OpenSSL 3.6.1 answers -aes-256-gcm with enc: AEAD ciphers not supported.

Text starting with U2FsdGVkX1 is Base64 of Salted__, written by openssl enc or CryptoJS AES.encrypt(text, “passphrase”), normally AES-256-CBC. CBC has no tag, and the openssl manual notes that random data passes its padding check more often than 1 in 256, so a wrong password can print garbage. The tool detects the header and points here. Both commands were run on 2026-09-30:

# made with openssl enc -pbkdf2
openssl enc -d -aes-256-cbc -pbkdf2 -a -A -in message.txt
# made with CryptoJS 4.2.0 AES.encrypt(text, "passphrase")
openssl enc -d -aes-256-cbc -md md5 -a -A -in message.txt

How Other AES Tools Behave

Tested on 2026-09-30 in desktop Chromium with the same text, watching the page’s requests:

  • devglan.com sends the text and the key in a POST request to devglan.com/online-tools/aes-encryption; encryption happens on their server.
  • aesencryption.net runs in the browser by default, but uses CBC with a fixed IV (12345678b0z2345n) and the password bytes padded with zeros as the key, with no key derivation. The same text and password give the same ciphertext every time. A wrong password shows “Invalid padding (wrong key?)“.
  • codertools.net runs in the browser (CBC by default, text key). A wrong key leaves the result empty with no message.
  • go-tools.org runs in the browser, uses AES-GCM with PBKDF2 at 600,000 iterations and writes the same byte layout without a prefix. This tool decrypts its passphrase output as it is.

This page adds a message for each kind of failure, raw keys with a separate IV and AAD, and files, with no analytics or ads.

Limitations

  • GCM only. The tool does not encrypt or decrypt CBC, ECB or CTR, so it cannot read OpenSSL enc or CryptoJS output; use the commands above.
  • Password mode has a fixed format: PBKDF2-HMAC-SHA256, 600,000 iterations, 16-byte salt, no AAD. The tag is always 128 bits. Raw key mode adds an IV field (24 hex digits, or text used as UTF-8 bytes) and an AAD field (text).
  • Files up to 256 MB, processed in memory: a 200 MB file took about 0.8 s on the test laptop, 5 MB of text about 1.7 s (mostly drawing the text box).
  • With random 96-bit IVs, NIST SP 800-38D (section 8.3) limits one raw key to 232 encryptions. Password mode derives a new key for every encryption.
  • The file name is not encrypted: report.pdf.enc shows the original name. The encrypted file does not store the name.
  • The password is used as typed (UTF-8, no Unicode normalization): “é” as one character and as “e” plus a combining accent give different keys.
  • A weak password stays weak: make one with the Password Generator. Check a decrypted file against a known SHA-256 with the File Hash Checker; to share a key with a stranger, use an RSA key pair.

FAQ

Which AES mode does this tool use?

AES-GCM only. Password mode uses AES-256-GCM with a key from PBKDF2-HMAC-SHA256; raw key mode uses AES-128, AES-192 or AES-256 depending on the key length. GCM adds a 16-byte authentication tag, so a wrong password or a changed byte makes decryption fail with "Authentication failed" instead of printing garbage.

Why does the same text give a different ciphertext every time?

Each encryption uses a new random 16-byte salt and a new random 12-byte IV. NIST SP 800-38D requires that an IV is not reused with the same key, and the new salt also gives a new key. Every one of the different outputs decrypts to the same text.

Can OpenSSL decrypt the output?

No. openssl enc does not support GCM, and its manual says it never will. Use the Python code on this page, the Web Crypto API, or any AES-GCM library with the byte layout described below. The other way round, the tool recognizes OpenSSL enc and CryptoJS output (it starts with U2FsdGVkX1) and tells you which openssl command reads it.

Is my text, password or file sent anywhere?

No. Encryption runs with the Web Crypto API inside the browser tab. The page does not save your input, does not put it in the URL, and does not load Google Analytics or AdSense.

How strong does the password need to be?

PBKDF2 with 600,000 iterations makes each guess slower (on the laptop used to test this page, about 73 ms in Node.js 24 and 0.3–1.2 s in Chromium), but a short or common password is still guessed quickly. Use a long random passphrase, and send it to the recipient through a different channel than the ciphertext.