Skip to content

Commit

Permalink
Clean up API
Browse files Browse the repository at this point in the history
  • Loading branch information
vanitasvitae committed Nov 16, 2024
1 parent 0716d02 commit ecd7051
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 144 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,9 @@
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.bouncycastle.openpgp.operator.PBEKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator;

Expand All @@ -35,9 +32,7 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -106,21 +101,9 @@ else if (configuration.recipients.isEmpty())
private HashAlgorithmNegotiator hashAlgorithmNegotiator =
(key, subkey) -> HashAlgorithmTags.SHA512;

private SubkeySelector encryptionKeySelector = certificate ->
{
List<OpenPGPCertificate.OpenPGPComponentKey> encryptionKeys = certificate.getEncryptionKeys();
return encryptionKeys.stream()
.map(OpenPGPCertificate.OpenPGPComponentKey::getKeyIdentifier)
.collect(Collectors.toList());
};
private SubkeySelector encryptionKeySelector = OpenPGPCertificate::getEncryptionKeys;

private SubkeySelector signingKeySelector = certificate ->
{
List<OpenPGPCertificate.OpenPGPComponentKey> signingKeys = certificate.getSigningKeys();
return signingKeys.stream()
.map(OpenPGPCertificate.OpenPGPComponentKey::getKeyIdentifier)
.collect(Collectors.toList());
};
private SubkeySelector signingKeySelector = OpenPGPCertificate::getSigningKeys;

// Literal Data metadata
private Date fileModificationDate = null;
Expand Down Expand Up @@ -217,7 +200,7 @@ public OpenPGPMessageGenerator setHashAlgorithmNegotiator(HashAlgorithmNegotiato
* @param recipientCertificate recipient certificate (public key)
* @return this
*/
public OpenPGPMessageGenerator addEncryptionCertificate(PGPPublicKeyRing recipientCertificate)
public OpenPGPMessageGenerator addEncryptionCertificate(OpenPGPCertificate recipientCertificate)
{
return addEncryptionCertificate(recipientCertificate, encryptionKeySelector);
}
Expand All @@ -231,9 +214,9 @@ public OpenPGPMessageGenerator addEncryptionCertificate(PGPPublicKeyRing recipie
* @param subkeySelector selector for encryption subkeys
* @return this
*/
public OpenPGPMessageGenerator addEncryptionCertificate(PGPPublicKeyRing recipientCertificate, SubkeySelector subkeySelector)
public OpenPGPMessageGenerator addEncryptionCertificate(OpenPGPCertificate recipientCertificate, SubkeySelector subkeySelector)
{
config.recipients.add(new Recipient(recipientCertificate, subkeySelector, implementation));
config.recipients.add(new Recipient(recipientCertificate, subkeySelector));
return this;
}

Expand All @@ -258,8 +241,8 @@ public OpenPGPMessageGenerator addEncryptionPassphrase(char[] passphrase)
* @return this
*/
public OpenPGPMessageGenerator addSigningKey(
PGPSecretKeyRing signingKey,
PBESecretKeyDecryptorProvider signingKeyDecryptorProvider)
OpenPGPKey signingKey,
SecretKeyPassphraseProvider signingKeyDecryptorProvider)
{
return addSigningKey(signingKey, signingKeyDecryptorProvider, signingKeySelector);
}
Expand All @@ -273,11 +256,11 @@ public OpenPGPMessageGenerator addSigningKey(
* @return this
*/
public OpenPGPMessageGenerator addSigningKey(
PGPSecretKeyRing signingKey,
PBESecretKeyDecryptorProvider signingKeyDecryptorProvider,
OpenPGPKey signingKey,
SecretKeyPassphraseProvider signingKeyDecryptorProvider,
SubkeySelector subkeySelector)
{
config.signingKeys.add(new Signer(signingKey, signingKeyDecryptorProvider, subkeySelector, implementation));
config.signingKeys.add(new Signer(signingKey, signingKeyDecryptorProvider, subkeySelector));
return this;
}

Expand Down Expand Up @@ -447,18 +430,16 @@ private void applySignatures(OpenPGPMessageOutputStream.Builder builder)
Stack<PGPSignatureGenerator> signatureGenerators = new Stack<>();
for (Signer s : config.signingKeys)
{
for (PGPSecretKey signingSubkey : s.signingSubkeys())
for (OpenPGPKey.OpenPGPSecretKey signingSubkey : s.signingSubkeys())
{
int hashAlgorithm = hashAlgorithmNegotiator.negotiateHashAlgorithm(s.signingKey, signingSubkey);
PGPSignatureGenerator sigGen = new PGPSignatureGenerator(
implementation.pgpContentSignerBuilder(signingSubkey.getPublicKey().getAlgorithm(), hashAlgorithm),
signingSubkey.getPublicKey());

PBESecretKeyDecryptor decryptor = s.decryptorProvider == null ? null :
s.decryptorProvider.provideDecryptor(signingSubkey);
PGPPrivateKey privKey = signingSubkey.extractPrivateKey(decryptor);
implementation.pgpContentSignerBuilder(signingSubkey.getPGPSecretKey().getPublicKey().getAlgorithm(), hashAlgorithm),
signingSubkey.getPGPSecretKey().getPublicKey());
char[] passphrase = signingSubkey.isLocked() ? s.passphraseProvider.providePassphrase(signingSubkey) : null;
PGPPrivateKey privateKey = signingSubkey.unlock(passphrase);

sigGen.init(PGPSignature.BINARY_DOCUMENT, privKey);
sigGen.init(PGPSignature.BINARY_DOCUMENT, privateKey);
signatureGenerators.push(sigGen);
}
}
Expand Down Expand Up @@ -561,7 +542,7 @@ public interface EncryptionNegotiator

public interface HashAlgorithmNegotiator
{
int negotiateHashAlgorithm(OpenPGPKey key, PGPSecretKey subkey);
int negotiateHashAlgorithm(OpenPGPKey key, OpenPGPCertificate.OpenPGPComponentKey subkey);
}

public static class Configuration
Expand Down Expand Up @@ -617,18 +598,11 @@ public Recipient(OpenPGPCertificate certificate, SubkeySelector subkeySelector)
*/
public List<PGPPublicKey> encryptionSubkeys()
{
// we first construct a set, so that we don't accidentally encrypt the message multiple times for the
// same subkey (e.g. if wildcards KeyIdentifiers are used).
Set<PGPPublicKey> encryptionKeys = new LinkedHashSet<>();
for (KeyIdentifier identifier : subkeySelector.select(certificate))
{
Iterator<PGPPublicKey> selected = certificate.getPGPKeyRing().getPublicKeys(identifier);
while (selected.hasNext())
{
encryptionKeys.add(selected.next());
}
}
return new ArrayList<>(encryptionKeys);
return subkeySelector.select(certificate)
.stream()
.map(OpenPGPCertificate.OpenPGPComponentKey::getPGPPublicKey)
.distinct()
.collect(Collectors.toList());
}
}

