Allow the user to specify a purpose for encryption

This commit is contained in:
Paul Schaub 2021-01-09 20:30:34 +01:00
parent 8df752e995
commit 11c41e7ba7
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
4 changed files with 67 additions and 4 deletions

View File

@ -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.
*

View File

@ -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<PGPPublicKey> encryptionKeys = new HashSet<>();
private final Set<Passphrase> 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() {

View File

@ -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;

View File

@ -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);
}
}