From c89558a01bc65761a106a08dfa5df1042814673c Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sat, 9 Jan 2021 20:55:19 +0100 Subject: [PATCH] Split KeyFlagSelectionStrategies up into Has{Any|All}KeyFlagsSelectionStrategy --- .../encryption_signing/EncryptionBuilder.java | 12 ++-- .../impl/EncryptionKeySelectionStrategy.java | 20 +++++- ...va => HasAllKeyFlagSelectionStrategy.java} | 5 +- .../impl/HasAnyKeyFlagSelectionStrategy.java | 71 +++++++++++++++++++ ...=> KeyFlagBasedSelectionStrategyTest.java} | 41 +++++++---- ...ncryptCommsStorageFlagsDifferentiated.java | 2 +- 6 files changed, 126 insertions(+), 25 deletions(-) rename pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/{HasKeyFlagSelectionStrategy.java => HasAllKeyFlagSelectionStrategy.java} (93%) create mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/HasAnyKeyFlagSelectionStrategy.java rename pgpainless-core/src/test/java/org/pgpainless/key/selection/key/{HasKeyFlagsSelectionStrategyTest.java => KeyFlagBasedSelectionStrategyTest.java} (67%) 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 19083a61..307cbf39 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 @@ -441,6 +441,12 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { new EncryptionKeySelectionStrategy(flags)); } + SecretKeySelectionStrategy signingKeySelector() { + return new And.SecKeySelectionStrategy( + new NoRevocation.SecKeySelectionStrategy(), + new SignatureKeySelectionStrategy()); + } + private static KeyFlag[] mapPurposeToKeyFlags(EncryptionStream.Purpose purpose) { KeyFlag[] flags; switch (purpose) { @@ -458,10 +464,4 @@ public class EncryptionBuilder implements EncryptionBuilderInterface { } return flags; } - - SecretKeySelectionStrategy signingKeySelector() { - return new And.SecKeySelectionStrategy( - new NoRevocation.SecKeySelectionStrategy(), - new SignatureKeySelectionStrategy()); - } } 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 9c1ced45..924aa319 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 @@ -15,6 +15,8 @@ */ package org.pgpainless.key.selection.key.impl; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.annotation.Nonnull; import org.bouncycastle.openpgp.PGPPublicKey; @@ -26,14 +28,26 @@ import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; */ public class EncryptionKeySelectionStrategy extends PublicKeySelectionStrategy { - private final HasKeyFlagSelectionStrategy.PublicKey keyFlagSelector; + public static final Logger LOGGER = Logger.getLogger(EncryptionKeySelectionStrategy.class.getName()); + + private final HasAnyKeyFlagSelectionStrategy.PublicKey keyFlagSelector; public EncryptionKeySelectionStrategy(KeyFlag... flags) { - this.keyFlagSelector = new HasKeyFlagSelectionStrategy.PublicKey(flags); + this.keyFlagSelector = new HasAnyKeyFlagSelectionStrategy.PublicKey(flags); } @Override public boolean accept(@Nonnull PGPPublicKey key) { - return key.isEncryptionKey() && keyFlagSelector.accept(key); + boolean isEncryptionKey = key.isEncryptionKey(); + boolean hasAppropriateKeyFlags = keyFlagSelector.accept(key); + + if (!isEncryptionKey) { + LOGGER.log(Level.FINE, "Key algorithm is not suitable of encryption."); + } + if (!hasAppropriateKeyFlags) { + LOGGER.log(Level.FINE, "Key " + Long.toHexString(key.getKeyID()) + " does not carry "); + } + + return isEncryptionKey && hasAppropriateKeyFlags; } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/HasKeyFlagSelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/HasAllKeyFlagSelectionStrategy.java similarity index 93% rename from pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/HasKeyFlagSelectionStrategy.java rename to pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/HasAllKeyFlagSelectionStrategy.java index 4a414140..a016dc2c 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/HasKeyFlagSelectionStrategy.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/HasAllKeyFlagSelectionStrategy.java @@ -24,7 +24,10 @@ import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; import org.pgpainless.key.selection.key.SecretKeySelectionStrategy; -public class HasKeyFlagSelectionStrategy { +/** + * Selection Strategy that accepts a key if it carries all of the specified key flags. + */ +public class HasAllKeyFlagSelectionStrategy { public static class PublicKey extends PublicKeySelectionStrategy { diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/HasAnyKeyFlagSelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/HasAnyKeyFlagSelectionStrategy.java new file mode 100644 index 00000000..e7acfd1e --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/HasAnyKeyFlagSelectionStrategy.java @@ -0,0 +1,71 @@ +/* + * Copyright 2021 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pgpainless.key.selection.key.impl; + +import java.util.Iterator; + +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSecretKey; +import org.bouncycastle.openpgp.PGPSignature; +import org.pgpainless.algorithm.KeyFlag; +import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; +import org.pgpainless.key.selection.key.SecretKeySelectionStrategy; + +/** + * Selection Strategies that accept a key if it carries at least one of the given key flags. + */ +public class HasAnyKeyFlagSelectionStrategy { + + public static class PublicKey extends PublicKeySelectionStrategy { + + private final int keyFlagMask; + + public PublicKey(KeyFlag... flags) { + this(KeyFlag.toBitmask(flags)); + } + + public PublicKey(int mask) { + this.keyFlagMask = mask; + } + + @Override + public boolean accept(PGPPublicKey key) { + Iterator signatures = key.getSignatures(); + int flags = signatures.next().getHashedSubPackets().getKeyFlags(); + return (keyFlagMask & flags) != 0; + } + } + + public static class SecretKey extends SecretKeySelectionStrategy { + + private final int keyFlagMask; + + public SecretKey(KeyFlag... flags) { + this(KeyFlag.toBitmask(flags)); + } + + public SecretKey(int mask) { + this.keyFlagMask = mask; + } + + @Override + public boolean accept(PGPSecretKey key) { + Iterator signatures = key.getPublicKey().getSignatures(); + int flags = signatures.next().getHashedSubPackets().getKeyFlags(); + return (keyFlagMask & flags) != 0; + } + } +} diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/selection/key/HasKeyFlagsSelectionStrategyTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/selection/key/KeyFlagBasedSelectionStrategyTest.java similarity index 67% rename from pgpainless-core/src/test/java/org/pgpainless/key/selection/key/HasKeyFlagsSelectionStrategyTest.java rename to pgpainless-core/src/test/java/org/pgpainless/key/selection/key/KeyFlagBasedSelectionStrategyTest.java index 0588c039..8eb76df4 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/selection/key/HasKeyFlagsSelectionStrategyTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/selection/key/KeyFlagBasedSelectionStrategyTest.java @@ -34,9 +34,10 @@ import org.pgpainless.key.generation.type.KeyType; import org.pgpainless.key.generation.type.ecc.EllipticCurve; import org.pgpainless.key.generation.type.eddsa.EdDSACurve; import org.pgpainless.key.generation.type.xdh.XDHCurve; -import org.pgpainless.key.selection.key.impl.HasKeyFlagSelectionStrategy; +import org.pgpainless.key.selection.key.impl.HasAllKeyFlagSelectionStrategy; +import org.pgpainless.key.selection.key.impl.HasAnyKeyFlagSelectionStrategy; -public class HasKeyFlagsSelectionStrategyTest { +public class KeyFlagBasedSelectionStrategyTest { @Test public void testKeyFlagSelectors() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { @@ -61,12 +62,14 @@ public class HasKeyFlagsSelectionStrategyTest { // ENCRYPT_COMMS PGPSecretKey s_encryptionKey = iterator.next(); - HasKeyFlagSelectionStrategy.SecretKey s_certifyOther = - new HasKeyFlagSelectionStrategy.SecretKey(KeyFlag.CERTIFY_OTHER); - HasKeyFlagSelectionStrategy.SecretKey s_encryptComms = - new HasKeyFlagSelectionStrategy.SecretKey(KeyFlag.ENCRYPT_COMMS); - HasKeyFlagSelectionStrategy.SecretKey s_encryptCommsEncryptStorage = - new HasKeyFlagSelectionStrategy.SecretKey(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE); + HasAllKeyFlagSelectionStrategy.SecretKey s_certifyOther = + new HasAllKeyFlagSelectionStrategy.SecretKey(KeyFlag.CERTIFY_OTHER); + HasAllKeyFlagSelectionStrategy.SecretKey s_encryptComms = + new HasAllKeyFlagSelectionStrategy.SecretKey(KeyFlag.ENCRYPT_COMMS); + HasAllKeyFlagSelectionStrategy.SecretKey s_encryptCommsEncryptStorage = + new HasAllKeyFlagSelectionStrategy.SecretKey(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE); + HasAnyKeyFlagSelectionStrategy.SecretKey s_anyEncryptCommsEncryptStorage = + new HasAnyKeyFlagSelectionStrategy.SecretKey(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE); assertTrue(s_certifyOther.accept(s_primaryKey)); assertFalse(s_certifyOther.accept(s_encryptionKey)); @@ -81,16 +84,22 @@ public class HasKeyFlagsSelectionStrategyTest { assertFalse(s_encryptCommsEncryptStorage.accept(s_primaryKey)); assertFalse(s_encryptCommsEncryptStorage.accept(s_signingKey)); + assertTrue(s_anyEncryptCommsEncryptStorage.accept(s_encryptionKey)); + assertFalse(s_anyEncryptCommsEncryptStorage.accept(s_primaryKey)); + assertFalse(s_anyEncryptCommsEncryptStorage.accept(s_signingKey)); + PGPPublicKey p_primaryKey = s_primaryKey.getPublicKey(); PGPPublicKey p_encryptionKey = s_encryptionKey.getPublicKey(); PGPPublicKey p_signingKey = s_signingKey.getPublicKey(); - HasKeyFlagSelectionStrategy.PublicKey p_certifyOther = - new HasKeyFlagSelectionStrategy.PublicKey(KeyFlag.CERTIFY_OTHER); - HasKeyFlagSelectionStrategy.PublicKey p_encryptComms = - new HasKeyFlagSelectionStrategy.PublicKey(KeyFlag.ENCRYPT_COMMS); - HasKeyFlagSelectionStrategy.PublicKey p_encryptCommsEncryptStorage = - new HasKeyFlagSelectionStrategy.PublicKey(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE); + HasAllKeyFlagSelectionStrategy.PublicKey p_certifyOther = + new HasAllKeyFlagSelectionStrategy.PublicKey(KeyFlag.CERTIFY_OTHER); + HasAllKeyFlagSelectionStrategy.PublicKey p_encryptComms = + new HasAllKeyFlagSelectionStrategy.PublicKey(KeyFlag.ENCRYPT_COMMS); + HasAllKeyFlagSelectionStrategy.PublicKey p_encryptCommsEncryptStorage = + new HasAllKeyFlagSelectionStrategy.PublicKey(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE); + HasAnyKeyFlagSelectionStrategy.PublicKey p_anyEncryptCommsEncryptStorage = + new HasAnyKeyFlagSelectionStrategy.PublicKey(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE); assertTrue(p_certifyOther.accept(p_primaryKey)); assertFalse(p_certifyOther.accept(p_encryptionKey)); @@ -104,5 +113,9 @@ public class HasKeyFlagsSelectionStrategyTest { "Must not accept the key, as it only carries ENCRYPT_COMMS, but not ENCRYPT_STORAGE"); assertFalse(p_encryptCommsEncryptStorage.accept(p_primaryKey)); assertFalse(p_encryptCommsEncryptStorage.accept(p_signingKey)); + + assertTrue(p_anyEncryptCommsEncryptStorage.accept(p_encryptionKey)); + assertFalse(p_anyEncryptCommsEncryptStorage.accept(p_primaryKey)); + assertFalse(p_anyEncryptCommsEncryptStorage.accept(p_signingKey)); } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/weird_keys/TestEncryptCommsStorageFlagsDifferentiated.java b/pgpainless-core/src/test/java/org/pgpainless/weird_keys/TestEncryptCommsStorageFlagsDifferentiated.java index d24ca9c2..a6a695cd 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/weird_keys/TestEncryptCommsStorageFlagsDifferentiated.java +++ b/pgpainless-core/src/test/java/org/pgpainless/weird_keys/TestEncryptCommsStorageFlagsDifferentiated.java @@ -56,6 +56,6 @@ public class TestEncryptCommsStorageFlagsDifferentiated { .onOutputStream(out); // since the key does not carry the flag ENCRYPT_COMMS, it cannot be used by the stream. - assertThrows(IllegalStateException.class, () -> builder.toRecipients(publicKeys)); + assertThrows(IllegalArgumentException.class, () -> builder.toRecipients(publicKeys)); } }