openssl has hundreds of subcommands and you need exactly six — but those six cover hashes, base64, passwords, TLS debugging, cert generation, and file encryption. Here they are.
OpenSSL is two things: a library that half the internet’s TLS runs on, and a command line tool you already have. The CLI is famously cryptic, but a short list of recipes covers almost everything a terminal user actually needs. The classic gotcha: macOS ships LibreSSL as /usr/bin/openssl — for the commands here, install the real thing with brew and it lands at /opt/homebrew/opt/openssl@3 (OpenSSL 3.6.4 at time of writing). Every recipe below was run against that binary; digests, base64, and rand behave the same on LibreSSL, while enc -pbkdf2 and the s_client plumbing below are checked on OpenSSL 3.
install
brew install openssl@3
# then use the full path or alias it:
echo 'alias openssl=/opt/homebrew/opt/openssl@3/bin/openssl' >> ~/.zshrcsudo apt install openssl
sudo dnf install openssl
sudo pacman -S openssl
examples
# SHA-256 digest of a file (same value as `shasum -a 256`)
openssl dgst -sha256 backup.tar.gz
# Base64: encode stdin, then decode it back
echo -n "hello terminal" | openssl base64
echo "aGVsbG8gdGVybWluYWw=" | openssl base64 -d
# A 32-char random password (24 bytes -> 32 base64 chars)
openssl rand -base64 24
# Pure hex randomness, for API keys and nonces
openssl rand -hex 16
# Inspect a live TLS cert: who it's for, who signed it, # whether the chain verified (0 = ok) echo | openssl s_client -connect github.com:443 \ -servername github.com 2>/dev/null | grep -E "subject=|issuer=|Verify"
# Just the dates, via the pipe into openssl x509
echo | openssl s_client -connect github.com:443 -servername github.com \
2>/dev/null | openssl x509 -noout -subject -dates
# One-line self-signed cert for local HTTPS dev: # req -x509 make a certificate, not a signing request # -newkey rsa:2048 -keyout/-out new key + where each file goes # -days 365 validity window # -nodes NO password on the key (NE des = no DES) # -subj skip the interactive question prompt openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \ -days 365 -nodes -subj "/CN=myproject.local"
# Password-encrypt a file (AES-256-CBC + PBKDF2 key stretching); # the "Salted__" header in the output is normal openssl enc -aes-256-cbc -pbkdf2 -in notes.txt -out notes.enc \ -pass pass:correcthorse
# Decrypt: same cipher, same password, -d to reverse
openssl enc -d -aes-256-cbc -pbkdf2 -in notes.enc \
-pass pass:correcthorse
# Keep passwords out of shell history: read from an env var
export NOTE_PW=$(openssl rand -base64 18)
openssl enc -aes-256-cbc -pbkdf2 -in notes.txt -out notes.enc \
-pass env:NOTE_PW
pro tip
Drop -pass entirely and openssl prompts for the password interactively — nothing lands in your history, and the command in your scrollback stays reusable. Combine with -pass env: in scripts for the best of both.
honest limits
enc file encryption is honest but bare: AES-256-CBC has no integrity check at all. The “bad decrypt” error is just a padding check, so a wrong password occasionally “succeeds” and writes garbage, and tampered files aren’t reliably detected. Without -pbkdf2 you get weak legacy key derivation, and AEAD ciphers like AES-GCM, which would add authentication, are rejected outright (“AEAD ciphers not supported”). For files whose secrecy actually matters, use age or your existing tooling; enc earns its keep for quick at-rest scrambling of files on disks you already control. The self-signed cert above also warns in every browser by construction — there’s no CA to vouch for it — which is fine for localhost, useless for the public internet. And none of this is LibreSSL-guaranteed: flag behavior outside the recipes above was not verified on macOS’s /usr/bin/openssl.