Security Runs locally Ready to use Built-in examples No tracking

AES Encrypt / Decrypt

Encrypt a message with a password and get a single string that carries everything the other side needs: salt, initialisation vector and ciphertext. Each run uses fresh random values, so encrypting the same text twice never produces the same output.

Storing a private note in a cloud service, or sending it to one person without its being readable in between, is the standard use for symmetric encryption. A key is derived from your password, given a random salt and initialisation vector, and the same sentence encrypts differently every time — the security rests on properly chosen parameters, not on keeping the algorithm secret. One thing to accept up front: lose the password and nobody, including this tool, can recover the text.

Three things to remember before using it. There is no way to recover a forgotten password, so keep it somewhere safe. Decryption requires the password, the key length and the iteration count to match exactly what encryption used. And the output is a custom concatenation of a 16-byte salt, a 16-byte initialisation vector and the ciphertext — not OpenSSL's Salted__ format — so decrypting it elsewhere means unpacking according to that layout.

How to use

  1. Enter the text and a password.
  2. Choose the key length and iteration count if another system requires specific ones.
  3. Copy the single output string, which carries salt, IV and ciphertext.
  4. Keep the password safe; decryption needs exactly the same parameters.

How it works

The output string's packaging format

The output is a fixed three-part concatenation: a 16-byte salt + a 16-byte initialization vector (IV) + the ciphertext, displayed as Base64 (default) or hex. Neither the salt nor the IV is secret — store or send them alongside the ciphertext. Decryption unpacks them in the same order, so anything encrypted here decrypts reliably as long as the password, key length and iteration count match.

Why two encryptions differ

Every encryption generates a fresh random salt and IV, so the same password and plaintext yield different ciphertexts each time — by design. If identical plaintext always produced identical ciphertext, attackers could infer "same content" from "same ciphertext" and precompute lookup tables (rainbow tables) for common password/plaintext pairs. Decryption is unaffected, since the salt and IV travel with the ciphertext.

Key points for encrypting and decrypting

Encrypting takes plaintext and a password; decrypting takes the full output string (don't clip the start, and don't mistake interior spaces for content) with the password, key length and iteration count all exactly as at encryption time. A wrong password or a single altered character in transit makes the tool report decryption failure — that's the PKCS#7 padding check doing its job: data validation failed, not the tool.

Method: AES-CBC (128 / 192 / 256-bit) with PKCS#7 padding; the key is derived from your passphrase with PBKDF2-HMAC-SHA256 (10,000 iterations by default), and the 16-byte salt and IV are regenerated randomly on every run. Output is Base64 or hex covering salt + IV + ciphertext. The implementation matches the FIPS-197 test vectors and node:crypto byte for byte.

Code example

Shell Encrypting and decrypting with OpenSSL on the command line

# Passphrase-derived key (PBKDF2) + random salt, the same idea as this tool
openssl enc -aes-256-cbc -pbkdf2 -iter 10000 -salt \
  -in plain.txt -out enc.txt
openssl enc -d -aes-256-cbc -pbkdf2 -iter 10000 \
  -in enc.txt -out plain.txt

# Note: OpenSSL's Salted__ header layout differs from this tool's three-part framing,
# so the output is not interchangeable — you would split the first 16 bytes as salt and the next 16 as IV

JavaScript Deriving a key with WebCrypto in the browser

// Derive an AES key from a passphrase (same parameters as this tool)
const baseKey = await crypto.subtle.importKey(
  "raw", new TextEncoder().encode(password), "PBKDF2", false, ["deriveKey"]);

const key = await crypto.subtle.deriveKey(
  { name: "PBKDF2", salt, iterations: 10000, hash: "SHA-256" },
  baseKey, { name: "AES-CBC", length: 256 }, false, ["encrypt", "decrypt"]);

// salt and iv are 16 bytes each and must be stored alongside the ciphertext

FAQ

I forgot the password — can it still be decrypted?

No, not by any means. The tool stores no password and hides none in the ciphertext — the key is derived from your password at each run, and a wrong password yields a wrong key and a validation failure. That is the point of AES: no backdoor, no bypass. Record the password somewhere safe after encrypting, ideally as a hint rather than beside the data.

Same text, same password — why do two encryptions differ?

Each run generates a fresh random salt and IV, saved alongside the ciphertext, so decryption is unaffected. The design is called semantic security: identical plaintext never produces identical ciphertext, so attackers can't compare ciphertexts to spot repeated content. If you need deterministic encryption (same input → same output, e.g. dedup queries), this AES-CBC flow isn't the right tool.

What are the salt and IV for, and why ship them with the ciphertext?

The salt derives the key from the password: without it, one password yields the same key everywhere and attackers can precompute tables for common passwords; a random salt gives every ciphertext its own key, killing precomputation. The IV makes each CBC block distinct so identical blocks don't encrypt identically. Neither is secret, but decryption needs the original values — hence they're packed into the output.

Does this tool use AES-GCM?

No — AES-CBC with PKCS#7 padding. CBC has the best compatibility: nearly every language and library supports it, so you can decrypt the output elsewhere. But CBC is not authenticated encryption: it detects most tampering (padding validation fails on decrypt) without GCM's explicit integrity verification. If tamper resistance matters and you control both ends, prefer a library with AES-GCM.

Should the output be Base64 or hex?

Depends on the destination. Base64 is shorter (about a quarter fewer characters than hex) and suits JSON, URL parameters and config files; hex uses only 0–9 and a–f, is easy to proofread, and compares byte by byte cleanly. Both are notations of the same bytes — either converts to the other, and decryption just needs the matching format.

How many PBKDF2 iterations should I pick?

The tool offers 1,000 / 10,000 / 50,000, defaulting to 10,000. More iterations raise the attacker's brute-force cost while making your own runs slower. For everyday use 10,000 is the common compromise; for long-term storage of important content pick 50,000 plus a long password. Decryption must use the same tier as encryption, or the derived key won't match.

Any requirements for the password?

The longer the better — at least 12 characters mixing case, digits and symbols; avoid names, birthdays, phone numbers, dictionary words and their simple mutations. PBKDF2 only raises the cost of guessing; it cannot make a weak password strong — "123456" falls eventually no matter the iteration count. Empty passwords are rejected.

Are my content and password uploaded?

No. AES, PBKDF2 and the randomness all run as in-browser JavaScript; the page makes no network requests, and nothing is written to localStorage — this tool has no history section precisely because it may handle real credentials. Confirm in DevTools' network panel; the tool even works offline.

Can it interoperate with OpenSSL, Java and other systems?

Yes, given identical parameters: AES-128/192/256-CBC, PKCS#7 padding, PBKDF2-HMAC-SHA256 key derivation, with the salt and IV taken from the head of the output string. The output is a custom three-part format, not OpenSSL's Salted__ format — so you can't feed the whole string to the openssl command; split off the first 16 bytes as salt and the next 16 as IV first.