How to Encrypt a Message with a Password (in Your Browser)
A practical guide to password-based encryption: how AES-GCM with PBKDF2 actually works, why the wire format matters for future compatibility, the common foot-guns (weak passwords, no integrity check, ECB mode), and how to encrypt a message in your browser without trusting a remote service with the plaintext.
Modern password-based encryption uses three things together: a password (or passphrase) you remember, a key-derivation function that turns the password into a cryptographic key (PBKDF2 with high iteration count, or Argon2), and an authenticated encryption mode (AES-GCM is the modern standard). The combination gives you confidentiality (no one can read the message without the password) and integrity (no one can modify the ciphertext without being detected). A browser-based encryptor does all three in your browser, so the plaintext never leaves your device. The most common mistake is using a weak password — even AES-256 cannot protect a password that is in a dictionary.
Encrypting a message with a password is one of those things that sounds simple and is genuinely tricky to get right. The wrong approach is also the historically common one: encrypt with a hand-rolled scheme, use a weak password, use a non-authenticated mode, leak the key in the metadata. The right approach is to use a modern authenticated encryption scheme with a key derivation function designed for passwords. This post covers how that actually works, the common foot-guns, and how to do it in your browser without trusting a remote service with the plaintext.
What "password-based encryption" actually means
A password is not a cryptographic key. Passwords are short, low-entropy, and human-memorable. Cryptographic keys are long, high-entropy, and random. Turning a password into a key is a job for a key-derivation function (KDF), and turning a key + plaintext into a ciphertext is a job for an encryption algorithm. The modern stack is:
- Password. A human-memorable string. The only secret the user needs to remember.
- KDF. A function that takes the password and a salt, and produces a key. The two modern choices are PBKDF2 (older, well-understood, widely supported) and Argon2 (newer, more resistant to GPU attacks, less universally supported). For a browser-based tool, PBKDF2 is the practical choice because the browser's Web Crypto API supports it natively.
- Encryption. An authenticated encryption mode that takes the key and the plaintext, and produces a ciphertext plus an authentication tag. The two modern choices are AES-GCM (the standard, hardware-accelerated on most CPUs) and ChaCha20-Poly1305 (newer, no hardware acceleration needed, used in TLS 1.3). For a browser-based tool, AES-GCM is the practical choice for the same reason.
The combination gives you both confidentiality (no one can read the plaintext without the password) and integrity (no one can modify the ciphertext without the recipient detecting it). Without the integrity check, an attacker can flip bits in the ciphertext and observe the resulting change in the plaintext, which is enough to break many encryption schemes.
PBKDF2: turning a password into a key
PBKDF2 (Password-Based Key Derivation Function 2) is the standard for password-based key derivation. It takes a password and a salt, and applies a pseudorandom function (usually HMAC-SHA256) many times in a row, producing a key of the desired length. The "many times" is the iteration count, and it is the main defense against brute-force attacks on the password.
The math: a password "password" might have 30 bits of entropy. A 256-bit key has 256 bits of entropy. PBKDF2 with 250,000 iterations increases the cost of testing one password by 250,000, so the attacker can test 250,000 times fewer passwords per second. The modern recommendation is 600,000 iterations for PBKDF2-SHA256, or 250,000 for systems with the older guidance. Either is a significant slowdown for an attacker.
The salt is a random value that is unique per password (or per file, or per message). The salt prevents an attacker from precomputing a rainbow table — a table of password → key mappings that would let them recover the key for any common password instantly. The salt is stored alongside the ciphertext; it is not a secret.
AES-GCM: the encryption step
AES-GCM is the modern standard for symmetric encryption. It takes a 256-bit key (in AES-256) and a 96-bit IV (initialization vector, sometimes called a nonce), and produces a ciphertext plus a 128-bit authentication tag. The tag is what gives the integrity check: any modification to the ciphertext produces a different tag, and the recipient detects the mismatch.
The IV is a random value that is unique per encryption operation. The IV is stored alongside the ciphertext; it is not a secret. The constraint is uniqueness: reusing an IV with the same key leaks information about the plaintexts and breaks the authentication. For practical use, the IV is generated by a CSPRNG for every encryption operation.
The wire format: what to store in the file
For a real implementation, the wire format matters. You need to store the salt, the IV, the ciphertext, and the authentication tag, in a way that can be parsed unambiguously. A common pattern:
v1:base64(salt[16] || iv[12] || ciphertext_with_tag)
This is the format used by the AES Encrypt / Decrypt tool on this site. The "v1" prefix lets the format evolve — if a future version uses a different KDF, a different iteration count, or a different cipher, the new format can be "v2:" and the parser can dispatch on the prefix. Existing v1 messages still decrypt correctly because the parameters are fixed in the v1 specification.
The salt, IV, and ciphertext+tag are concatenated in binary, then base64-encoded for safe text transport. The result is a single string that can be pasted into an email, a chat message, or a file. The string is the entire encrypted message; nothing else needs to be sent.
The four common foot-guns
1. Weak passwords
AES-256 with 250,000 PBKDF2 iterations cannot protect a password that is in a dictionary. An attacker with a GPU can test billions of password guesses per second, even with the iteration count. The defense is a strong password, ideally a random one of 16+ characters. The Password Strength Checker gives an entropy and time-to-crack estimate; aim for at least 80 bits of entropy (a strong password, not a memorable word).
2. Reusing the IV
Every encryption must use a fresh IV. Reusing an IV with the same key leaks information about the plaintexts. The fix: generate the IV with a CSPRNG for every operation. The encryptor on this site does this automatically.
3. Using ECB mode
AES-ECB (Electronic Codebook) encrypts each block of the plaintext independently with the same key. The result is that identical plaintext blocks produce identical ciphertext blocks, which leaks structure (e.g. a bitmap image in ECB mode retains its visual pattern in the ciphertext). AES-GCM does not have this problem; the IV randomizes every block. The default for any modern encryptor is a non-ECB mode; if you see ECB in a tool, do not use it.
4. No integrity check
Older encryption modes (CBC without a MAC) do not provide integrity. An attacker can flip bits in the ciphertext and observe the result. AES-GCM provides integrity by default; CBC requires an additional MAC (HMAC) to be safe. Use AES-GCM (or AES-CCM, or ChaCha20-Poly1305) and the integrity check is included.
How to use the AES Encrypt tool
- Open the AES Encrypt / Decrypt tool.
- Type or paste the plaintext in the input field.
- Type a strong password (16+ characters, ideally generated by the Password Generator).
- Click encrypt. The result is the wire-format string, ready to copy.
- Send the result to the recipient through any channel (email, chat, file).
- Send the password through a different channel (in person, phone call, separate messenger). Never send both the ciphertext and the password through the same channel.
To decrypt: paste the wire-format string, type the password, click decrypt. The plaintext appears if the password is correct; an error appears if it is not.
The whole encryption runs in the browser. The plaintext is in your input field, the password is in a separate field, the encryption happens in JavaScript, and the result is rendered locally. Nothing is sent to a remote service, nothing is logged, and the plaintext does not need to leave your device.
How to share the password safely
The standard answer for sharing a password is "in person" or "over the phone" — a separate channel from the one carrying the ciphertext. The reason is that an attacker who intercepts one channel is unlikely to also intercept the other. For most use cases:
- Ciphertext by email, password by phone call.
- Ciphertext by chat message, password by text message.
- Ciphertext in a file share, password in a separate password manager entry shared with the recipient.
What you want to avoid: ciphertext and password in the same email, the same chat thread, the same file, or the same database record. The whole point of separating the channels is that an attacker who gets one does not get the other.
When to use this and when not to
Password-based encryption in the browser is right for:
- One-off messages to a known recipient. "Here is the contract, the password is our usual one."
- Files you want to back up encrypted. Encrypt the file with a strong password, store the ciphertext, remember the password.
- Personal notes you do not want synced plaintext to the cloud. Encrypt before sync, decrypt after sync.
It is not right for:
- High-value secrets that need to survive the password being lost. There is no recovery mechanism; the password is the only way to decrypt. Use a password manager, a hardware key, or a service with a recovery flow.
- Real-time messaging. The encrypt/decrypt cycle is one-shot; live chat uses double-ratchet protocols (Signal, etc.) that handle the key exchange automatically.
- Multi-recipient messages. Each recipient needs the password, which means the password has to be shared through a separate channel to each. For group messages, asymmetric encryption (PGP, age) is the right tool.
A short pre-encryption checklist
- Use a strong password (16+ characters, generated by the Password Generator or composed of 4-5 random words).
- Use a tool that uses AES-GCM (or ChaCha20-Poly1305) with a fresh IV per encryption. The AES tool on this site does this.
- Send the ciphertext and the password through separate channels.
- Include a version prefix in the wire format so the format can evolve without breaking old messages.
- For files, consider compressing before encrypting — the compression ratio is usually higher on plaintext than on the already-structured ciphertext.
The right tool, with a strong password, gives you confidentiality and integrity in a single string. The wrong tool, with a weak password, gives you the illusion of security without the substance. The check takes a minute; the consequences of skipping it can last for years.