Expand All @@ -638,48 +612,25 @@ public List<PGPPublicKey> encryptionSubkeys()
static class Signer
{
private final OpenPGPKey signingKey;
private final PBESecretKeyDecryptorProvider decryptorProvider;
private final SecretKeyPassphraseProvider passphraseProvider;
private final SubkeySelector subkeySelector;

/**
* Create a {@link Signer}.
*
* @param signingKey OpenPGP key
* @param decryptorProvider provider for decryptors to unlock the signing subkeys
* @param subkeySelector selector to select the signing subkey
*/
public Signer(PGPSecretKeyRing signingKey,
PBESecretKeyDecryptorProvider decryptorProvider,
SubkeySelector subkeySelector,
OpenPGPImplementation implementation)
{
this(new OpenPGPKey(signingKey, implementation),
decryptorProvider, subkeySelector);
}

public Signer(OpenPGPKey signingKey,
PBESecretKeyDecryptorProvider decryptorProvider,
SecretKeyPassphraseProvider passphraseProvider,
SubkeySelector subkeySelector)
{
this.signingKey = signingKey;
this.decryptorProvider = decryptorProvider;
this.passphraseProvider = passphraseProvider;
this.subkeySelector = subkeySelector;
}

public List<PGPSecretKey> signingSubkeys()
public List<OpenPGPKey.OpenPGPSecretKey> signingSubkeys()
{
// we first construct a set, so that we don't accidentally sign the message multiple times using the
// same subkey (e.g. if wildcards KeyIdentifiers are used).
Set<PGPSecretKey> signingKeys = new LinkedHashSet<>();
for (KeyIdentifier identifier : subkeySelector.select(signingKey))
{
Iterator<PGPSecretKey> selected = signingKey.getPGPKeyRing().getSecretKeys(identifier);
while (selected.hasNext())
{
signingKeys.add(selected.next());
}
}
return new ArrayList<>(signingKeys);
return subkeySelector.select(signingKey)
.stream()
.map(signingKey::getSecretKey)
.distinct()
.collect(Collectors.toList());
}
}

