skeeto / passphrase2pgp

Generate a PGP key from a passphrase
The Unlicense
187 stars 14 forks source link

GnuPG 2.3 Questions #9

Closed Librechain closed 3 years ago

Librechain commented 3 years ago

Hey!

First want to say that this project is phenomenal. You are the only entity / individual I've come across that has had the same desire to make the kind of augmentations to PGP key generations that you did.

Recently, I saw that GnuPG released a new version (2.3) and announced through their mailing list: https://lists.gnupg.org/pipermail/gnupg-announce/2021q2/000458.html

There are a ton of new upgrades to it that (in my opinion) significantly enhance the security of the PGP protocol and address some of the drawbacks you mentioned in your blog post (which led me here).

One of the changelog items deals with 'date' and 'time', which you mention as a pain point in the ReadMe for this project, so hopefully that solves the issues you identified (or at least mitigates them to some extent).

Looking forward to getting your feedback / opinion on all of this whenever you can.

Once again, great job on this project man.

skeeto commented 3 years ago

I'm glad you've found passphrase2pgp useful, or at least interesting!

I have also taken note of GnuPG 2.3 and one feature in particular caught me eye: AEAD encryption. Done correctly, this would finally bring PGP encryption into the 21st century. Unfortunately, and as to be expected from GnuPG's usual mediocrity, its implementation in version 2.3 is broken and insecure. It's essentially useless in its current form.

Classical PGP encryption has only a weak form of optional authentication called MDC. This authentication is trivially stripped from any message. By default GnuPG will exit with failure if no MDC is present, but only after decrypting and outputting the entire possibly-compromised plaintext. Due to limitations of PGP itself, it simply cannot tell the difference between a altered message and a legacy message. GnuPG could avoid outputting unauthenticated plaintext, but due to the structure of the PGP format this would require buffering the entire message, which is often impractical. (Many less-useful criticisms of GnuPG miss this important detail.)

The new AEAD encryption mode has a strong, chunked authentication scheme that solves this problem. Implementations can always practically output strictly authenticated plaintext only buffering a chunk at a time regardless of the overall size of the message. The exit status indicates if a message was truncated, and that can only happen at chunk boundaries. It strikes a nice engineering balance, and it's a solid addition to the future of OpenPGP.

But that's where GnuPG screws up. Given all the tools necessary to get this right, it still outputs unauthenticated plaintext in AEAD operation! In case you have any doubts, you can see this for yourself. First encrypt a 2MiB message using 1MiB chunks:

head -c$((1<<21)) /dev/zero | gpg -c --batch --passphrase=x --force-aead --chunk-size 20 >enc

You can use --list-packets to verify that it is indeed AEAD. (Not an unreasonable check given GnuPG's tendency to silently ignore command line options and do non-obvious things.) Tamper with it by writing some zeros at, say, offset 1024 (i.e. early in the first chunk):

dd conv=notrunc if=/dev/zero of=enc bs=8 count=1 seek=1024

Then decrypt:

gpg --batch --passphrase=x <enc | wc -c

wc will indicate it got 983034 bytes of output before gpg exited with a failure status, i.e. it saw nearly the entire first chunk. If you inspect this output with a hex editor you can even see the tampering in the output. How on earth did GnuPG screw this up? I haven't dug into the source code yet, but I suspect it's a deep architectural problem typical of GnuPG. I bet that without some significant rewriting it is simply unable to authenticate before writing output, and it was easier to do the wrong thing than to fix it.

By the way, if you need a build of GnuPG 2.3, here's what I do:

https://github.com/skeeto/lean-static-gpg https://github.com/skeeto/gnupg-windows-build

If you go with the first option, you may need to uninstall your system GnuPG since otherwise GnuPG will use the wrong gpg-agent despite being explicitly told otherwise (--with-agent-pgm). (This is another one of those irritating GnuPG architectural issues.)

So I was initially quite excited to see AEAD support. I've considered adding encryption support to passphrase2pgp, but there were no other implementations against which to test. I thought it was finally time to take a crack at it. However, GnuPG has screwed this up badly enough that I'm going to wait. PGP encryption remains mediocre in practice.

The new default of ed25519 is great and will help with passphrase2pgp compatibility. There are still versions of GnuPG being distributed that don't support EC (RHEL 7, CentOS 7, some Git distributions), so this new default makes passphrase2pgp more legitimate.

Some of GnuPG's date handling bugs have been fixed, particularly the severe one ignoring key expiration, but others have not (see T4669). Again, you can observe this for yourself: Run --full-generate-key in version 2.3 and enter, say, "1000y" for the expiration period. Rather than get a distant expiration date (impossible to express in the OpenPGP format) or an error (the correct response, and passphrase2pgp's behavior) you'll silently get a nonsense, 32-bit wrapped date.

Improved Windows support is nice (UTF-8, T4398). This wasn't GnuPG's fault, but rather that every C toolchain for Windows is broken in order to remain compatible with Microsoft's 1990s vendor lock-in business strategy (that's another whole rant). Otherwise I don't find the other new features or changes in 2.3 particularly interesting.

Librechain commented 3 years ago

Hey! (sorry this response took so long) ; closing this issue, since it was more so a question rather than any "issue" with the project itself.

Thanks a ton for your super informative post. Have you reached out to the GnuPG team to tell them all of this? The tone of your post gave me the impression that perhaps you don't think they would be responsive to collaborating / taking on the responsibility of amending some of the issues that you pointed out.

I've never interacted with them before, so I wouldn't know either way. I hope that's not the case - but I guess that's the way of the word, right?

Does Passphrase2pgp Still Work With GnuPG 2.3 Without Issue?

Wasn't sure if any of the changes in the latest version of GnuPG would be 'breaking' in any way for passphrase2pgp.

It would truly suck to have to pick between using the latest version of GnuPG and passphrase2pgp (as your construction is one of the best ways to ensure that data can be encrypted and accessed later without having to store the actual private key on a device / server somewhere)

I'm assuming though that since it uses whatever version of GnuPG is on disk that there are probably no problems.

Curious About Advice / Suggestions For Default Configurations

This is way outside of the scope of this project, so if you're too busy to answer this question, then I completely understand.

But since you have a repo that streamlines the installation process for GnuPG, I was wondering if you had any suggested 'hardening' configurations in light of the newly available features for GPG 2.3

You seem very, very knowledgeable about the intricacies of PGP in general, so figured you'd be the best person to ask (again, if not - no worries! I'm sure you must be busy).

Contact Information For a Semi-Related Mini Project?

As a side note, there is a small side project that I have that is coded in Golang just like Passphrase2pgp. Its a command line tool that deals with encryption (file system encryption). This would be a fork of an already existing project. There are a few tweaks / changes to the configuration that my team and I wanted to make to 'modernize' its capabilities.

I very much believe that this tool would complement passphrase2pgp very well.

This is an open source project that will be released as such under a permissive license. Ample credit will be given to you in the documentation & other related areas (unless you object for any reason). This project stems from the same motivation that prompted you to make this project.

Not sure if you do any work like this or not - but if so, would love to touch base with you to rundown what we're looking for and see if this is something that's a good fit.

In my estimation, the project / task itself would probably require no more than 2-3 hours of your time. You can set the price based on what you feel the work & your time spent on it would be worth.