OpenSSL Cheatsheet

Random and Passwords

Use this OpenSSL reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Generate random bytes

rand takes a byte count and writes to stdout. The count is bytes, never characters, which matters the moment you add an encoding.

openssl rand -hex 32          # 64 hex chars, 256 bits
openssl rand -base64 32       # 44 base64 chars, 256 bits
openssl rand -base64 24       # 32 base64 chars, no = padding
openssl rand 32 > key.bin     # raw binary
openssl rand -out key.bin 32  # same, explicit
Bytes-hex chars-base64 charsTypical use
163224Session id, IV, salt
244832API key, no padding
326444Secret key, JWT signing secret
489664Long-lived credential
6412888HMAC-SHA512 key

Base64 output length is 4 × ceil(n/3). Multiples of 3 bytes give no = padding, which is why 24 and 48 look tidier than 32.

Size suffixes work for large amounts:

openssl rand 1K > 1kb.bin
openssl rand 10M > 10mb.bin

Passwords people will type

Base64 contains + and /, which break shell quoting, URLs, and connection strings. Filter them out when the value gets pasted somewhere.

# URL and shell safe, 32 chars
openssl rand -base64 48 | tr -d '+/=' | cut -c1-32

# hex only, unambiguous over the phone
openssl rand -hex 16

# alphanumeric, exactly 20 chars
LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 20; echo

tr -d after generating shortens the string, so generate extra. Asking for 48 bytes and trimming to 32 characters keeps well over 128 bits of entropy even in the worst case.

A few one-liners worth keeping:

openssl rand -base64 32                       # generic app secret
openssl rand -hex 32                          # JWT / cookie signing key
openssl rand -base64 24 | tr -d '+/='         # DB password
openssl rand -hex 16                          # request id, correlation id
openssl rand -base64 32 | tr -d '\n'          # strip trailing newline

Password hashes for config files

passwd produces crypt-format hashes for /etc/shadow, Apache htpasswd, and similar files. This is not for application passwords.

openssl passwd -6 'plaintext'      # SHA-512 crypt, $6$
openssl passwd -5 'plaintext'      # SHA-256 crypt, $5$
openssl passwd -apr1 'plaintext'   # Apache MD5, $apr1$
openssl passwd -1 'plaintext'      # MD5 crypt, $1$
openssl passwd -6 -stdin           # read from stdin, keeps it out of history
$ openssl passwd -6 'hunter2'
$6$C0oOWA6yqvNz3Jke$RVeLbCPfoiYPPxfHqEZfmz0S...
FlagSchemeVerdict
-6SHA-512 cryptUse this if you must pick one here
-5SHA-256 cryptAcceptable
-apr1Apache MD5Only for Apache basic auth
-1MD5 cryptLegacy, weak
-aixmd5AIX MD5 cryptAIX interop only

OpenSSL has no bcrypt and no Argon2 in passwd, and -crypt (classic DES crypt) was removed in 3.0. For application passwords use your language's Argon2id or bcrypt binding, or mkpasswd / htpasswd -B.

Key derivation from a password

When you need a key from a password rather than a random one, kdf is the right subcommand. Length is in bytes.

# PBKDF2, 600k iterations, 32-byte key
openssl kdf -keylen 32 -kdfopt digest:SHA256 \
  -kdfopt pass:mypassword -kdfopt hexsalt:0011223344556677 \
  -kdfopt iter:600000 PBKDF2

# scrypt, memory hard, better against GPUs
openssl kdf -keylen 32 -kdfopt pass:mypassword \
  -kdfopt hexsalt:0011223344556677 \
  -kdfopt n:32768 -kdfopt r:8 -kdfopt p:1 SCRYPT

# HKDF, for expanding an existing high-entropy secret
openssl kdf -keylen 32 -kdfopt digest:SHA256 \
  -kdfopt hexkey:00112233 -kdfopt hexsalt:aabb \
  -kdfopt info:app-v1 HKDF

The KDF name goes last, after every -kdfopt. Output is colon separated uppercase hex, so strip the colons for anything downstream:

openssl kdf -keylen 32 -kdfopt digest:SHA256 -kdfopt pass:pw \
  -kdfopt hexsalt:00112233 -kdfopt iter:600000 PBKDF2 | tr -d ':\n'

Entropy and where randomness comes from

OpenSSL 3.x seeds from the operating system CSPRNG (getrandom on Linux, getentropy on BSD and macOS, BCryptGenRandom on Windows) and reseeds automatically.

openssl rand -hex 32                  # already cryptographically secure
cat /dev/urandom | head -c 32 | xxd   # same source, no OpenSSL needed

- ~/.rnd and -rand are historical. Modern builds do not need a seed file, and RANDFILE in openssl.cnf is ignored. - unable to write 'random state' is harmless on 1.x builds without a writable home directory. It does not mean the output was weak. - Inside a container or a freshly booted VM, the kernel CSPRNG may block briefly before it is seeded. getrandom waits rather than returning weak bytes, which is the correct behaviour.

Gotchas

- -hex and -base64 do not change the entropy, only the encoding. rand -hex 16 and rand -base64 16 are both 128 bits. - rand -base64 N output can contain +, /, and =. Unescaped in a YAML value, a URL, or a Postgres connection string, any of them break something. - openssl rand writes a trailing newline for -hex and -base64. Pipe through tr -d '\n' before putting it in a file that must not have one. - openssl passwd 'secret' puts the password in your shell history. Use -stdin and pipe it in. - openssl passwd with no algorithm flag defaults to the weakest scheme the build still offers. Always pass -6 explicitly. - Never use $RANDOM, date +%s, or a language's default Math.random for anything a user must not guess. They are not cryptographic.