reop - reasonable expectation of privacy

One of the obvious ideas I (and several others had) as soon as signify was released was to extend it to do more. After all, no program is complete until it can read email. Or at least munge up your email real bad.

Enter reop - reasonable expectation of privacy.


With some curiosity I read Creating the perfect GPG keypair. My conclusion is that there’s no such thing has a perfect GPG key pair. And we wonder why people leak secrets using hotmail. This shouldn’t be hard. More ranting about GPG at the bottom. Moving on.

reop is clearly influenced by signify (What can I say? I like my own designs.), but it’s not a clone. Its handling of keys is the most significant difference (besides the obvious, more features). Default keys are supported, and you can even add all your pals to ~/.reop/pubkeyring and verify their messages automatically, just like a normal PGP program.

Supported operations include signing -S and verifying -V messages, plus a variety of options for encrypting messages (-A -D -E). It does everything you’d expect a PGP program to do. More accurately, it does everything I expect you to expect a PGP program to do. I may be wrong, but it kills me to see people reaching for the gpg or openssl hammer of infinite possibilities for the simplest of tasks. Limitations below.

There is a (short) manual, of course, but there aren’t so many options that you should need to consult it more than once. Usually the short help text should be sufficient to get you started. I’ve tried to keep the option mnemonics reasonable.

reop # print usage usage: reop -G [-n] [-i ident] [-p pubkey -s seckey] reop -A [-i ident] [-p pubkey -s seckey] -m message [-x encfile] reop -D [-i ident] [-p pubkey -s seckey] -m message [-x encfile] reop -E [-i ident] [-p pubkey -s seckey] -m message [-x encfile] reop -S [-e] [-x sigfile] -s seckey -m message reop -V [-eq] [-x sigfile] -p pubkey -m message reop -G -i tedu # create tedu key pair reop -E -i ralph -m message # encrypt a message for ralph reop -D -x message.enc # ralph decrypts my message

I had a short lived plan to support the real OpenPGP standard, but as I was scrolling through it, I came across the words “ASN.1 Object Identifiers” and my monitor went blank to prevent permanent damage. As it is, reop implements a sort of look-alike/feel-alike facsimile of the standard.

-----BEGIN REOP SIGNED MESSAGE----- "So, you're the UNIX guru." At the time, Randy was still stupid enough to be flattered by this attention, when he should have recognized them as bone-chilling words. -----BEGIN REOP SIGNATURE----- ident:tedu RWS1l0sm+eG0IZ7/JZ7V3Ct584XleF33BQkIiXmHNHjHKWTBZprpVPeiLsCpkRFL1m0y3z7xFBkx nzoNVbTELwB932C1rdllJwQ= -----END REOP SIGNED MESSAGE-----

A reop key technically consists of two keys (one for signing, one for encrypting). The interesting part of a reop public key fits in a tweet (the ----- decoration stuff is too much though).

-----BEGIN REOP PUBLIC KEY----- ident:tedu RWRDU7WXSyb54bQhy9CZ7Qq6kUZMeOkxDeFNDOU/jl6oQp+vfgGbIP9mRinCQ/pnpvqCMjLnDG7I I8gMZw/P6zJ+jEaFZX+9pTyCYA== -----END REOP PUBLIC KEY-----

You don’t get to pick your algorithms. I pick them (sort of; nacl picked them). There is theoretical support for future algorithm changes. In general, reop only asks questions that only the user can answer, and which the user should be able to answer. Fewer features -> fewer feature options -> fewer commands to edit, adjust, and otherwise tweak those options.

$ wc reop/* reop/*/* 3038 11969 89452 total $ man gpg2 | wc 3138 15876 150953 $ wc rfc4880.txt 5043 28451 203706 rfc4880.txt


I’m guessing you’d rather hear about the fun crypto bits than my infallible programming skills.
All the crypto comes from nacl (indirectly via libsodium). Specifically, reop uses crypto_sign (Ed25519), crypto_box (Curve25519, Salsa20, and Poly1305) and crypto_secretbox (Salsa20 and Poly1305). I have not personally vetted these functions. Internet told me they were safe. ChaCha20 would be nice; maybe someday.

