Overview of PGP replacements

OpenPGP became a de facto standard for encryption and digital signature, used to secure email and XMPP communications but also by as a dedicated file encryption and signing provider by popular backup tools. Each of these use scenarios suffers from dated OpenPGP design and confusing user interface.

A number of notable projects were developed with the intent to replace OpenPGP, some with ambitions to replace the whole cryptosystem, others with a very limited scope following the "do one thing well" philosophy.

opmsg

opmsg is written in C++ and with very few dependencies (OpenSSL). The core features are data encryption/decryption and digital signature/verification. opmsg is not merely a simple file encryption tool — it implements a whole cryptosystem including key exchange, separate identities (including ones derived from a passphrase for deniability) and a DH key exchange (yes, in static messages) which enables Forward Secrecy. Additional tools from the same author offer integration with popular email clients and BTC ledger as web of trust, QR codes and P2P message exchange.

Out of all discussed tools, opmsg is the most advanced project with ambitions to replace the whole OpenPGP cryptosystem. Unfortunately, this also brings back the GnuPG usability nightmares and makes it complicated for casual usage. While it seems to be production-ready from technical point of view, many of the extra features seem to be more of a proof-of-concept rather than parts of a consistent architecture.

opmsg signed or encrypted messages are ASCII, PEM-encoded files, just with more sections than classic PGP blob. Unfortunately, the tool cannot serialize messages into a binary format which would minimize ASCII overhead.

$ cat ~/.opmsg/config
version=3
idformat=short
calgo=aes256gcm

List my own private keys (personas):

$ opmsg --list

opmsg: version=1.79 (C) 2019 Sebastian Krahmer: https://github.com/stealth/opmsg

opmsg: persona list:
opmsg: Successfully loaded 1 personas.
opmsg: id | type | has privkey | #(EC)DHkeys | name
opmsg: 82ec11407846fa43 ec      1 6
opmsg: SUCCESS.

Encrypt a sample test to self:

$ echo "test message" | opmsg --encrypt 82ec11407846fa43 -P 82ec11407846fa43

opmsg: version=1.79 (C) 2019 Sebastian Krahmer: https://github.com/stealth/opmsg

opmsg: encrypting for persona 82ec11407846fa43
-----BEGIN OPMSG-----
version=3
-----BEGIN SIGNATURE-----
MFUCKQCndOcMpphWjd510iglaV7Ay8mhL9sw6vyqh1gvcLwL2d71L5yMTRzxAih03tGp81K9moBziMir
mM0GZuK3Saj62vHjIWCcAx14Bp4ssNXDimSK
-----END SIGNATURE-----
rythmz=sha256:sha256:sha256:aes256gcm:0Z1Hw+hstp3b3zBGRuG5RzGE9GNMn9Py
cfg-num=3:1:
gcm-aad-tag=0DNzeI5I6gEVNyAhHyTv0A==
src-id=82ec11407846fa437526e9433c34c2c1913d64141ffd6aa0f2c350531eeaac9d
dst-id=82ec11407846fa437526e9433c34c2c1913d64141ffd6aa0f2c350531eeaac9d
kex-id=28093140121cbe0bb41654bfd4d4fcaabd970206a41ae255f5bc422b6d7897c0
-----BEGIN PUBLIC KEY-----
MGowFAYHKoZIzj0CAQYJKyQDAwIIAQEJA1IABK9Qfqdu1Vvz3DGngpfYuv+KDlrv
x2eT4/vdHFSx6v5iKdFrYQS95iRxm/ysef5bGXP+SQd9ZGr8OXRqosmPtEOVpInZ
78cJKlEz39dRwoU2
-----END PUBLIC KEY-----

-----BEGIN PUBLIC KEY-----
MGowFAYHKoZIzj0CAQYJKyQDAwIIAQEJA1IABKsKkQ2+sFvOx4QxZcEYjd8OFLOX
r06UbyWOj8kpJQ2bp3Gdqi7vjAujfzXBRWleQMrmlKAX7GzKH0dwDwFJuczHzF9r
jpVGkg/SqOv5K50t
-----END PUBLIC KEY-----

