Signify and Minisign are not the same thing

Published on

As I read about cryptographic tools, such as GnuPG and age, there was one that people recommended for signing files, or rather, a couple of them: signify and minisign.

Now, I’m not a strong user of these tools, as I don’t regularly release software or any other sort of files that must be verified for potential tampering, but I was still curious about this use case, and most of the recommendations I’ve read treated both tools as somewhat interchangeable: “just use signify or minisign, whatever you want”. They are nigh identical tools, based around the same principle and with similar user interfaces, but as it turns out, they’re not compatible with each other.

This write-up serves as a possible source of clarification for any confused user searching why they can’t sign files with keys made in the other program. I know I was one of them.

Keep in mind that I am using Debian Testing, so the packages might be different from the releases you’re using. In fact, all mentions of the signify command refer to signify-openbsd due to a name clash with an email signature generator.

Generation

Before signing your files, you need to create a key pair; the secret key creates the signature, and the public key verifies said signature. Skimming the man pages, we can see how the key creation commands are not the same:

signify  -G [-n] [-c comment] -p pubkey -s seckey

minisign -G [-p pubkey_file] [-s seckey_file] [-W]

Signify’s -c option defines a comment for your key (the “untrusted comment” line) at generation-time, while minisign does this at signature-time. The -n and -W flags do the same: avoid using a password to encrypt the key file.

Notice how -p and -s are optional in minisign. Unlike signify, which needs specific paths to store the key pair, minisign stores the secret key by default on ~/.minisign/minisign.key. The public key is stored as minisign.pub in the current directory.

Signature

signify  -S [-enz] [-x sigfile] -s seckey -m message

minisign -S [-H] [-x sig_file] [-s seckey_file] [-c untrusted_comment]
            [-t trusted_comment] -m file [file ...]

Here we can see how minisign not only lets you assign an untrusted comment when signing a file with -c, but it also lets you assign a custom trusted comment with t, which no one can modify without invalidating the signature. Conversely, while missing signature-time comments, signify is able to embed the message in the signature file it creates by using the -e flag, as well as embed the signature in the header of a gzip file with the -z flag. I have no idea what -H (“Requires the input to be prehashed”) does, and apparently it will be removed in the future anyway.

Let’s do a test:

mkdir -p signikeys && signify  -G -p signikeys/key.pub -s signikeys/key.sec -n
mkdir -p minikeys  && minisign -G -p minikeys/key.pub  -s minikeys/key.sec  -W
echo 'This is a test' > test.txt
signify  -S -s signikeys/key.sec -m test.txt -x test.txt.signify
minisign -S -s minikeys/key.sec  -m test.txt -x test.txt.minisign

There’s no output from the signature operation, so everything’s normal. Now let’s sign with the opposite keys:

signify -S -s minikeys/key.sec -m test.txt -x test.txt.signify-minikeys
# signify-openbsd: unable to parse minikeys/key.sec
minisign -S -s signikeys/key.sec -m test.txt -x test.txt.minisign-signikeys
# base64 conversion failed - was an actual secret key given?

Each program can’t read the other’s keys. If you look at the secret keys, you can see the minisign one is slightly longer. They’re fundamentally not the same, and this is true even if we use a password for either of them or both.

$ cat signikeys/key.sec
untrusted comment: signify secret key
RWRCSwAAAABSXFgEHTEe8MaWRd2VhnhaiNX7SEKnRX1HpKzOd/7Rr2AGt6Ti+scwJECiC3Zo+Vp/mMmhpHMTbBT+qt6F1cUvmEJD5/DVgS1rOr3sM1J4I+zsdXN7tja2c4CT68uyvvg=
$ cat minikeys/key.sec 
untrusted comment: minisign encrypted secret key
RWQAAEIyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7WDMerTVfXdRVEOpd6Ejq95Jp8DBvH0La1KvAMoS8p/qOP3ujDeXNp42ES4vNFHgvey9vEkdTMfio9GOlS3h5b6o8HkU+rwbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

It goes without saying that you should not use these keys, ever. They are not secret anymore.

Verification

signify  -V [-eqz] [-p pubkey] [-t keytype] [-x sigfile] -m message

