3

I have a file I encrypted with PGP in 2003. It contains some personal data I'd like to regain access to. I have vague idea of the password, but not enough to successfully guess; but I know its complexity is low. I estimate that search space is on the order of 1e9 and that I need to be able to try about 1000 passwords per second to have chance of cracking it in reasonable timeframe (less than year). Pgpdump says:

$ pgpdump myfile.tar.pgp
Old: Symmetrically Encrypted Data Packet(tag 9)(7267297 bytes)
    Encrypted data [sym alg is IDEA, simple string-to-key]

Trivial approach with repeatedly invoking gnupg is far too slow (about 1 password per second). I would welcome some ideas how to approach this problem, or even better, if some tools to help with this exist.

My current thinking is to piece together my own decrypter code from PGP 2.6.3 source, but that would be quite a project, especially as I am not proficient with C.

Thanks to @dave_thompson_085 for pointing out that there is in fact a way to check if the supplied password is correct (sort of). Unfortunately, it's only a 16 bits, so it inevitably will run into collisions (I actually found one before), passwords that will be accepted, but won't result in correct decryption.

6
  • Depending on your budget Elcomsoft might have the solution, I think they do support that format elcomsoft.com/edpr.html Commented Nov 23, 2022 at 10:15
  • If you do take up on that that software project your best bet is likely to build upon either JtR or Hashcat as a lot of building blocks would be there already. Commented Nov 23, 2022 at 10:18
  • @BrunoRohée Unfortunately the main part of the cracker would be decrypting and verifying the decryption, so JtR/Hashcat won't be much help here. This is not like recovering a password from a hash.
    – mdw
    Commented Nov 23, 2022 at 11:07
  • I assumed the format was somewhat reasonable and that there was e.g. a 32 bit value used to check a password input was correct before doing all that work. Commented Nov 23, 2022 at 11:09
  • If you have the resources (memory, cpu), you can try to parallelize the attack. I would start with a dictionary attack, perhaps with a dictionary based on your vague idea of the password. Commented Nov 23, 2022 at 15:18

2 Answers 2

1

RFC 4880 §3.7.1.1 describes rudimentarily the S2K algorithms. The good news is that it's extremely weak by today's standard, and that plain hashes are well supported by both JohnTheRipper and Hashcat, so you should investigate the way old PGP (before the OpenPGP format) checks for password correctness before decryption and produce something that can be ingested by JtR or Hashcat.

5
  • PGP seems to derive the key by simply MD5ing the password string. That would be easy, but there is no way to check if the password is correct, you simply decrypt and get either correct plaintext or nonsense. This is further complicated by the fact, that the plaintext is compressed before encryption. There are further gotchas for unexperienced user like me, e.g. PGP 2.6.3 doesn't cleanly compile, esp. the inline assembly doesn't work in GCC.
    – mdw
    Commented Nov 23, 2022 at 10:50
  • Meh, no clear key correctness test makes it a PITA, and full decryption, decompression and test makes it inherently slow. Commented Nov 23, 2022 at 11:10
  • You can short circuit this significantly by decompressing and decrypting only small part (say first 512 bytes) of the file. The underlying file is a tar, so you can check that there are only ASCII chars in there. Also any decompression error means you can immediately bail out.
    – mdw
    Commented Nov 23, 2022 at 11:22
  • 1
    @mdw+ PGP-and-OpenPGP's CFB variant, described in 13.9 of 4880 (or 12.9 of 2440), does put 16-bits of redundancy after the initial nonce block, which detects most wrong keys (and thus passwords) without decrypting more or decompressing at all Commented Nov 24, 2022 at 1:09
  • @dave_thompson_085 Yes, that's an interesting observation, I'll try to look into that.
    – mdw
    Commented Nov 24, 2022 at 9:51
0

I have the same problem, and I may be able to put it into perspective.

As already mentioned, PGP puts 16 bits of redundancy into the second block. This can be used to short-circuit password checks (see the Oracle in "An Attack on CFB Mode Encryption As Used By OpenPGP" by Serge Mister & Robert Zuccherato 2005). It essentially rejects 65535 out of 65536 wrong passwords extremely quick (in less than a few thousand CPU cycles).

You can further improve this by decoding the 3rd block and verifying that the header is a valid PGP packet header. Rejects 3 out of 4 remaining candidates.

After that, you can feed it into PGP. Do not use the official PGP command-line build because of countless issues. Rather, build your own executable, that at its core just calls

PGPDecode(c,
    PGPOInputFile(c, inpath),
    PGPOOutputFile(c, outpath),
    PGPOPassphraseBuffer(c, pass, strlen(pass)),
    PGPOLastOption(c)
);

If this call is successful, and the result is larger than the ciphertext (because compression!), you have a candidate.

I can run 1.2 million attempts per second per core on my machine. Even without multi-threading, 1e9 possibilities just take a cup of coffee and produce just a few dozen serious candidates that you can check manually for consistency.

Still, if your password is strong and there are more than a hundred billion possibilities, you’re out of luck.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .