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
Scan with WeChat to share this tool
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
| Input | Message |
|---|---|
The first example with password wrong password | Authentication 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 key | This 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
| Mode | Layout |
|---|---|
| Password | v2: + 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 prefix | Same 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 key | Base64 or hex of IV (12) | ciphertext | tag (16). With the IV field filled: ciphertext | tag only. |
| Files | The 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.encshows 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.