Create and Verify File MACs with OpenSSL mac
You will calculate a message authentication code (MAC) for a file with the installed openssl mac command, save the result safely, and compare it with a later calculation. A MAC detects changes when the verifier has the same secret key; it is not encryption and it is not a substitute for a digital signature when the key must be public. Allow about fifteen minutes. You need OpenSSL and a test file whose bytes you intend to authenticate.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide follows the openssl-mac(1ssl) manual installed with OpenSSL 3.0.13 from the Ubuntu package, and the OpenSSL 3.6.1 binary found first in PATH on the reference machine. Provider support and the available algorithms can differ between builds, so check your own command before putting an algorithm in a script.
1. Check the command and available MACs
Start with read-only checks. They do not require sudo or elevated privileges:
$ command -v openssl
/home/linuxbrew/.linuxbrew/bin/openssl
$ openssl version
OpenSSL 3.6.1 27 Jan 2026
$ openssl list -mac-algorithms
... HMAC ...
... CMAC ...
... KMAC-128, KMAC128 ...
Your paths and list will differ. The command takes the MAC name as its final argument. The manual calls this mac_name. Use a name that appears in your list, such as HMAC, rather than assuming that an algorithm is present because another OpenSSL build provides it.
Checkpoint: run openssl mac -help. The options relevant here are -in, -out, -binary, -digest and repeated -macopt values.
2. Prepare a small input without changing anything important
Use a copy or a disposable test file while learning. A MAC covers the exact bytes, including line endings and a final newline:
$ printf '%s\n' 'example message for MAC testing' > message.txt
$ sha256sum message.txt
e.g. message.txt
The digest output is only an input check; do not treat it as the MAC. If the real input is sensitive, keep it in its existing location and avoid putting its contents into shell history. The examples below use hexadecimal keys so that the key bytes are unambiguous.
3. Calculate an HMAC as hexadecimal text
HMAC is the usual starting point for authenticating a file with a digest. Select the digest explicitly and pass a hexadecimal key with hexkey::
$ openssl mac -digest SHA256 \
-macopt hexkey:00112233445566778899AABBCCDDEEFF \
-in message.txt HMAC
6e0c...replace-with-the-value-printed-by-your-host...
The displayed value is hexadecimal text. Do not copy the illustrative line above as an expected cryptographic answer: the output depends on the exact input bytes and key. A successful command writes the MAC to standard output and exits with status zero.
Capture output only after deciding where it may safely live. This writes a new file, but the key remains visible in the shell command and may be retained by shell history or process observation:
$ openssl mac -digest SHA256 \
-macopt hexkey:00112233445566778899AABBCCDDEEFF \
-in message.txt -out message.mac HMAC
$ test -s message.mac && wc -c < message.mac
64
Without -binary, HMAC-SHA256 produces 64 hexadecimal characters. The exact count is a useful sanity check, not proof that the key or input was correct.
4. Verify by calculating again and comparing
Recalculate into a temporary file and compare the bytes. Use cmp rather than comparing terminal text by eye:
$ tmp_mac=$(mktemp)
$ trap 'rm -f "$tmp_mac"' EXIT
$ openssl mac -digest SHA256 \
-macopt hexkey:00112233445566778899AABBCCDDEEFF \
-in message.txt -out "$tmp_mac" HMAC
$ cmp -s message.mac "$tmp_mac" && echo 'MAC matches'
MAC matches
If cmp reports a difference, check the input path, key, digest, line endings and whether either MAC file was truncated. Do not respond by trying random keys. If the input has changed, that is exactly what the MAC is meant to reveal.
5. Use binary output only when the next tool needs bytes
The -binary option writes the raw MAC instead of hexadecimal text. It is useful for a protocol or binary file, but it is not suitable for displaying in a terminal:
$ openssl mac -digest SHA256 \
-macopt hexkey:00112233445566778899AABBCCDDEEFF \
-in message.txt -out message.mac.bin -binary HMAC
$ wc -c message.mac.bin
32
For HMAC-SHA256, 32 raw bytes correspond to 64 hexadecimal characters. Keep the text and binary forms separate; comparing one with the other will always fail. A binary MAC may contain control bytes, so do not print it with cat.
6. Choose CMAC or KMAC deliberately
CMAC needs a cipher selection. The installed manual documents AES-CBC names for CMAC:
$ openssl mac -cipher AES-128-CBC \
-macopt hexkey:00112233445566778899AABBCCDDEEFF \
-in message.txt CMAC
e.g. hexadecimal CMAC output
KMAC uses a variable output size. Set it explicitly when another system expects a particular length, and remember that size: is measured in bytes:
$ openssl mac -macopt hexkey:00112233445566778899AABBCCDDEEFF \
-macopt custom:deployment-check -macopt size:16 \
-in message.txt KMAC128
e.g. 32 hexadecimal characters
These algorithms are not interchangeable. A verifier must know the MAC name, digest or cipher, key encoding, customisation string and output format. Record those parameters with the consuming protocol, but never record the secret key in a public manifest.
7. Avoid the common traps
By default, -in reads standard input and -out writes standard output. A hyphen passed as the input filename also means standard input. This is convenient for a pipeline, but a producer that emits a warning or changes line endings can change the authenticated bytes. For reproducible checks, name the input file and inspect it before calculating.
The key: form is for printable alphanumeric key text. Use hexkey: when the key is bytes or contains characters that could be altered by shell handling. The manual requires a key for every MAC algorithm. Never use the placeholder key in a real deployment, and avoid putting production keys directly on a shared command line. Use your platform's approved secret-handling method, then pass the resulting value only for the lifetime of the command.
Do not overwrite a trusted MAC file with shell redirection until the new result is known to be complete. If replacement is required, write a temporary file in the same directory, compare or validate it, then rename it deliberately. A failed command can otherwise leave a truncated output that looks like a real result.
Done means
openssl list -mac-algorithmsconfirmed that the chosen MAC is available on this host.- The input bytes, MAC name and parameters are recorded, while the secret key remains protected.
- The output format is intentional: hexadecimal for text workflows or raw bytes for a binary protocol.
- A second calculation with the same parameters matches with
cmp -s. - A changed input or any mismatch stops the workflow for investigation rather than being ignored.