-----BEGIN PUBLIC KEY-----
MGowFAYHKoZIzj0CAQYJKyQDAwIIAQEJA1IABHoh60w5W4HEwQcvjcj8ZbycaD36
fkZXikKf0U76IQuEi/YYE93ewgVoOWX1T0ny1CwlJ2RVAzyCxt2m9tDPWAO56tdH
8K/FtCKwGzTSvYmu
-----END PUBLIC KEY-----

-----BEGIN KEX-----
AmVgctFl/Lezf4VOBQGnVYOXQou/1jqCqwSoPY8Z0P6xSdku/0R77lE=
-----END KEX-----

-----BEGIN OPMSG DATA-----
HkF8eQI4IQiW62qc7w==

-----END OPMSG-----
opmsg: SUCCESS.

age

age implements file encryption and decryption, has very clear user interface for key generation and actual file operations, and supports binary data. age does one job and does it well and seems to be a perfect tool for casual usage and backup encryption.

age encrypted messages have integrity protection but the tool does not offer a standalone digital signature.

Age key generation:

$ ./age-keygen
# created: 2020-06-11T16:21:51+01:00
# public key: age1t8vpx5psvng2dd5tswyp945wnazdhcd0um6ann9g52veze0h5p0scutu6u
AGE-SECRET-KEY-1PH0X325GFGT6JEZAUF3D9CFSUUSUP7S92M0C96Z8563AR2L599DQZV4P0F

Age encryption (to myself, just using the public key above):

$ echo "test message" | age --armor -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHaWhURDYrSGxaS1kzSXhl
MHZlNG8yMnR3ZWZLeUJ6UzBnNjhKL2tTS3dNClhQck9LYjFqWlBncHFsSlFQU2kw
RUZBbis5RGo4QmRBQjJOK0c2RmxZNTQKLS0tIElVS2J1eDNSZkRjd3JLakFEK1dM
QXBHckN4NlBZSnk2S1QraVlnRTdMckkKgQha9/oB6FjUDGZqVzCnuJgqKhzeUE9v
f09pNl5FiJLVNO2fps0EcrnOzES1
-----END AGE ENCRYPTED FILE-----

saltpack

saltpack is the file encryption component behind keybase command-line tool. It's implemented in Python so installation is matter of simple pip3 install saltpack command. Feature-wise it offers a standard set: encrypt, encrypt and sign, decrypt, sign, verify, on binary files or ASCII-armored.

Saltpack is clearly intended to be used as a single-purpose low-level utility that is not intended to be used outside of Keybase. It certainly can be, but you need to know exactly what you're doing. The utility command-line interface has no features related to key management whatsoever. Keys for symmetric encryption can be generated with OpenSSL (openssl rand -hex 32) but you'd need to use a third-party utility (like PyNACL) to generate the Curve25519 key for signatures.

Saltpack encryption (symmetric):

$ echo "test message" | saltpack encrypt 7197776c96abbe85d56bf244cf540490a7f93b8c0ffc9f16507e9b2b6cb128e8
BEGIN SALTPACK ENCRYPTED MESSAGE. kcJn5brvybfNjz6 D5litY0cge0o8cB TfxK1uQZtmH40xa l0gonT39p6gJtQF 1tIQhnkVsq7ePtm ANiVglF6O4OIsgr o89xjdX9xci6V5l P6RCXLolkrNmrzI AX2nTVD3aqLD3jz kQkO7jyeymqzSSn eAcX7lHVnVrxHpd NcWU91qm3P6owYe PeadDy0SeNqm9gx NcqfSjvFJOtrvcY MwZjrIA17qOOQsL st8uAh2iFAyeB1r KICtg2dCcLujeBA APZJonujHje6327 UogJJu25m03mFb6 ncYMVCBf9xQrFtY mhhONboFg7XrXgL AKuQG7wuKmygxKi xC3Z4UwnUr6TJu1 djUm4AjH4NnOhab uo2CfiFzm. END SALTPACK ENCRYPTED MESSAGE.

