Thread Reader
Marcus Brinkmann

Marcus Brinkmann
@lambdafu

Nov 17, 2021
19 tweets
Twitter

Here is all you need toknow about the password security of PGP private keys and PGP symmetric encryption. tl;dr: PGP uses outdated and insecure algorithms. If you have to use it, you must choose a super strong password to protect yourself from brute force attacks. ๐Ÿงต๐Ÿ‘‡

This thread is about password protection of PGP private keys (stored or exported), and about password protected PGP messages ("gpg -c"). It's not about the public key encryption of PGP messages. This is inspired by a news story about somebody sending a private PGP key by email.
Password-based security uses the same strong symmetric encryption as public key based security, e.g. AES-128. The difference is how the symmetric key is computed. With passwords, a key derivation function (KDF) is used that computes the key from the password.
A simple idea is to use a hash function to compute a pseudo-random secret from the password. The problem is that an attacker can use precomputed rainbow tables to attack many passwords faster. To defeat rainbow tables, the password is made unique by a per-message random ("salt").
However, a single hash function invocation is so fast that it does not really impact brute force guessing. So, to make guessing slower, the hash function is invoked many times in a single key derivation. But this also slows down legitimate users, so we have to be extra careful.
KDFs can be tuned by setting a parameter that determines the number of hash computations. The recommendation is that you set this parameter as high as your users can tolerate. For example, GnuPG calibrates the PGP KDF to 100ms/pw single-core CPU time on the local machine.
But there is a limit to how many iterations can be encoded in the PGP data format. The details are in RFC4880, and pretty gruesome. Bear with me. The PGP KDF is called S2K and is a bit similar to PBKDF2 if you know that. It's basically the process I described above.
PGP S2K supports all three above methods: A simple, single hash invocation without a salt. A single hash invocation with a salt. And iterated salted hashing. Needless to say, the first two variants do not have a tuneable security margin and should not be used anymore.
The iterated salt S2K has a tuneable parameter, the "count". The count consists of a "mantisse" between 16 and 31, and an exponent (to basis 2) between 6 and 21. The total count is mantisse*2^exponent, which is a number between 1024 and 65,011,712. This is a hard limit in PGP!
The count is not the number of hash iterations, though, but the number of bytes used as input to the hash function (the salt and password are input repeatedly). With a blocksize of 512 bits (SHA-1, SHA-2), we have to divide by 64, giving an iteration count of up to approx. 1M.
This means that at best, PGP passwords are protected by 1M hash function invocations. In practice, the default count in GPG was for a long time 65536, which means only 1024 invocations. Today, the default depends on the speed of your computer (it's calibrated to 100ms).
By the way, the "good" hash functions supported by the PGP standard are SHA-1 and SHA-2 variants, and only SHA-1 is mandatory. For symmetric encryption, GPG uses SHA-1 by default. If you know your recipient supports it, you could also use the slightly slower (=stronger) SHA-2s.
The problem is that computing SHA-1 can be done very quickly using standard CPUs (~100MH/s), GPUs (~20 GH/s), and dedicated ASICs (such as used for Bitcoin mining, total network capacity ~160 Million TeraHash/s!). We can now compute how hard it is to brute-force a PGP password.
If you use GPG for symmetric encryption, it will warn you if you use a weak password. It recommends at least 8 characters, and at least one character should be a digit or special character. With these minimum requirements, there are about 26^7 * 95 = 763 Giga possible passwords.
A warning message from GnuPG: "You have entered an insecure passphrase. A passphrase should be at least 8 characters long. A passphrase should contain at least 1 digit or special character. Enter new passphrase or take this one anyway."
With a single GPU (such as an RTX3090 with 23 GH/s) and 1024 H/Password, we are looking at 22.5M password guesses per second. With 763G possible passwords this should take only 9.44 hours to brute force. With the strongest "count" setting, this would be 9440 hours or 390 days.
Now, you can improve this a bit by using a stronger hash function (SHA-256: Faktor 2.3, SHA-512: Faktor 7), but really the only viable option here is a much stronger password. The password recommendations made by GPG are simply inadequate for today's hashing performance.
To finish with a specific recommendation in case you have to use PGP: Using a 64-letter alphabet (a-zA-Z0-9+/) and a password length of 14 characters, you can pretty much ignore the PGP S2K settings. Thanks for making it through this thread! ๐Ÿ™
@Thread Reader App unroll, please
Marcus Brinkmann
I'm a tempura shrimp and you can't catch me! | ๐Ÿฆ™ ALPACA Attack | ๐Ÿฆ Raccon Attack | ๐Ÿ˜ˆ DEMONS Attack | @lambdafu@mastodon.social
Follow on Twitter
Missing some tweets in this thread? Or failed to load images or videos? You can try to .