1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-11-26 14:22:05 +01:00

Add handy default methods for the API and add documentation

This commit is contained in:
Paul Schaub 2020-08-24 16:00:23 +02:00
parent 65b670740e
commit 848a7a428b
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
3 changed files with 279 additions and 13 deletions

View file

@ -18,6 +18,7 @@ package org.pgpainless.decryption_verification;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -28,13 +29,41 @@ import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.pgpainless.key.OpenPgpV4Fingerprint; import org.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnprotectedKeysProtector;
public interface DecryptionBuilderInterface { public interface DecryptionBuilderInterface {
DecryptWith onInputStream(InputStream inputStream); /**
* Create a {@link DecryptionStream} on an {@link InputStream} which contains the encrypted and/or signed data.
*
* @param inputStream encrypted and/or signed data.
* @return api handle
*/
DecryptWith onInputStream(@Nonnull InputStream inputStream);
interface DecryptWith { interface DecryptWith {
/**
* Decrypt the encrypted data using the secret keys found in the provided {@link PGPSecretKeyRingCollection}.
* Here it is assumed that the secret keys are not password protected.
* For password protected secret keys use {@link #decryptWith(SecretKeyRingProtector, PGPSecretKeyRingCollection)}
* and pass in a {@link org.pgpainless.key.protection.PasswordBasedSecretKeyRingProtector}.
*
* @param secretKeyRings secret keys
* @return api handle
*/
default Verify decryptWith(@Nonnull PGPSecretKeyRingCollection secretKeyRings) {
return decryptWith(new UnprotectedKeysProtector(), secretKeyRings);
}
/**
* Decrypt the encrypted data using the secret keys found in the provided {@link PGPSecretKeyRingCollection}.
* The secret keys are being unlocked by the provided {@link SecretKeyRingProtector}.
*
* @param decryptor for unlocking locked secret keys
* @param secretKeyRings secret keys
* @return api handle
*/
Verify decryptWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRingCollection secretKeyRings); Verify decryptWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRingCollection secretKeyRings);
Verify doNotDecrypt(); Verify doNotDecrypt();
@ -43,33 +72,123 @@ public interface DecryptionBuilderInterface {
interface Verify extends VerifyWith { interface Verify extends VerifyWith {
VerifyWith verifyDetachedSignature(InputStream inputStream) throws IOException, PGPException; /**
* Pass in one or more detached signatures to verify.
*
* @param inputStream detached signature (ascii armored or binary).
* @return api handle
* @throws IOException in case something is wrong with the input stream
* @throws PGPException if the detached signatures are malformed
*/
VerifyWith verifyDetachedSignature(@Nonnull InputStream inputStream) throws IOException, PGPException;
VerifyWith verifyDetachedSignatures(List<PGPSignature> signatures); /**
* Pass in a detached signature to verify.
*
* @param signature detached signature
* @return api handle
*/
default VerifyWith verifyDetachedSignature(@Nonnull PGPSignature signature) {
return verifyDetachedSignatures(Collections.singletonList(signature));
}
/**
* Pass in a list of detached signatures to verify.
*
* @param signatures detached signatures
* @return api handle
*/
VerifyWith verifyDetachedSignatures(@Nonnull List<PGPSignature> signatures);
/**
* Instruct the {@link DecryptionStream} to not verify any signatures.
*
* @return api handle
*/
Build doNotVerify(); Build doNotVerify();
} }
interface VerifyWith { interface VerifyWith {
/**
* Pass in a collection of public keys to verify the signatures with.
*
* @param publicKeyRings public keys
* @return api handle
*/
HandleMissingPublicKeys verifyWith(@Nonnull PGPPublicKeyRingCollection publicKeyRings); HandleMissingPublicKeys verifyWith(@Nonnull PGPPublicKeyRingCollection publicKeyRings);
HandleMissingPublicKeys verifyWith(@Nonnull Set<OpenPgpV4Fingerprint> trustedFingerprints, @Nonnull PGPPublicKeyRingCollection publicKeyRings); /**
* Pass in a collection of public keys along with the fingerprint of the key that shall be used to
* verify the signatures.
*
* @param trustedFingerprint {@link OpenPgpV4Fingerprint} of the public key that shall be used to verify the signatures.
* @param publicKeyRings public keys
* @return api handle
*/
default HandleMissingPublicKeys verifyWith(@Nonnull OpenPgpV4Fingerprint trustedFingerprint,
@Nonnull PGPPublicKeyRingCollection publicKeyRings) {
return verifyWith(Collections.singleton(trustedFingerprint), publicKeyRings);
}
/**
* Pass in a collection of public keys along with a set of fingerprints of those keys that shall be used to
* verify the signatures.
*
* @param trustedFingerprints set of trusted {@link OpenPgpV4Fingerprint OpenPgpV4Fingerprints}.
* @param publicKeyRings public keys
* @return api handle
*/
HandleMissingPublicKeys verifyWith(@Nonnull Set<OpenPgpV4Fingerprint> trustedFingerprints,
@Nonnull PGPPublicKeyRingCollection publicKeyRings);
/**
* Pass in a trusted public key ring to verify the signature with.
*
* @param publicKeyRing public key
* @return api handle
*/
default HandleMissingPublicKeys verifyWith(@Nonnull PGPPublicKeyRing publicKeyRing) {
return verifyWith(Collections.singleton(publicKeyRing));
}
/**
* Pass in a set of trusted public keys to verify the signatures with.
*
* @param publicKeyRings public keys
* @return api handle
*/
HandleMissingPublicKeys verifyWith(@Nonnull Set<PGPPublicKeyRing> publicKeyRings); HandleMissingPublicKeys verifyWith(@Nonnull Set<PGPPublicKeyRing> publicKeyRings);
} }
interface HandleMissingPublicKeys { interface HandleMissingPublicKeys {
/**
* Pass in a callback that can is used to request missing public keys.
*
* @param callback callback
* @return api handle
*/
Build handleMissingPublicKeysWith(@Nonnull MissingPublicKeyCallback callback); Build handleMissingPublicKeysWith(@Nonnull MissingPublicKeyCallback callback);
/**
* Instruct the {@link DecryptionStream} to ignore any missing public keys.
*
* @return api handle
*/
Build ignoreMissingPublicKeys(); Build ignoreMissingPublicKeys();
} }
interface Build { interface Build {
/**
* Build the configured {@link DecryptionStream}.
*
* @return the decryption stream
* @throws IOException in case of an I/O error
* @throws PGPException if something is malformed
*/
DecryptionStream build() throws IOException, PGPException; DecryptionStream build() throws IOException, PGPException;
} }

View file

@ -257,12 +257,12 @@ public class EncryptionBuilder implements EncryptionBuilderInterface {
} }
@Override @Override
public <O> Armor signWith(@org.jetbrains.annotations.NotNull SecretKeyRingProtector decryptor, @org.jetbrains.annotations.NotNull PGPSecretKey... keys) { public Armor signWith(@org.jetbrains.annotations.NotNull SecretKeyRingProtector decryptor, @org.jetbrains.annotations.NotNull PGPSecretKey... keys) {
return new SignWithImpl().signWith(decryptor, keys); return new SignWithImpl().signWith(decryptor, keys);
} }
@Override @Override
public <O> Armor signWith(@org.jetbrains.annotations.NotNull SecretKeyRingProtector decryptor, @org.jetbrains.annotations.NotNull PGPSecretKeyRing... keyRings) { public Armor signWith(@org.jetbrains.annotations.NotNull SecretKeyRingProtector decryptor, @org.jetbrains.annotations.NotNull PGPSecretKeyRing... keyRings) {
return new SignWithImpl().signWith(decryptor, keyRings); return new SignWithImpl().signWith(decryptor, keyRings);
} }
@ -275,13 +275,13 @@ public class EncryptionBuilder implements EncryptionBuilderInterface {
class SignWithImpl implements SignWith { class SignWithImpl implements SignWith {
@Override @Override
public <O> Armor signWith(@Nonnull SecretKeyRingProtector decryptor, public Armor signWith(@Nonnull SecretKeyRingProtector decryptor,
@Nonnull PGPSecretKey... keys) { @Nonnull PGPSecretKey... keys) {
if (keys.length == 0) { if (keys.length == 0) {
throw new IllegalArgumentException("Recipient list MUST NOT be empty."); throw new IllegalArgumentException("Recipient list MUST NOT be empty.");
} }
for (PGPSecretKey s : keys) { for (PGPSecretKey s : keys) {
if (EncryptionBuilder.this.<O>signingKeySelector().accept(null, s)) { if (EncryptionBuilder.this.signingKeySelector().accept(null, s)) {
signingKeys.add(s); signingKeys.add(s);
} else { } else {
throw new IllegalArgumentException("Key " + s.getKeyID() + " is not a valid signing key."); throw new IllegalArgumentException("Key " + s.getKeyID() + " is not a valid signing key.");
@ -292,7 +292,7 @@ public class EncryptionBuilder implements EncryptionBuilderInterface {
} }
@Override @Override
public <O> Armor signWith(@Nonnull SecretKeyRingProtector decryptor, public Armor signWith(@Nonnull SecretKeyRingProtector decryptor,
@Nonnull PGPSecretKeyRing... keys) { @Nonnull PGPSecretKeyRing... keys) {
if (keys.length == 0) { if (keys.length == 0) {
throw new IllegalArgumentException("Recipient list MUST NOT be empty."); throw new IllegalArgumentException("Recipient list MUST NOT be empty.");
@ -300,7 +300,7 @@ public class EncryptionBuilder implements EncryptionBuilderInterface {
for (PGPSecretKeyRing key : keys) { for (PGPSecretKeyRing key : keys) {
for (Iterator<PGPSecretKey> i = key.getSecretKeys(); i.hasNext(); ) { for (Iterator<PGPSecretKey> i = key.getSecretKeys(); i.hasNext(); ) {
PGPSecretKey s = i.next(); PGPSecretKey s = i.next();
if (EncryptionBuilder.this.<O>signingKeySelector().accept(null, s)) { if (EncryptionBuilder.this.signingKeySelector().accept(null, s)) {
EncryptionBuilder.this.signingKeys.add(s); EncryptionBuilder.this.signingKeys.add(s);
} }
} }

View file

@ -29,63 +29,195 @@ import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.CompressionAlgorithm;
import org.pgpainless.algorithm.HashAlgorithm; import org.pgpainless.algorithm.HashAlgorithm;
import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
import org.pgpainless.decryption_verification.OpenPgpMetadata;
import org.pgpainless.exception.SecretKeyNotFoundException; import org.pgpainless.exception.SecretKeyNotFoundException;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnprotectedKeysProtector;
import org.pgpainless.key.selection.keyring.PublicKeyRingSelectionStrategy; import org.pgpainless.key.selection.keyring.PublicKeyRingSelectionStrategy;
import org.pgpainless.key.selection.keyring.SecretKeyRingSelectionStrategy; import org.pgpainless.key.selection.keyring.SecretKeyRingSelectionStrategy;
import org.pgpainless.util.MultiMap; import org.pgpainless.util.MultiMap;
public interface EncryptionBuilderInterface { public interface EncryptionBuilderInterface {
/**
* Create a {@link EncryptionStream} on an {@link OutputStream} that contains the plain data that
* shall be encrypted and or signed.
*
* @param outputStream output stream of the plain data.
* @return api handle
*/
ToRecipients onOutputStream(@Nonnull OutputStream outputStream); ToRecipients onOutputStream(@Nonnull OutputStream outputStream);
interface ToRecipients { interface ToRecipients {
/**
* Pass in a list of trusted public keys of the recipients.
*
* @param keys recipient keys for which the message will be encrypted.
* @return api handle
*/
WithAlgorithms toRecipients(@Nonnull PGPPublicKey... keys); WithAlgorithms toRecipients(@Nonnull PGPPublicKey... keys);
/**
* Pass in a list of trusted public key rings of the recipients.
*
* @param keys recipient keys for which the message will be encrypted.
* @return api handle
*/
WithAlgorithms toRecipients(@Nonnull PGPPublicKeyRing... keys); WithAlgorithms toRecipients(@Nonnull PGPPublicKeyRing... keys);
/**
* Pass in a list of trusted public key ring collections of the recipients.
*
* @param keys recipient keys for which the message will be encrypted.
* @return api handle
*/
WithAlgorithms toRecipients(@Nonnull PGPPublicKeyRingCollection... keys); WithAlgorithms toRecipients(@Nonnull PGPPublicKeyRingCollection... keys);
/**
* Pass in a map of recipient key ring collections along with a strategy for key selection.
*
* @param selectionStrategy selection strategy that is used to select suitable encryption keys.
* @param keys public keys
* @param <O> selection criteria type (eg. email address) on which the selection strategy is based
* @return api handle
*/
<O> WithAlgorithms toRecipients(@Nonnull PublicKeyRingSelectionStrategy<O> selectionStrategy, <O> WithAlgorithms toRecipients(@Nonnull PublicKeyRingSelectionStrategy<O> selectionStrategy,
@Nonnull MultiMap<O, PGPPublicKeyRingCollection> keys); @Nonnull MultiMap<O, PGPPublicKeyRingCollection> keys);
/**
* Instruct the {@link EncryptionStream} to not encrypt any data.
*
* @return api handle
*/
DetachedSign doNotEncrypt(); DetachedSign doNotEncrypt();
} }
interface WithAlgorithms { interface WithAlgorithms {
/**
* Add our own public key to the list of recipient keys.
*
* @param keys own public keys
* @return api handle
*/
WithAlgorithms andToSelf(@Nonnull PGPPublicKey... keys); WithAlgorithms andToSelf(@Nonnull PGPPublicKey... keys);
/**
* Add our own public key to the list of recipient keys.
*
* @param keys own public keys
* @return api handle
*/
WithAlgorithms andToSelf(@Nonnull PGPPublicKeyRing... keys); WithAlgorithms andToSelf(@Nonnull PGPPublicKeyRing... keys);
/**
* Add our own public keys to the list of recipient keys.
*
* @param keys own public keys
* @return api handle
*/
WithAlgorithms andToSelf(@Nonnull PGPPublicKeyRingCollection keys); WithAlgorithms andToSelf(@Nonnull PGPPublicKeyRingCollection keys);
/**
* Add our own public keys to the list of recipient keys.
*
* @param selectionStrategy key selection strategy used to determine suitable keys for encryption.
* @param keys public keys
* @param <O> selection criteria type (eg. email address) used by the selection strategy.
* @return api handle
*/
<O> WithAlgorithms andToSelf(@Nonnull PublicKeyRingSelectionStrategy<O> selectionStrategy, <O> WithAlgorithms andToSelf(@Nonnull PublicKeyRingSelectionStrategy<O> selectionStrategy,
@Nonnull MultiMap<O, PGPPublicKeyRingCollection> keys); @Nonnull MultiMap<O, PGPPublicKeyRingCollection> keys);
/**
* Specify which algorithms should be used for the encryption.
*
* @param symmetricKeyAlgorithm symmetric algorithm for the session key
* @param hashAlgorithm hash algorithm
* @param compressionAlgorithm compression algorithm
* @return api handle
*/
DetachedSign usingAlgorithms(@Nonnull SymmetricKeyAlgorithm symmetricKeyAlgorithm, DetachedSign usingAlgorithms(@Nonnull SymmetricKeyAlgorithm symmetricKeyAlgorithm,
@Nonnull HashAlgorithm hashAlgorithm, @Nonnull HashAlgorithm hashAlgorithm,
@Nonnull CompressionAlgorithm compressionAlgorithm); @Nonnull CompressionAlgorithm compressionAlgorithm);
/**
* Use a suite of algorithms that are considered secure.
*
* @return api handle
*/
DetachedSign usingSecureAlgorithms(); DetachedSign usingSecureAlgorithms();
} }
interface DetachedSign extends SignWith { interface DetachedSign extends SignWith {
/**
* Instruct the {@link EncryptionStream} to generate detached signatures instead of One-Pass-Signatures.
* Those can be retrieved later via {@link OpenPgpMetadata#getSignatures()}.
*
* @return api handle
*/
SignWith createDetachedSignature(); SignWith createDetachedSignature();
/**
* Do not sign the plain data at all.
*
* @return api handle
*/
Armor doNotSign(); Armor doNotSign();
} }
interface SignWith { interface SignWith {
<O> Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKey... keys); /**
* Pass in a list of secret keys used for signing.
* Those keys are considered unlocked (ie. not password protected).
* If you need to use password protected keys instead, use {@link #signWith(SecretKeyRingProtector, PGPSecretKey...)}.
*
* @param keys secret keys
* @return api handle
*/
default Armor signWith(@Nonnull PGPSecretKey... keys) {
return signWith(new UnprotectedKeysProtector(), keys);
}
<O> Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRing... keyRings); /**
* Pass in a list of secret keys used for signing, along with a {@link SecretKeyRingProtector} used to unlock
* the secret keys.
*
* @param decryptor {@link SecretKeyRingProtector} used to unlock the secret keys
* @param keys secret keys used for signing
* @return api handle
*/
Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKey... keys);
/**
* Pass in a list of secret keys used for signing, along with a {@link SecretKeyRingProtector} used to unlock
* the secret keys.
*
* @param decryptor {@link SecretKeyRingProtector} used to unlock the secret keys
* @param keyRings secret keys used for signing
* @return api handle
*/
Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRing... keyRings);
/**
* Pass in a map of secret keys for signing, as well as a {@link org.pgpainless.key.selection.key.SecretKeySelectionStrategy}
* that is used to determine suitable secret keys.
* If the keys are locked by a password, the provided {@link SecretKeyRingProtector} will be used to unlock the keys.
*
* @param selectionStrategy key selection strategy
* @param decryptor decryptor for unlocking secret keys
* @param keys secret keys
* @param <O> selection criteria type (eg. email address)
* @return api handle
*
* @throws SecretKeyNotFoundException in case no suitable secret key can be found
*/
<O> Armor signWith(@Nonnull SecretKeyRingSelectionStrategy<O> selectionStrategy, <O> Armor signWith(@Nonnull SecretKeyRingSelectionStrategy<O> selectionStrategy,
@Nonnull SecretKeyRingProtector decryptor, @Nonnull SecretKeyRingProtector decryptor,
@Nonnull MultiMap<O, PGPSecretKeyRingCollection> keys) @Nonnull MultiMap<O, PGPSecretKeyRingCollection> keys)
@ -95,8 +227,23 @@ public interface EncryptionBuilderInterface {
interface Armor { interface Armor {
/**
* Wrap the encrypted/signed output in an ASCII armor.
* This can come in handy for sending the encrypted message via eg. email.
*
* @return encryption stream
* @throws IOException in case some I/O error occurs
* @throws PGPException in case of some malformed pgp data
*/
EncryptionStream asciiArmor() throws IOException, PGPException; EncryptionStream asciiArmor() throws IOException, PGPException;
/**
* Do not wrap the output in an ASCII armor.
*
* @return encryption stream
* @throws IOException in case some I/O error occurs
* @throws PGPException in case of some malformed pgp data
*/
EncryptionStream noArmor() throws IOException, PGPException; EncryptionStream noArmor() throws IOException, PGPException;
} }