Saltpack signature:

$ echo "test message" | saltpack sign 7197776c96abbe85d56bf244cf540490a7f93b8c0ffc9f16507e9b2b6cb128e87197776c96abbe85d56bf244cf540490a7f93b8c0ffc9f16507e9b2b6cb128e8
BEGIN SALTPACK SIGNED MESSAGE. kYM5h1pg6qz9UMn j6G7KB2OUdTE6Lz G095yS2e3DXts15 7C7kv3B876MpkSx TQ5c8zTQISiVtCa 5KBOaKyZD6b3HNL NzoFkYeTwuoJmTb QBQwtN32YYbMHD9 LYcb8PN4NcLbUCm 1a6V5LaxuqqFNTa
1yPkvrj9w7NsTQD RqdYWo9yOqU6dpT vppvwpdWov66pfY DE6ZMbtg3b4nKIs hMZCnRNMs6wCQ2d Q1b3NSBx1ee6nIH BCL8x1ovjERHUf3 BtIf1QbvRRoelaJ HhOK7vmodiRnjua VpYDqTusXdjGGab xJel7W64FPuCJ6b A. END SALTPACK SIGNED MESSAGE.

sio (ncrypt)

sio is a file encryption tool written in Go intended for symmetric encryption-at-rest of data like backups, with very small overhead and support for very large files. It clearly follows the principle of doing just one thing, but doing it well. The library that implements the file format is called sio and it comes with a simple command-line utility called ncrypt.

$ echo "test message" | ./ncrypt -p lieg7shatalu0Pahsh3i > test.dat
$ hexdump -C test.dat
00000000  dd 61 85 13 74 be 42 10  9f 02 14 ef 0a 72 75 0c  |.a..t.B......ru.|
00000010  77 b6 b3 b9 5e a4 b8 d4  ca fb b3 0d 32 12 57 30  |w...^.......2.W0|
00000020  20 00 0c 00 fa 67 ec 7a  1c 36 f7 fb 0c 0d 56 e3  | ....g.z.6....V.|
00000030  22 6d 6c 3f 61 de 1d 1a  da a0 d9 2d 0b 11 c5 c7  |"ml?a......-....|
00000040  e4 ec f0 fb 7e 88 a0 17  61 6e 07 3a e3           |....~...an.:.|
0000004d

signify

signify is utility for digitally signing files written for OpenBSD and ported to other systems. In Ubuntu it's available in package called signify-openbsd. In OpenBSD it's commonly used for digitally signing distribution packages and publisher keys are distributed as part of the operating system. Private key is always protected by a passphrase.

$ signify-openbsd -G -p keyname.pub -s keyname.sec
passphrase:
confirm passphrase:

$ cat keyname.pub
untrusted comment: signify public key
RWSGgAl+M1CdQGaVEmULsxWY8lp/x1mcolEziYm4IipZhsqwJkZ4LFMJ

Sign a file:

$ signify-openbsd -S -s keyname.sec -m lorem.txt
passphrase:

$ cat lorem.txt.sig
untrusted comment: verify with keyname.pub
RWSGgAl+M1CdQHF/EA0rnJ83t0pF7pGr3x1DoLHRygne99dwbCcbc4evXw9qh35nH1hHvmluyfjEGbb2LduqCfcENEGyxs0oKAE=

minisign

minisign is an evolution of signify written in C. It can verify signatures created by the latter but not the way around. Minisign adds a number of performance and functional improvements so for a new project that does not require compatibility with OpenBSD this is probably a better choice.

Command-line options of minisign is the same as signify with a few extra options.

encpipe

encpipe is a companion to minisign — single-purpose and very simple utility for symmetric encryption of data. The intended usage scenario is a classic Linux network pipe, where encpipe provides confidentiality and integrity:

nc -l 6666 | encpipe -d -p password
encpipe -e -p password -i /etc/passwd | nc 127.0.0.1 6666