Hash Data and Passwords with OpenSSL

OpenSSL’s dgst command hashes files and streams with any digest the build supports (SHA-256 by default), and the same binary also covers keyed HMACs and Unix-style password hashes — a complete hashing toolkit on nearly every Unix system.

Hash a file or stream

openssl dgst -sha256 $FILE
printf %s 'hello world' | openssl dgst -sha256
# SHA2-256(stdin)= b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9

With no file argument, stdin is hashed. The default digest is SHA-256, so openssl dgst alone works, and every digest name doubles as a sub-command: openssl sha512 $FILE.

Choose the digest

openssl list -digest-algorithms   # what this build supports
openssl dgst -sha512 $FILE
openssl dgst -sha3-256 $FILE

New work should use SHA-256 or better. MD5 and SHA-1 survive only for interoperability with legacy formats — both are collision-broken and unfit for signatures or anything adversarial. The OpenSSL docs say the same: “New or agile applications should probably use SHA-256.”

coreutils-compatible output

-r prints hash *file lines in the sha256sum/sha1sum format:

openssl dgst -sha256 -r $FILE
# b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 *file

HMAC

A plain digest proves nothing about origin — anyone can recompute it. HMAC folds a secret key into the hash, which is what authenticates the message:

openssl dgst -sha256 -hmac 'secret' $FILE
openssl dgst -sha256 -mac HMAC -macopt hexkey:736563726574 $FILE

-hmac takes the key as a printable string; -mac HMAC -macopt hexkey: takes key bytes in hex, for keys with non-printable bytes. The OpenSSL docs prefer the separate openssl mac command over these flags for new use.

Password hashes

openssl passwd produces Unix crypt-style hashes — $1$ (MD5), $5$ (SHA-256), $6$ (SHA-512), plus $apr1$ for Apache:

openssl passwd -6 -salt NaCl 'password'
# $6$NaCl$wgUT.rFtuFRzXtzjaakQ6lE.TCT0Xxym5UHcUwqQ5Bn9ZZpLjv0cFjJO1wZkQ6aY.TmOUuozSJ0cmnWQ.k16U1

-6 selects SHA-512-crypt (Ulrich Drepper’s scheme). Supplying -salt makes output reproducible — useful for test vectors; omit it for real hashes so a random salt is used. See unix-password-hash-formats for the format family and hashcat for how fast these fall to offline guessing.

Common pitfalls

  • echo changes the hash. echo 'hello world' | openssl dgst hashes hello world plus a newline. Use printf %s when you mean the bare string.
  • A digest is not authentication. Only the HMAC forms above bind the hash to a secret; a bare sha256 is forgeable by anyone.
  • Password hashes are a compatibility format. crypt-style hashes exist for /etc/shadow-style verification, not as modern password-storage advice.

Sources