justinludwig / jpgpj

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

jpgpj cannot decode GPG2 .kbx ("keybox") rings #21

Closed lgoldstein closed 5 years ago

lgoldstein commented 5 years ago

I generated and populated a key ring using Linux gpg2 commands. When loading the pubring.kbx (in this case) there is no error, but the ring is reported as empty (which I can assure you it isn't):

Ring ring;
try (InputStream stream = Files.newInputString("/path/to/pubring.kbx")) {
    ring = new Ring(stream);
}
Collection<Key> keys = ring.getKeys();   // returns empty list

If you wish, I can send you a zip of the generated key-ring files for inspection and analysis (since they were for a test I don't really need them), though I believe the issue is easily reproducible. Seems to be some kind of version issue, since I can successfully load/read my $HOME/.gnunpg/pubring.gpg file. I did verify that version 1.x rings are correctly decoded, so I assume that my real ring was once 1.x and converted to 2.x, but the conversion left it somehow backward compatible.

justinludwig commented 5 years ago

Thanks for raising this issue! JPGPJ currently doesn't support reading keys from the gpg2 "kbx" (aka "keybox") file format. However, I believe Bouncy Castle (the underlying crypto library that JPGPJ uses) recently added some tools for reading these kind of files, so it should be possible to update JPGPJ to pull the public keys out of "keybox" files. I'll leave this issue open as a placeholder for adding that functionality (and also tweak the issue title to help remind myself about it).

In the meantime, if you need to use new keys that are only stored in a .kbx file, you can work around it by using gpg2 to first export the keys from the keybox to a traditional keyring like this:

gpg2 --keyring /path/to/pubring.kbx --export > /path/to/pubring.gpg

And then JPGPJ should be able to load the exported keys from /path/to/pubring.gpg like normal.

lgoldstein commented 5 years ago

Thanks for the quick reply and workaround. BTW, great library - makes working with PGP keys relatively easy - see MINA SSHD - keep up the good work.

justinludwig commented 5 years ago

I just released a new version of JPGPJ (0.6.1) that should be able load public keys from a "kbx" file, just like you'd expect. Let me know if you run into any issues with it.

lgoldstein commented 5 years ago

Great - I'll look, into it soon and open a new issue if I find any problems...

bclark76 commented 5 years ago

I did:

$ gpg2 --keyring /path/to/pubring.kbx --export > /path/to/pubring.gpg $ gpg2 --keyring /path/to/pubring.kbx --export-secret-keys > /path/to/secring.gpg

and this seems to work fine. I can use those files as my public key file and my secret key file the way I had been.

I can use the .kbx file for public keys too.

But as for the secret keys, no luck. I cannot pass pubring.kbx as they secret key file, and so signing while encrypting also doesn't work that way.

Trying to remain compatible with using gpg2 maintained .gnupg/ directory. ATM, being able to export keys into .gpg format is good enough, but I wonder if it will be possible to use secret keys from a /home/username/.gnupg/ directory without asking admins to do an export step whenever they update something...

As for me, they haven't updated to .kbx format yet so I still have .gpg ring files to use anyway, but the day may come when there's just .kbx files.

justinludwig commented 5 years ago

That's a good point -- I hadn't really thought about the issue of trying to suck in all the secret keys from a .gnupg directory before. With gpg2, the secret key material is stored separately from the public key information, with the secret key material for each subkey stored as a separate .key file in the .gnupg/private-keys-v1.d directory -- that's why JPGPJ currently only uses the public part of keys when loading from a .kbx file.

It'd be some work to add support for loading these gpg2 secret .key files, and matching them up with the public key info from a .kbx file; but it would be nice if you could just point JPGPJ at a directory and have it load up all available keys from it, like say:

Ring ring = new Ring(new File("path/to/.gnupg"));
KeyForSigning signingKey = new KeyForSigning(ring.findAll("alice").get(0), "password123");
KeyForEncryption encryptionKey = new KeyForEncryption(ring.findAll("bob").get(0));
new Encryptor(signingKey, encryptionKey).encrypt(
    new File("plain.txt"),
    new File("cipher.txt.gpg")
);

or:

Ring ring = new Ring(new File("path/to/.gnupg"));
ring.findAll("bob").get(0).setPassphrase("b0bru1z!");
new Decryptor(ring).decrypt(new File("cipher.txt.gpg"), new File("plain.txt"));

Also, it would be nice if you could call out specific .kbx and .key files to load into a JPGPJ ring:

Ring ring = new Ring(
    new File("path/to/pubring.kbx"),
    new File("path/to/1234ABCD.key"),
    new File("path/to/5678EF90.key"),
    new File("path/to/ABCD1234.key"),
    new File("path/to/EF905789.key")
);

Or load the .key file for just a specific subkey:

Ring ring = new Ring(new File("path/to/pubring.kbx"));
Key alice = ring.findAll("0x1234ABCD").get(0);
Subkey signingKey = alice.findAll("0x1234ABCD").get(0);
signingKey.loadSecretKey(new File("path/to/alice-signing.key"));
signingKey.setPassphrase("password123");

I'll open up a new issue specifically for loading gpg2 secret keys (with the intent of implementing support for it in the future).