Due to the recent EFail disclosure, a new conversation has arisen over the security (it’s lacking) and usability (it’s complex) of PGP. This is a good conversation to have and, while I clearly have my own opinion, I welcome everyone’s thoughts in the comments below. I know the term “Post-PGP Age” is going to concern some members of the InfoSec community who will argue that strong, secure PGP clients are still the ideal solution for any use case, or at least the majority of them. My intention with this article is not to argue that PGP should die. Instead, I want to outline reasonable alternatives to PGP, of which readers may not be aware, so they can make an informed decision regarding their use case.
What is the problem with PGP?
Cryptography professor Matthew Green has a great article detailing the technical issues with PGP from 2014 and Keybase lists a series of cryptographic issues with PGP. We’ll summarize the two most troubling issues but those articles are definitely worth a read.
The biggest concern with PGP is that the cryptography just isn’t sufficient by modern standards. Chiefly, PGP has no support for forward secrecy. Forward secrecy is a property of cryptosystems that maintains confidentiality even if secret keys used in the past are compromised in the future. Each session has a different secret key. In some cases, such as with Signal, every single message has a new session key so, if a key is compromised, it only affects that particular message. The rest of the conversation remains secret. Without forward secrecy in PGP, if an attacker gains control of either party’s private key, the entire history of the conversation is compromised.
Additionally, PGP does not employ authenticated encryption by default. Authenticated encryption is a property that combines the confidentiality and integrity properties of ciphertext into one operation. There is a Modification Detection Code (MDC) option supported in OpenPGP since 2001, but it must be opted-in by client implementations and many have not. A secure cryptosystem should enforce secure defaults. There is, of course, a valid argument about maintaining support for legacy systems but, after 15+ years, it should be acceptable to begin to require the option.
What are my alternatives?
If you need to send encrypted email or secure sensitive files, what do you use if not PGP? Let’s look at what else is out there.
OpenSSL
Let me kick off by saying that, while it is an available alternative, you should not choose OpenSSL. Public key encryption with OpenSSL is a lengthy process and there are simpler options with stronger security available. But, let’s look at how it would work. Replace any %wrapped%
text with an appropriate value.
1) Get the recipient’s public key in pem
format and go to step 2. If the key is in rsa
format, such as a key generated for SSH, the recipient must perform the following operations to convert their public and private keys:
openssl rsa -in %RSA PRIVKEY% -outform pem > %PRIVKEY%.pem
openssl rsa -in %RSA PRIVKEY% -pubout -outform pem > %PUBKEY%.pem
2) As the sender, generate a random key:
openssl rand -base64 32 > %KEY%.bin
The 32 bytes in the -base64
flag generates a 256-bit key.
3) The sender encrypts the key:
openssl rsautl -encrypt -inkey %PUBKEY%.pem -pubin -in %KEY%.bin -out %KEY%.bin.enc
4) The sender encrypts the file:
openssl enc -aes-256-cbc -salt -in %FILE_TO_ENCRYPT% -out %ENCRYPTED_FILE%.enc -pass file:%ABSOLUTE_PATH_TO_KEY%.bin
1) The sender transmits the file and encrypted key to the recipient. The recipient now decrypts the key:
openssl rsautl -decrypt -inkey %PRIVKEY%.pem -in %KEY%.bin.enc -out %KEY%.bin
6) And the recipient now decrypts the file:
openssl enc -d -aes-256-cbc -in %ENCRYPTED_FILE%.enc -out %FILE% -pass file:%ABSOLUTE_PATH_TO_KEY%.bin
So, we are left with 5-6 steps. Unless you use LibreSSL, AES-GCM modes will not be available to you, meaning you will have to select the aes-256-cbc
option when encrypting. AES-GCM is an authenticated encryption mode of AES, but authenticated encryption is not present in OpenSSL at the time of this article. If you must use OpenSSL, I recommend using the generally drop-in replacement, LibreSSL, with which you will have authenticated encryption modes.
With OpenSSL, we have a cumbersome process that doesn’t even solve (unless you use LibreSSL) one of our two primary cryptographic concerns with PGP. Let’s see what else we can use.
Saltpack
Saltpack is a new cryptographic format developed by Keybase that is built on top of the NaCL cryptographic library. Saltpack was designed specifically to improve upon the security shortcomings of PGP. Details on the encryption spec can be found here. It provides authenticated encryption and forward secrecy, among other guarantees like repudiable authentication. How do you use it? There are two options.
Use the Keybase client
The sender and recipient must install Keybase.
1) Then, the sender encrypts the message:
keybase encrypt %RECIPIENT_KEYBASE_USERNAME% -m "%MESSAGE%"
# Or, read the message in from a file
keybase encrypt %RECIPIENT_KEYBASE_USERNAME < %MESSAGEFILE%
2) And the recipient decrypts the message:
keybase decrypt -m "%MESSAGE%"
# Or, from a file
keybase decrypt < %MESSAGEFILE%
There are also sign
and verify
commands available.
Use a Saltpack package for your programming language
Currently, there are Saltpack packages in Go and Python. However, the Go package is the one used by Keybase and is fully featured. The Python package lags behind in terms of feature support, at least according to the Python package’s README on Github. You can still perform the same encryption, decryption, signing, and verifying with the Python package as with the Go package.
To install:
# Go
go get github.com/keybase/saltpack
# Python - requires Python 3
pip install saltpack
The Godocs contain example usage of the Go library, so let’s look at what the Python usage would look like:
1) The sender encrypts the message:
python3 -m saltpack encrypt "%RECIPIENT_PUBKEY%" -m "%MESSAGE%" > %ENCRYPTED%.enc
1) The receiver decrypts the message:
python3 -m saltpack decrypt "%RECIPIENT_PRIVKEY%" < %ENCRYPTED%.enc
Saltpack, especially via the Keybase client, is a great choice for users. A server can run these commands via a CLI, while users also have the option of Keybase’s apps or the Keybase website.
Other
And finally, there are other alternatives, such as libpqcrypto, that require a development investment but could also serve as PGP replacements. There are also many NaCl clients that could be bootstrapped to support PGP-like behavior while taking advantage of stronger encryption. For “plug-and-play” encrypted email and file support, I recommend looking at Saltpack.
Thoughts on the article? Do you have other alternatives? Leave a comment!
Top comments (3)
Update: If I rewrote this today, I would end by directing people to Age for file/message symmetric encryption, magic wormhole for asymmetric encryption/E2E encrypted file transfer, and Minisign for file signatures and verification.
I know this post was made a while back, but I will pitch in here.
Currently my recommendation is Libsodium for developers and anyone implementing cryptography in applications. Which, is actually a fork of NaCL. I am glad you mentioned Saltpack. I never heard of it.
Keybase is great for individuals who don't know much about cryptography or just need an easy to use solution.
OpenSSL, PGP and other hard to use cryptography libraries and tools should be avoided for pretty much everyone. It's just easy to slip up.
On a note, you should be using Ed25519 keys for OpenSSL because it's newer, and RSA can be implemented insecurely, and often is.
Here are some Right Answers about cryptography.
You're totally right re: EC keys. Libsodium is also a great library and I should have mentioned it here. I do include it in this article on cryptographic randomness.