justinludwig / jpgpj

Java Pretty Good Privacy Jig
MIT License
75 stars 20 forks source link

Unable to decrypt file encrypted with BCPG 1.46 #8

Closed jaroslawk closed 6 years ago

jaroslawk commented 7 years ago

I have a legacy system which send's me information encrypted with pgp using BCPG 1.46. Using gpg I can decrypt is correctly, but not using jpgpj.

Here is example message:

-----BEGIN PGP MESSAGE----- Version: BCPG v1.46

hQEMAysESB6IChRpAQf+KYnoIfSC02hd7xvS5jumg7m8kzikwultRTfKkGd+kRtX OovHgAQ7WvZumsnXTpDiMOBPTqfP+aWb3eWI+TdSrOXjIejFdhoTBHr3ODkQXWzT 08FGfpH6VL0VoD34Vy84h7Dl2/Ym9/k2wGajVrh5C3WVt6JqH5lgnFvjK3dAZs3r 3yFvWu/LEFEanHwahVYhG4CZIQo3g4muU1LjVdD08pdQCpggBrT2CsHnVp1mCv6O KdMjerHy61yt8H0fFVPavdFKZuzmdpnYd0cEv/adw+alxOH31Wl5hCJ1G3AF/7N2 VjR57s4TRwRs0HxANeMv4If0xpF972Iz6LovWeGcuckd8pbQe5L5TXkYyLlFFUkS Ux40Fo1065HCOkKJUDU= =wxnx -----END PGP MESSAGE-----

encrypted with test-ring-pub.asc

Attaching sample file how this was generated.

PGPEncryptionOld.java.txt

dependency:

<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcpg-jdk15on</artifactId>
  <version>1.46</version>
</dependency>
justinludwig commented 7 years ago

Thanks for providing an easy example to work with! Sorry for taking so long to respond. Looks like this legacy system is not using the public key's standard "encryption" subkey for encryption, but rather the "certification" subkey. While the sample code from PGPEncryptionOld.java is using the Bouncy Castle PGPPublicKey.isEncryptionKey() method to check for a subkey that can be used for encryption, that method actually returns true for any subkey that can be used for encryption, rather than only for subkeys with usage flags specifically set for encryption.

If you use gpg --list-keys test-key-2 to list out the basic info for test-key-2, you'll get this output:

pub   rsa2048/880A1469 2016-03-06 [SC]
uid         [ unknown] Test 2 (CODESurvey) <test-key-2@codesurvey.org>
uid         [ unknown] Test Key 2 <test-key-2@c02e.org>
sub   rsa2048/AFAFA3C5 2016-03-06 [E]
sub   rsa2048/BC3F6A4B 2016-03-08 [S]

The first subkey (880A1469, on the 1st line) is the "certification" subkey (and is also flagged for "signing", as indicated by the [SC] label at the end of its line). Even though it's not flagged for encryption use, it technically can be used that way -- and since it's the first subkey listed, it's the first subkey the sample encryption code from PGPEncryptionOld.java will select.

The second subkey (AFAFA3C5, on the 4th line) is the "encryption" subkey (as indicated by the [E] label). This is the subkey that standard PGP applications use for encryption. However, it's a pain to find and sort through the usage flags for subkeys with the Bouncy Castle API, so that's why most example code for Bouncy Castle doesn't bother.

JPGPJ does check usage flags, though, so that's why by default it doesn't attempt to use the "certification" subkey for encryption/decryption. It is possible, however, to override this by explicitly setting the forDecryption property on a subkey to true. Here's an example that allows all the subkeys of test-key-2 to be used for decryption -- you should be able to use the same technique to decrypt the messages from the legacy system:

Decryptor decryptor = new Decryptor(
    new Key(new File("src/test/resources/test-key-2-master.asc"), "c02e")
);
decryptor.setVerificationRequired(false);

for (Key key: decryptor.getRing().getKeys())
    for (Subkey subkey: key.getSubkeys())
        subkey.setForDecryption(true);

decryptor.decrypt(
    new File("path/to/ciphertext.asc"),
    new File("path/to/plaintext.txt")
);
jaroslawk commented 6 years ago

Justin thank you for an explanation. I found a workaround for this problem earlier but this is a good source of information.

justinludwig commented 6 years ago

Glad you found a workaround -- I will add a section to the DecryptingFiles wiki page about it to help others avoid this issue.

justinludwig commented 6 years ago

I added a Decryption Errors section to the Decrypting Files wiki page to document what to check for or do when you encounter various errors, including an example of how to flag subkeys for decryption if you run into this kind of error.