diff --git a/pgpainless-core/src/main/java/org/pgpainless/PGPainless.java b/pgpainless-core/src/main/java/org/pgpainless/PGPainless.java index 3fd90f82..92cfeefb 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/PGPainless.java +++ b/pgpainless-core/src/main/java/org/pgpainless/PGPainless.java @@ -66,12 +66,26 @@ public class PGPainless { /** * Create an {@link EncryptionStream}, which can be used to encrypt and/or sign data using OpenPGP. + * This method assumes that the stream will be used to encrypt data for communication purposes. + * If you instead want to encrypt data that will be saved on disk (eg. a backup), use + * {@link #encryptAndOrSign(EncryptionStream.Purpose)} and chose an appropriate purpose. + * * @return builder */ public static EncryptionBuilder encryptAndOrSign() { return new EncryptionBuilder(); } + /** + * Create an {@link EncryptionStream}, that can be used to encrypt and/or sign data using OpenPGP. + * + * @param purpose how will the data be used? + * @return builder + */ + public static EncryptionBuilder encryptAndOrSign(EncryptionStream.Purpose purpose) { + return new EncryptionBuilder(purpose); + } + /** * Create a {@link DecryptionStream}, which can be used to decrypt and/or verify data using OpenPGP. * diff --git a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java index 6ca02604..202f9fb8 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java @@ -37,6 +37,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.HashAlgorithm; +import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.SignatureType; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.exception.SecretKeyNotFoundException; @@ -55,6 +56,7 @@ import org.pgpainless.util.Passphrase; public class EncryptionBuilder implements EncryptionBuilderInterface { + private final EncryptionStream.Purpose purpose; private OutputStream outputStream; private final Set encryptionKeys = new HashSet<>(); private final Set encryptionPassphrases = new HashSet<>(); @@ -67,6 +69,14 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { private CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.UNCOMPRESSED; private boolean asciiArmor = false; + public EncryptionBuilder() { + this.purpose = EncryptionStream.Purpose.COMMUNICATIONS; + } + + public EncryptionBuilder(@Nonnull EncryptionStream.Purpose purpose) { + this.purpose = purpose; + } + @Override public ToRecipients onOutputStream(@Nonnull OutputStream outputStream) { this.outputStream = outputStream; @@ -425,9 +435,28 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { } PublicKeySelectionStrategy encryptionKeySelector() { + KeyFlag[] flags = mapPurposeToKeyFlags(purpose); return new And.PubKeySelectionStrategy( new NoRevocation.PubKeySelectionStrategy(), - new EncryptionKeySelectionStrategy()); + new EncryptionKeySelectionStrategy(flags)); + } + + private static KeyFlag[] mapPurposeToKeyFlags(EncryptionStream.Purpose purpose) { + KeyFlag[] flags; + switch (purpose) { + case COMMUNICATIONS: + flags = new KeyFlag[] {KeyFlag.ENCRYPT_COMMS}; + break; + case STORAGE: + flags = new KeyFlag[] {KeyFlag.ENCRYPT_STORAGE}; + break; + case STORAGE_AND_COMMUNICATIONS: + flags = new KeyFlag[] {KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE}; + break; + default: + throw new AssertionError("Illegal purpose enum value encountered."); + } + return flags; } SecretKeySelectionStrategy signingKeySelector() { diff --git a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java index e3c90040..0b74e25b 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java +++ b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java @@ -59,6 +59,23 @@ import org.pgpainless.util.Passphrase; */ public final class EncryptionStream extends OutputStream { + public enum Purpose { + /** + * The stream will encrypt communication that goes over the wire. + * Eg. EMail, Chat... + */ + COMMUNICATIONS, + /** + * The stream will encrypt data that is stored on disk. + * Eg. Encrypted backup... + */ + STORAGE, + /** + * The stream will use keys with either flags to encrypt the data. + */ + STORAGE_AND_COMMUNICATIONS + } + private static final Logger LOGGER = Logger.getLogger(EncryptionStream.class.getName()); private static final Level LEVEL = Level.FINE; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/EncryptionKeySelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/EncryptionKeySelectionStrategy.java index e59e87fa..9c1ced45 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/EncryptionKeySelectionStrategy.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/EncryptionKeySelectionStrategy.java @@ -26,11 +26,14 @@ import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; */ public class EncryptionKeySelectionStrategy extends PublicKeySelectionStrategy { - private static final HasKeyFlagSelectionStrategy.PublicKey HAS_ENCRYPT_COMMS_FLAG = - new HasKeyFlagSelectionStrategy.PublicKey(KeyFlag.ENCRYPT_COMMS); + private final HasKeyFlagSelectionStrategy.PublicKey keyFlagSelector; + + public EncryptionKeySelectionStrategy(KeyFlag... flags) { + this.keyFlagSelector = new HasKeyFlagSelectionStrategy.PublicKey(flags); + } @Override public boolean accept(@Nonnull PGPPublicKey key) { - return key.isEncryptionKey() && HAS_ENCRYPT_COMMS_FLAG.accept(key); + return key.isEncryptionKey() && keyFlagSelector.accept(key); } }