Expand Down Expand Up @@ -806,11 +757,11 @@ public interface SubkeySelector
* @param certificate OpenPGP key or certificate
* @return non-null list of identifiers
*/
List<KeyIdentifier> select(OpenPGPCertificate certificate);
List<OpenPGPCertificate.OpenPGPComponentKey> select(OpenPGPCertificate certificate);
}

public interface PBESecretKeyDecryptorProvider
public interface SecretKeyPassphraseProvider
{
PBESecretKeyDecryptor provideDecryptor(PGPSecretKey key);
char[] providePassphrase(OpenPGPKey.OpenPGPSecretKey key);
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
package org.bouncycastle.openpgp.api.test;

import org.bouncycastle.bcpg.ArmoredInputStream;
import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
import org.bouncycastle.bcpg.test.AbstractPacketTest;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPObjectFactory;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.api.BcOpenPGPImplementation;
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.openpgp.api.OpenPGPMessageGenerator;
import org.bouncycastle.openpgp.api.OpenPGPMessageOutputStream;
import org.bouncycastle.openpgp.bc.BcPGPObjectFactory;
import org.bouncycastle.util.encoders.Hex;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class OpenPGPMessageGeneratorTest
extends AbstractPacketTest
Expand Down Expand Up @@ -141,14 +133,10 @@ private void seipd2EncryptedMessage()
"j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805\n" +
"I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==\n" +
"-----END PGP PUBLIC KEY BLOCK-----";
ByteArrayInputStream bIn = new ByteArrayInputStream(v6Cert.getBytes(StandardCharsets.UTF_8));
ArmoredInputStream aIn = new ArmoredInputStream(bIn);
BCPGInputStream pIn = new BCPGInputStream(aIn);
PGPObjectFactory objFac = new BcPGPObjectFactory(pIn);
PGPPublicKeyRing publicKeys = (PGPPublicKeyRing) objFac.nextObject();
OpenPGPCertificate cert = OpenPGPCertificate.fromAsciiArmor(v6Cert, new BcOpenPGPImplementation());

OpenPGPMessageGenerator gen = new OpenPGPMessageGenerator();
gen.addEncryptionCertificate(publicKeys);
gen.addEncryptionCertificate(cert);

ByteArrayOutputStream bOut = new ByteArrayOutputStream();
OutputStream encOut = gen.open(bOut);
Expand All @@ -158,8 +146,10 @@ private void seipd2EncryptedMessage()
System.out.println(bOut);
}

private void seipd1EncryptedMessage() throws IOException, PGPException {
String v4Cert = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
private void seipd1EncryptedMessage()
throws IOException, PGPException
{
String v4Key = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
"Comment: Bob's OpenPGP Transferable Secret Key\n" +
"\n" +
"lQVYBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv\n" +
Expand Down Expand Up @@ -241,19 +231,10 @@ private void seipd1EncryptedMessage() throws IOException, PGPException {
"xqAY9Bwizt4FWgXuLm1a4+So4V9j1TRCXd12Uc2l2RNmgDE=\n" +
"=miES\n" +
"-----END PGP PRIVATE KEY BLOCK-----\n";
ByteArrayInputStream bIn = new ByteArrayInputStream(v4Cert.getBytes(StandardCharsets.UTF_8));
ArmoredInputStream aIn = new ArmoredInputStream(bIn);
BCPGInputStream pIn = new BCPGInputStream(aIn);
PGPObjectFactory objFac = new BcPGPObjectFactory(pIn);
PGPSecretKeyRing secretKeys = (PGPSecretKeyRing) objFac.nextObject();
List<PGPPublicKey> pubKeys = new ArrayList<>();
for (Iterator<PGPPublicKey> it = secretKeys.getPublicKeys(); it.hasNext(); ) {
pubKeys.add(it.next());
}
PGPPublicKeyRing publicKeys = new PGPPublicKeyRing(pubKeys);
OpenPGPKey key = OpenPGPKey.fromAsciiArmor(v4Key, new BcOpenPGPImplementation());

OpenPGPMessageGenerator gen = new OpenPGPMessageGenerator();
gen.addEncryptionCertificate(publicKeys);
gen.addEncryptionCertificate(key);

ByteArrayOutputStream bOut = new ByteArrayOutputStream();
OutputStream encOut = gen.open(bOut);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ private void roundTripV6KeyEncryptedMessage()

OpenPGPMessageGenerator gen = new OpenPGPMessageGenerator()
.setArmored(true)
.addEncryptionCertificate(key.getPGPPublicKeyRing())
.addEncryptionCertificate(key)
.setIsPadded(false);

ByteArrayOutputStream bOut = new ByteArrayOutputStream();
Expand Down
Loading

0 comments on commit ecd7051

Please sign in to comment.