You have a collection of files that you want to sign with GPG. Should you sign each file individually, sign a file containing a list of SHA-256 hashes, or do something different altogether? Which method you choose has important consequences for security.
Problem 1: File name integrity
Signing files one at a time signs the contents of the files. It (typically)
does not protect the file names from tampering. This could be disastrous in
some situations (e.g. an attacker could change blacklist.txt
to
whitelist.txt
).
Problem 2: Set membership integrity
Signing individual files does not prevent adding or removing files from the set of files that were transmitted. In some cases, this is important: if you’re transmitting a set of log files, an attacker could selectively remove one that captured incriminating information, without that change being detected. If an attacker has the opportunity to see multiple transmissions, they could add files from an old transmission to the new transmission (essentially a variant on replay attacks). The files would still have valid signatures individually, so the additions would not be detected. If you’re transmitting a set of user accounts (one per file), an attacker could revert their account to an earlier state (e.g. back to having admin status).
What should you do?
Given the above, I recommend protecting the transmission as a whole instead of part-by-part. There are too many things that can go wrong when each file is signed individually. The easiest way of getting everything right is to create a tarball or zip file of the files and sign the entire archive:
The above commands will create a GPG signature file myfiles.zip.gpg
that can
be used to verify that myfiles.zip
has not been tampered with. When
receiving the zip file, just verify the signature before unzipping:
An alternative
This may not be possible or practical if, for example, zipping the files would
be too resource-intensive. In that case, it is still possible to avoid most of
the above problems. Do not sign the files individually. Instead, produce a
SHA256SUMS
file containing a list of file names and corresponding hashes, and
sign that file. The sha256sum
command on Linux makes this easy:
When it’s time to check the signature:
Make sure that you use sha256sum
and not the older sha1sum
or md5sum
, as
those hash functions are no longer safe to use.
There’s one catch with this method: sha256sum
won’t notice if there are other
files in the current directory that are not listed in the SHA256SUMS
file.
If an attacker adds a malicious file to the files you received, sha256sum
won’t detect that anything is wrong, since it only checks the files whose
hashes are listed. Consider whether this problem actually affects the security
of your application: you may need to add additional security checks. This is
why I generally recommend working with signed zip files instead.