Encrypt and Decrypt Files Safely with openssl enc
You will encrypt a file with AES-256-CBC, PBKDF2 and a randomly generated salt, then decrypt it and verify that the restored file is identical. Allow about 10 minutes. You need OpenSSL and read/write access to a test directory. No root privileges are required.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you start
This guide targets the OpenSSL 3.6.1 command installed on this machine. The local openssl-enc(1ssl) manpage is dated for OpenSSL 3.0.13, so the command's live help may show newer options. Check the version and the cipher names available in your own installation:
$ openssl version
OpenSSL 3.6.1 27 Jan 2026
$ openssl enc -list | grep -E 'aes-256-cbc|aes-256-ctr'
The exact version line and cipher list can differ. If a cipher is absent, do not substitute a guessed name. Pick one that -list reports.
1. Prepare a disposable test file
Work in a directory that does not contain the original you care about. The commands below create a small plaintext file and reserve separate names for the encrypted and restored copies.
$ mkdir -p ~/openssl-enc-check
$ cd ~/openssl-enc-check
$ printf '%s\n' 'Private test message' > message.txt
$ umask 077
$ ls -l message.txt
Checkpoint: message.txt should exist, and its contents should be exactly the test message. The umask affects files created from this point in the shell; it does not repair permissions on files that already exist.
2. Encrypt with AES and PBKDF2
Use a password prompt so the passphrase does not appear in shell history or the process list. -pbkdf2 makes password-based key derivation explicit. The default PBKDF2 iteration count is 10,000 in this command; -iter can raise it when you accept the extra time.
$ openssl enc -aes-256-cbc -pbkdf2 \
-in message.txt -out message.enc
enter AES-256-CBC encryption password:
Verifying - enter AES-256-CBC encryption password:
Use a long, unique passphrase. Do not use -pass pass:... for a real secret: it exposes the value to your shell history and can expose it to process inspection. If an existing password file is necessary for automation, protect it with restrictive permissions and use -pass file:/path/to/passphrase.
Checkpoint: confirm that the output is binary and begins with OpenSSL's salted header:
$ file message.enc
$ xxd -l 16 message.enc
00000000: 5361 6c74 6564 5f5f ................ Salted__.......
The salt is stored with the ciphertext so the same password can derive the same key during decryption. It is not a secret. Do not use -nosalt except for an old compatibility requirement or a test. Without a salt, repeated passwords produce repeated keys and make dictionary attacks easier.
3. Decrypt into a new file
Keep the original plaintext until the restored copy has been checked. The -d option selects decryption; the cipher and -pbkdf2 settings must match the encryption command.
$ openssl enc -d -aes-256-cbc -pbkdf2 \
-in message.enc -out restored.txt
enter AES-256-CBC decryption password:
A wrong password can produce an error such as bad decrypt, or it can leave partial output. Treat any output from a failed decryption as untrusted and remove it before retrying. This example changes local files, so recovery is simply to delete the generated copies, not the original:
$ cmp --silent message.txt restored.txt && echo 'round trip verified'
round trip verified
$ rm -- restored.txt message.enc
The final command is destructive for those generated files. Run it only after you have finished checking them. If you need to keep the encrypted file, omit that command.
4. Use Base64 only when transport needs text
Encryption produces binary data. Add -a when a text-only transport requires Base64, such as a system that cannot safely carry arbitrary bytes. Base64 is encoding, not extra encryption.
$ openssl enc -aes-256-cbc -pbkdf2 -a \
-in message.txt -out message.enc.b64
enter AES-256-CBC encryption password:
Verifying - enter AES-256-CBC encryption password:
$ openssl enc -d -aes-256-cbc -pbkdf2 -a \
-in message.enc.b64 -out restored.txt
enter AES-256-CBC decryption password:
$ cmp --silent message.txt restored.txt && echo 'Base64 round trip verified'
Base64 round trip verified
Do not add -A casually. It requests one-line Base64 processing, and the manpage records a bug with large files. The normal wrapped output is safer for general files.
5. Know the security boundary
openssl enc does not provide authenticated encryption. It cannot use AEAD modes such as GCM or CCM, and its padding check is only a weak password or corruption signal, not an integrity guarantee. Someone who can alter the ciphertext may do so without a reliable tamper alarm. For bulk data where integrity and key management matter, use a format and tool designed for that purpose, such as openssl cms, rather than inventing a protocol around enc.
Avoid manually supplying -K, -iv or -S unless you are interoperating with a defined format. They take hexadecimal values, and OpenSSL 3 changed the handling of an explicit -S value: it is not prepended to the ciphertext and must be supplied again during decryption. Random salt with a prompted password is the less error-prone path.
Common failure checks
- "Unknown cipher": run
openssl enc -listand use an installed name. - "bad decrypt": check the password, cipher, PBKDF2 setting and whether the input was Base64 encoded.
- Empty or partial output: do not use it. Decrypt into a temporary name, verify it with
cmp, then rename it only after success. - Automation leaks a password: replace command-line
-pass pass:...with a protected file, an appropriate secret source, or an interactive prompt.
Done means
- The installed version and cipher list were checked.
- Encryption used AES, PBKDF2 and the default random salt.
- Decryption used matching options and a separate output name.
cmpverified that the restored bytes match the original.- You know that
encis not an authenticated-encryption or tamper-detection format.