Create and verify signed checksums for directory trees
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Create and verify GPG-signed SHA256 checksums for all files in a
directory tree.


The general purpose of creating checksums for files and comparing
them over time is to determine whether files have changed. Either
accidentally or maliciously.

Several intrusion detection systems already exist that serve this
purpose, among other things. So why this script?

* I don't want to bother with the complexities of an 
  enterprise-grade IDS.

* I don't want a central database of checksums.
  Instead, I want one checksum file (.checksums) per directory,
  in order to be able to easily copy directories around and still
  be able to verify their checksums.

* Incremental creation/update of checksums.
  Assuming that I/you trust data integrity on the system where
  the checksums are generated.


- ruby >= 2.0
- gpgme ruby bindings version 2.0.0 (or possibly newer)
 - either the gpgme gem
 - or the Debian package ruby-gpgme


Create checksums for one or more directories

$ checksums create directory1 directory2 ...

Verify checksums

$ checksums verify directory1 directory2 ...

Update checksums (see considerations below)

$ checksums verify directory1 directory2 ...

When signing checksum files, checksums by default uses the first
suitable key from your GPG keyring. Such a key must have a private
key useable for signing.

When verifying checksum files, by default all such keys are considered

The --signer option allows to explicity specify a key to be used
for signing and verifying. The key can be given in any form that is
acceptable to GPG, such as key ID or fingerprint.

$ checksums create --signer 0123456789ABCDEF

To create checksums for directories and all their sub-directories,
add the --recursive option.

Directories can be excluded from consideration using the --exclude
option. This option can be given multiple times.

  $ checksums create --recursive --exclude=michael /home

Creates checksums for directories in and under /home, excluding
everything below /home/michael.

  $ checksums create --recursive --exclude='**/.git' /usr/local/src
Creates checksums for directories in and under /usr/local/src,
excluding .git directories.
  $ checksums create --recursive --exclude='**/.*' .

Creates checksums for the current directory and below, excluding
any "hidden" directories whose name starts with ".".


When updating checksums, new checksums are only calculated for those
directories where at least one file has a modification timestamp newer
than that of the checksums file for that directory.

Therefore, if you don't trust the timestamps on your computer, don't
update checksums, but always create them afresh.

Furthermore, timestamps are only accurate to one second.
Assume a checksums file for a directory is written and in the same
second a file in that directory changes, is added or removed.
An update will not notice this change and so will not write a new
checksums file.

If files are changing so rapidly that the contents of a directory
change while the checksums for that same directory are calculated, it
is not possible to write a consistent checksums file at all.
In such a case, this tool just might not be appropriate for your needs.


Whose keys are they anyway?

When run as an ordinary user, the script uses that user's keyring.

When run in a root login session, i.e. `su -', not plain `su' or `sudo',
the script tries to use root's keyring. Possibly unsuccessfully, when
there's no gpg-agent running for root.

When run via `sudo -E', the keyring of the user running sudo is used!

When run via `sudo', depending on sudo configuration, this is either
the same as `sudo -E' or it fails when there's no gpg-agent for root.

In order to have sudo pass the GPG_AGENT_INFO environment variable
through to the checksums script, add the following lines to
/etc/sudoers or to a file in /etc/sudoers.d; use `visudo' or
`visudo -f' for editing these files.

Cmnd_Alias CHECKSUMS = /usr/local/bin/checksums # or wherever you install the script

Copyright (C) 2015 Michael Schürig <>