One thing to note is that the crypto_box construction (reop -E) may not behave like other public key encryption schemes you are familiar with. It takes two key pairs; the receiver’s public key as expected and the sender’s secret key, which offers a measure of authentication.

What the documentation doesn’t really make clear is that same set of keys used for encrypting work for decrypting (i.e., it’s not asymmetric). For instance, if Alice, sending a message to Bob, encrypts with secAlice and pubBob, that would normally be decrypted by Bob with pubAlice and secBob. But secAlice and pubBob work just as well to decrypt. If you were expecting to encrypt some secret with a public key and then have that computer “forget” how to access the secret, that won’t work.

reop works around this by introducing the -A (asymmetric? anonymous?) option, which creates an ephemeral key pair for the sender. The sender public key is embedded in the message; the sender secret key is thrown away; and now only the recipient with the recipient’s secret key can decrypt the data. However, now you lose authentication. If that matters, you can sign the result, but for now you have to compose the operations manually.

Nonces, where necessary, are generated randomly.

The nacl functions are all accessed via wrappers, very similar to the C++ wrappers. The C nacl API requires the caller to provide padded buffers (i.e., ciphertext, auth tag, and zeroed scratch space all contiguous in memory), which is somewhat inconvenient for a program like reop. As a result, more memory is allocated and data copied than strictly mathematically necessary. Additionally, nacl has a “packet” interface, not a “stream” interface, which imposes some other limits on message size, but for most practical purposes it should be fine.

It’s unfortunate, but I think nacl is the closest I’ve ever seen to a software interface that is perpendicular to the rest of the program. For a program that is essentially a CLI for nacl, reop spends considerable effort making sure that things are just so. The ZEROBYTES vs BOXZEROBYTES nonsense is just this side of ridiculous.


There’s no support for key revocation, or long chains of certificates, or partial trust, or key servers. For the most part, I think this is feel good wankery that doesn’t accomplish as much as one would like. I wonder how many people have ever revoked their PGP keys to see how it works in practice. The reop trust model is very simple. You can probably even understand it.

Keys don’t expire. If we expand the scope of inquiry slightly to TLS certs, I’ve lost count of the problems I’ve seen caused by prematurely expiring certs. Number of times an expired cert has saved my ass? Zero. This is arguably shortsighted, I know.

You can’t embed a JPG selfie into reop keys. Not even a tiny one.

reop doesn’t include a Tempest resistant font for viewing top zecret messages.


Developed on OpenBSD. Builds elsewhere. Uses libsodium.

I have endeavored to keep the code modular, such that it could be used in a library, but this is generally thwarted by the knowledge that top-level code has the privilege of simply giving up when things don’t go its way. Returning error codes -> having to check error codes.

I’m not enamored with the parsing code. Too much pointer banging.


As promised, a rant. I’m sure there are people who use GPG. I can’t. Let’s run gpg2 --gen-key.

Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only)

Why, in 2014, is GPG prompting me to create an RSA sign only key, which an RFC (4880) written in 2007 says are deprecated and SHOULD NOT be generated?

Please specify how long the key should be valid. 0 = key does not expire ... Key is valid for? (0) Key does not expire at all Is this correct? (y/N) Key is valid for? (0)

Help, I’m trapped in an infinite loop. If the default isn’t the right choice, it shouldn’t be the default. But here comes my favorite part.

We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy. We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy.

Holy shit! What kind of toy random number generator is GPG using? Never mind that the message is printed twice. Never mind that both messages flick by before I have half a chance to read them, let alone do anything to entropize my system. “Wiggle the mouse for moar entropies.” I wouldn’t trust a program that prints messages like this to protect my middle school slambook.

Posted 2014-04-01 12:32:27 by tedu Updated: 2014-04-01 23:50:45
Tagged: project security software
comment by Nobody at 2014-04-27 02:46:41:
Regarding the GPG RNG: Doesn't it use /dev/random, which is fed by, among other things, mouse and keyboard input? Why is it a problem for it to suggest doing that if it's blocking on /dev/random?

P.S. I found the secret login/registration. :)