justinludwig / jpgpj

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

Modification: if Key Usage flags are not present then set them all #22

Closed mariuszmagdziarz closed 5 years ago

mariuszmagdziarz commented 5 years ago

if Key Usage flags are not present then set them all (older key or key generation process simply did not include the flags) For instance, these kinds of keys (without flags) are being used correctly by Linux GPG command-line tool. image (I cannot attach the key because contains the name of the client and its email)

The key from the above screenshot could be used to encryption by GPG command-line tool but could not be used by jpgpj (throw this exception PGPException("no suitable encryption key found")

justinludwig commented 5 years ago

Thanks for pointing out this issue and providing some code to address it! Sorry for taking so long to respond. One worry I have about automatically setting all a subkey's usage flags to true is that if the key has multiple subkeys, and you try to encrypt and/or sign with the key, you may end up encrypting or signing with a different subkey than your recipient expects -- with a typical key that has two subkeys, the first subkey is usually used for signing, and the second for encryption.

I'm thinking another way to address this (which would also solve some other common issues with usage flags) would be to create a new set of Key subclasses. These subclasses would make it eaiser to use keys that don't have usage flags (or have usage flags that don't match how they're actually used):

  1. A KeyForDecryption class that would automatically set the forDecryption flag to true for all of its subkeys (or rather, all subkeys that technically could be used for decryption), regardless of their actual usage flags.

  2. A KeyForVerification class that would automatically set the forVerification flag to true for all of its subkeys (or rather, all subkeys that technically could be used for verification), regardless of their actual usage flags.

  3. A KeyForEncryption class that would, if none of its subkeys have any encryption usage flags set, automatically set the forEncryption flag to true on the subkey that's mostly likely meant to be used for encryption.

  4. A KeyForSigning class that would, if none of its subkeys have any signing usage flags set, automatically set the forSigning flag to true on the subkey that's mostly likely meant to be used for signing.

Each of the above classes would also turn off the other usage flags for all of its subkeys -- for example, the KeyForDecryption would also turn off the forVerification, forEncryption, and forSigning flags for all of its subkeys (which would ensure that you don't inadvertantly use a key for verification that you intend only to use for decryption, or use a key for encryption that you intend only to use for signing, etc).

Having a KeyForDecryption class would be convenient in cases like those raised by issues #8 and #16, where subkeys are being used differently than their usage flags indicate; for example, the code sample in #8 could be simplified to the following:

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

decryptor.decrypt(
    new File("path/to/ciphertext.asc"),
    new File("path/to/plaintext.txt")
);

And with a KeyForEncryption class, instead of having to fiddle with the flags of the recipient's subkeys in order to use them for encryption (like in this example, if bob-pub.gpg was the key without usage flags):

Key bob = new Key(new File("/path/to/bob-pub.gpg"));
bob.getSubkeys().get(1).setForEncryption(true);

Encryptor encryptor = new Encryptor(
    new Key(new File("/path/to/alice-sec.gpg"), "password123"),
    bob
);

encryptor.encrypt(
    new File("path/to/plaintext.txt"),
    new File("path/to/ciphertext.txt.gpg")
);

You could simply use the KeyForEncryption class like the following to set the forEncryption flag automatically:

Encryptor encryptor = new Encryptor(
    new Key(new File("/path/to/alice-sec.gpg"), "password123"),
    new KeyForEncryption(new File("/path/to/bob-pub.gpg"))
);

encryptor.encrypt(
    new File("path/to/plaintext.txt"),
    new File("path/to/ciphertext.txt.gpg")
);

Or use the KeyForEncryption and KeyForSigning classes like the following if you wanted to use alice's key only to sign, and bob's key only to encrypt:

Encryptor encryptor = new Encryptor(
    new KeyForSigning(new File("/path/to/alice-sec.gpg"), "password123"),
    new KeyForEncryption(new File("/path/to/bob-pub.gpg"))
);

encryptor.encrypt(
    new File("path/to/plaintext.txt"),
    new File("path/to/ciphertext.txt.gpg")
);

I'd like to take a cut at the above idea, and try to generate those 4 new Key subclasses in the next few weeks.

mariuszmagdziarz commented 5 years ago

Justin thanks for your answer. I understand worries related to my change so I am waiting for your change. I have made a workaround for this issue.

To be frank, I had the issue #8 too, but I have made a workaround as well.

justinludwig commented 5 years ago

Thanks again for raising this issue! I added those KeyForDecryption etc classes (javadocs here), and released them as JPGPJ 0.7.