Skip to content

Commit

Permalink
added streamlined method for adding subkeys to existing keyrings (rel…
Browse files Browse the repository at this point in the history
…ates to github bcgit#755)
  • Loading branch information
dghgit committed Aug 3, 2020
1 parent 2c6f071 commit 8ff0b3b
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 4 deletions.
41 changes: 37 additions & 4 deletions pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRingGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.List;

import org.bouncycastle.bcpg.PublicSubkeyPacket;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
Expand All @@ -29,12 +30,12 @@ public class PGPKeyRingGenerator
*
* @param certificationLevel
* @param masterKey
* @param id
* @param checksumCalculator
* @param id id to associate with the key.
* @param checksumCalculator key checksum calculator
* @param hashedPcks
* @param unhashedPcks
* @param keySignerBuilder
* @param keyEncryptor
* @param keySignerBuilder builder for key certifications - will be initialised with master secret key.
* @param keyEncryptor encryptor for secret subkeys.
* @throws PGPException
*/
public PGPKeyRingGenerator(
Expand All @@ -58,6 +59,38 @@ public PGPKeyRingGenerator(
keys.add(new PGPSecretKey(certificationLevel, masterKey, id, checksumCalculator, hashedPcks, unhashedPcks, keySignerBuilder, keyEncryptor));
}

/**
* Create a new key ring generator based on an original secret key ring. The default hashed/unhashed sub-packets
* for subkey signatures will be taken from the first signature on the master key.
*
* @param originalSecretRing the secret key ring we want to add a subkeyto,
* @param secretKeyDecryptor a decryptor for the signing master key.
* @param checksumCalculator key checksum calculator
* @param keySignerBuilder builder for key certifications - will be initialised with master secret key.
* @param keyEncryptor encryptor for secret subkeys.
* @throws PGPException
*/
public PGPKeyRingGenerator(
PGPSecretKeyRing originalSecretRing,
PBESecretKeyDecryptor secretKeyDecryptor,
PGPDigestCalculator checksumCalculator,
PGPContentSignerBuilder keySignerBuilder,
PBESecretKeyEncryptor keyEncryptor)
throws PGPException
{
this.masterKey = new PGPKeyPair(originalSecretRing.getPublicKey(),
originalSecretRing.getSecretKey().extractPrivateKey(secretKeyDecryptor));
this.keyEncryptor = keyEncryptor;
this.checksumCalculator = checksumCalculator;
this.keySignerBuilder = keySignerBuilder;

PGPSignature certSig = (PGPSignature)originalSecretRing.getPublicKey().getSignatures().next();
this.hashedPcks = certSig.getHashedSubPackets();
this.unhashedPcks = certSig.getUnhashedSubPackets();

keys.addAll(originalSecretRing.keys);
}

/**
* Add a sub key to the key ring to be generated with default certification and inheriting
* the hashed/unhashed packets of the master key.
Expand Down
42 changes: 42 additions & 0 deletions pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3294,6 +3294,48 @@ public void testShouldProduceSubkeys()
// Extract the public keys
ByteArrayOutputStream bOut = new ByteArrayOutputStream(2048);
Iterator<PGPPublicKey> iterator = secretKeys.getPublicKeys();
int count = 0;
while (iterator.hasNext())
{
bOut.write(((PGPPublicKey)iterator.next()).getEncoded());
count++;
}

isTrue(count == 2);

checkPublicKeyRing(secretKeys, bOut.toByteArray());

isTrue(Arrays.areEqual(publicKeys.getEncoded(), bOut.toByteArray()));

// add an extra subkey
pgpGenerator = new PGPKeyRingGenerator(secretKeys, null, calculator, signerBuilder, null);

// Add sub key

subPackets.setKeyFlags(false, KeyFlags.ENCRYPT_STORAGE & KeyFlags.ENCRYPT_COMMS);

pair = generator.generateKeyPair();
pgpSubKey = new JcaPGPKeyPair(PublicKeyAlgorithmTags.ECDH, pair, new Date());

pgpGenerator.addSubKey(pgpSubKey, subPackets.generate(), null);

// Generate SecretKeyRing

secretKeys = pgpGenerator.generateSecretKeyRing();

publicKeys = pgpGenerator.generatePublicKeyRing();
count = 0;
for (Iterator it = publicKeys.getPublicKeys(); it.hasNext();)
{
it.next();
count++;
}
isTrue(count == 3);

checkPublicKeyRing(secretKeys, publicKeys.getEncoded());
// Extract the public keys
bOut = new ByteArrayOutputStream(2048);
iterator = secretKeys.getPublicKeys();
while (iterator.hasNext())
{
bOut.write(((PGPPublicKey)iterator.next()).getEncoded());
Expand Down

0 comments on commit 8ff0b3b

Please sign in to comment.