bc-java icon indicating copy to clipboard operation
bc-java copied to clipboard

Feature request: Expose API for copying PGPPublicKey

Open ov7a opened this issue 2 years ago • 6 comments

Consider a scenario when a PGP key is acquired from a remote server and we only care about the master key and (probably) subkeys. The downloaded key might contain a lot of irrelevant data like images or user ids. There should be a way to transform PGPKeyring to remove unnecessary data from it.

Right now it is possible with this constructor for master key and this constructor for a subkey, but they are both are package private.

See an example of usage here.

Other scenarios might include GDPR handling (stripping any private data from a key) or size considerations (keeping a keyring as small as possible).

ov7a avatar May 23 '23 13:05 ov7a

okay, interesting, as the example usage points out, there's a bit of list juggling to keep everything in sync. What if rather than exposing the constructors we add an extract method, something like PGPKeyRing.extract(PGPKeyRing.KEYS | PGPKeyRing.SIGNATURES) which would return just the keys and key signatures? I'm not sure how far we could push it but at least we should be able to ensure correctness.

dghgit avatar May 30 '23 00:05 dghgit

Ensuring correctness is nice, yeah. However, I doubt It would be extensible enough to support all possible key transformations. I think extraction might be feasible with some sort of builder class for PGPKey.

ov7a avatar May 30 '23 05:05 ov7a

I suspect there'll be a point where just parsing the encoding and ignoring things would be the easiest way to do this... For the use case described, you're trying to generate a list of keys with their associated certifications but have all the user information and trust packets stripped out. Is that correct?

dghgit avatar May 31 '23 06:05 dghgit

Actually, I was thinking about this encoding/decoding, but found it a bit cumbersome in the end. As a user, I expect that library provides abstraction on lower-lever details and I don’t like the idea of serializing/deserializing stuff just to change something. It’s something like doing JSON.parse(JSON.stringify(o)); to get a deep copy of an object in JS.

Yes, your description of my case is correct. At first we decided to strip all userIDs, but then we decided to leave one for debugging purposes.

ov7a avatar May 31 '23 07:05 ov7a

Another use-case that is probably related to this:

OpenPGP v6 introduces minimal key-revocation certificates. To revoke a key(ring), it will be sufficient to distribute only the bare primary key (no user-ids, no signatures) with a single revocation signature. To extract only the bare key, it is currently required to strip all signatures, userIds and attributes one-by-one from a copy of the original key. An API that allows to directly create a copy from the public key would be nice to reduce the complexity here.

vanitasvitae avatar Jun 13 '23 17:06 vanitasvitae

I found that stripping any additional packets from the a public key works best using this constructor.

With it, I can clean a whole key ring simply using this method:

PGPPublicKeyRing original = ...;
KeyFingerprintCalculator fpCalc = ...;

List<PGPPublicKey> cleaned = new ArrayList<>();
Iterator<PGPPublicKey> it = original.getPublicKeys();
while(it.hasNext()) {
    PGPPublicKey cleanedKey = new PGPPublicKey(it.next().getPublicKeyPacket(), fpCalc);
    cleaned.add(cleanedKey);
}
PGPPublicKeyRing cleanedKeyRing = new PGPPublicKeyRing(cleaned);

vanitasvitae avatar Jun 20 '23 15:06 vanitasvitae