minisign -V [-x sig_file] [-p pubkey_file | -P pubkey] [-o] [-q] -m file

The verification stage is straightforward and pretty much the same in both programs: -V sets the verify mode, -x is the signature file generated in the previous step, -p is the public key file, and -m is the message, i.e. the file whose integrity we’re checking. We have a -q flag for suppressing output, as well.

As for signify-exclusive options, we have -e to verify signatures with an embeded message (as in signify -e -x signature_with_embed -p key.pub -m new_file, which will create new_file with the contents of the original file.), -z as the same thing for signed gzip files, -t for deducing a key type or something (don’t ask me what this does, it matches a key on /etc/signify/*-keytype.pub, and I don’t have that directory since I use the Debian version). For minisign, -o prints the message file to the standard output, and -P allows you to use the base64 string representation of a key instead of a file, as in minisign -V -P RWRHpKzOd/7Rr5hCQ+fw1YEtazq97DNSeCPs7HVze7Y2tnOAk+vLsr74 -m test.txt -x test.txt.minisign.

Well, we may not be able to sign files with keys generated by another program, but what about verification?

$ signify-openbsd -V -x test.txt.signify -p signikeys/key.pub -m test.txt
Signature Verified
$ minisign -V -x test.txt.minisign -p minikeys/key.pub -m test.txt
Signature and comment signature verified
Trusted comment: timestamp:1699600567	file:test.txt	hashed
$ signify-openbsd -V -x test.txt.minisign -p minikeys/key.pub -m test.txt
signify-openbsd: unsupported file test.txt.minisign
$ minisign -V -x test.txt.signify -p signikeys/key.pub -m test.txt
Trusted comment not present

So, not only the secret key structure is different, but also the signatures they generate:

$ cat test.txt.signify
untrusted comment: verify with key.pub
RWRHpKzOd/7Rryg60iRfonpDvuFq40qPJn9XiEsuHh2kWmXwyZNJ+/YhB/7KgFuLN6pXdsXBJj+7AJA1kkWkwOPJG8fN821ZJAs=
$ cat test.txt.minisign
untrusted comment: signature from minisign secret key
RUTtYMx6tNV9dwXgHep+70+uZy4mDwEMmdNwapL4/Nlpt3i8gwI1VG++3fjm/ImPAOxBft7FCGyWoD7nOJvcHJYZJx3nZwCcPw8=
trusted comment: timestamp:1699600567	file:test.txt	hashed
3/rMchyZllQfWMx0OU8MSfxSCBYXydlhG9ZlBrRIJhfRsAMkrazWjJDDdO7AtKx6q++y5R1w2FxJuhOj9P7hAQ==

As hinted at in the signature section, we have a trusted comment on the minisign signature, a comment that no one can tamper with as it would invalidate the signature. Meanwhile, the signify signature only has an untrusted comment, which can be modified freely. In other words, they generate files with a different structure, even if they look similar to each other.

Miscellaneous

Signify can verify a list of SHA-256 checksums and automatically check the integrity of each file on the list with the -C option. However, you must use the BSD version of sha256 to generate the checksum or use GNU’s sha256sum with the --tag option.

Minisign uses the -C option to change the password for a secret key, as well as to remove it with the -W flag. It also has a -R option, which recreates the public key in case you only have the secret key, for example, if you have it in the ~/.minisign directory and don’t remember where you stored the public key.

Which one should I use?

Hard to say. They solve the same problem in almost the same way, but implementation differences make them unable to serve as drop-in replacements for each other.

Use signify if…

  • …you use OpenBSD.
  • …your distro uses signify.
  • …you want to create files with an embedded signature.

Use minisign if…

  • …you want to use trusted comments.
  • …you use Windows or WebAssembly.
  • …you prefer to leverage your crypto to libsodium.
  • …you want to compile using zig.

Use either if…

  • …you want to verify files signed with one or another.

Use none if…

  • …you still believe PGP is the way to go.
  • …you don’t know what this whole “digital signature” mumbo jumbo is all about.

To be fair, me neither. I don’t know a thing about crypto, so don’t take my opinions too seriously.