diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/CompressionAlgorithm.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/CompressionAlgorithm.java index b1f11185..a2e78c5f 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/CompressionAlgorithm.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/CompressionAlgorithm.java @@ -5,10 +5,14 @@ package org.pgpainless.algorithm; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import org.bouncycastle.bcpg.CompressionAlgorithmTags; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * Enumeration of possible compression algorithms. * @@ -37,10 +41,28 @@ public enum CompressionAlgorithm { * @param id id * @return compression algorithm */ + @Nullable public static CompressionAlgorithm fromId(int id) { return MAP.get(id); } + /** + * Return the {@link CompressionAlgorithm} value that corresponds to the provided numerical id. + * If an invalid id is provided, thrown an {@link NoSuchElementException}. + * + * @param id id + * @return compression algorithm + * @throws NoSuchElementException in case of an unmapped id + */ + @Nonnull + public static CompressionAlgorithm requireFromId(int id) { + CompressionAlgorithm algorithm = fromId(id); + if (algorithm == null) { + throw new NoSuchElementException("No CompressionAlgorithm found for id " + id); + } + return algorithm; + } + private final int algorithmId; CompressionAlgorithm(int id) { diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/Feature.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/Feature.java index 9ec7e362..52de27bf 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/Feature.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/Feature.java @@ -7,10 +7,14 @@ package org.pgpainless.algorithm; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import org.bouncycastle.bcpg.sig.Features; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * An enumeration of features that may be set in the {@link Features} subpacket. * @@ -60,16 +64,46 @@ public enum Feature { } } + /** + * Return the {@link Feature} encoded by the given id. + * If the id does not match any known features, return null. + * + * @param id feature id + * @return feature + */ + @Nullable public static Feature fromId(byte id) { return MAP.get(id); } + /** + * Return the {@link Feature} encoded by the given id. + * If the id does not match any known features, throw an {@link NoSuchElementException}. + * + * @param id feature id + * @return feature + * @throws NoSuchElementException if an unmatched feature id is encountered + */ + @Nonnull + public static Feature requireFromId(byte id) { + Feature feature = fromId(id); + if (feature == null) { + throw new NoSuchElementException("Unknown feature id encountered: " + id); + } + return feature; + } + private final byte featureId; Feature(byte featureId) { this.featureId = featureId; } + /** + * Return the id of the feature. + * + * @return feature id + */ public byte getFeatureId() { return featureId; } @@ -80,6 +114,7 @@ public enum Feature { * @param bitmask bitmask * @return list of key flags encoded by the bitmask */ + @Nonnull public static List fromBitmask(int bitmask) { List features = new ArrayList<>(); for (Feature f : Feature.values()) { diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/HashAlgorithm.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/HashAlgorithm.java index b8c97d7e..bcd69cc0 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/HashAlgorithm.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/HashAlgorithm.java @@ -6,9 +6,13 @@ package org.pgpainless.algorithm; import java.util.HashMap; import java.util.Map; +import java.util.NoSuchElementException; import org.bouncycastle.bcpg.HashAlgorithmTags; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * An enumeration of different hashing algorithms. * @@ -42,10 +46,28 @@ public enum HashAlgorithm { * @param id numeric id * @return enum value */ + @Nullable public static HashAlgorithm fromId(int id) { return ID_MAP.get(id); } + /** + * Return the {@link HashAlgorithm} value that corresponds to the provided algorithm id. + * If an invalid algorithm id was provided, throw a {@link NoSuchElementException}. + * + * @param id algorithm id + * @return enum value + * @throws NoSuchElementException in case of an unknown algorithm id + */ + @Nonnull + public static HashAlgorithm requireFromId(int id) { + HashAlgorithm algorithm = fromId(id); + if (algorithm == null) { + throw new NoSuchElementException("No HashAlgorithm found for id " + id); + } + return algorithm; + } + /** * Return the {@link HashAlgorithm} value that corresponds to the provided name. * If an invalid algorithm name was provided, null is returned. @@ -56,6 +78,7 @@ public enum HashAlgorithm { * @param name text name * @return enum value */ + @Nullable public static HashAlgorithm fromName(String name) { return NAME_MAP.get(name); } diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/PublicKeyAlgorithm.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/PublicKeyAlgorithm.java index fcb1801c..baa8f92e 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/PublicKeyAlgorithm.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/PublicKeyAlgorithm.java @@ -5,10 +5,14 @@ package org.pgpainless.algorithm; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * Enumeration of public key algorithms as defined in RFC4880. * @@ -96,12 +100,30 @@ public enum PublicKeyAlgorithm { * If an invalid id is provided, null is returned. * * @param id numeric algorithm id - * @return algorithm + * @return algorithm or null */ + @Nullable public static PublicKeyAlgorithm fromId(int id) { return MAP.get(id); } + /** + * Return the {@link PublicKeyAlgorithm} that corresponds to the provided algorithm id. + * If an invalid id is provided, throw a {@link NoSuchElementException}. + * + * @param id numeric algorithm id + * @return algorithm + * @throws NoSuchElementException in case of an unmatched algorithm id + */ + @Nonnull + public static PublicKeyAlgorithm requireFromId(int id) { + PublicKeyAlgorithm algorithm = fromId(id); + if (algorithm == null) { + throw new NoSuchElementException("No PublicKeyAlgorithm found for id " + id); + } + return algorithm; + } + private final int algorithmId; private final boolean signingCapable; private final boolean encryptionCapable; diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureSubpacket.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureSubpacket.java index e3a754ae..9429f0c6 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureSubpacket.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureSubpacket.java @@ -4,6 +4,9 @@ package org.pgpainless.algorithm; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import static org.bouncycastle.bcpg.SignatureSubpacketTags.ATTESTED_CERTIFICATIONS; import static org.bouncycastle.bcpg.SignatureSubpacketTags.CREATION_TIME; import static org.bouncycastle.bcpg.SignatureSubpacketTags.EMBEDDED_SIGNATURE; @@ -36,6 +39,7 @@ import static org.bouncycastle.bcpg.SignatureSubpacketTags.TRUST_SIG; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; /** @@ -412,14 +416,28 @@ public enum SignatureSubpacket { /** * Return the {@link SignatureSubpacket} that corresponds to the provided id. + * If an unmatched code is presented, return null. * * @param code id * @return signature subpacket */ + @Nullable public static SignatureSubpacket fromCode(int code) { - SignatureSubpacket tag = MAP.get(code); + return MAP.get(code); + } + + /** + * Return the {@link SignatureSubpacket} that corresponds to the provided code. + * + * @param code code + * @return signature subpacket + * @throws NoSuchElementException in case of an unmatched subpacket tag + */ + @Nonnull + public static SignatureSubpacket requireFromCode(int code) { + SignatureSubpacket tag = fromCode(code); if (tag == null) { - throw new IllegalArgumentException("No SignatureSubpacket tag found with code " + code); + throw new NoSuchElementException("No SignatureSubpacket tag found with code " + code); } return tag; } @@ -433,7 +451,11 @@ public enum SignatureSubpacket { public static List fromCodes(int[] codes) { List tags = new ArrayList<>(); for (int code : codes) { - tags.add(fromCode(code)); + try { + tags.add(requireFromCode(code)); + } catch (NoSuchElementException e) { + // skip + } } return tags; } diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureType.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureType.java index a31dd31a..c2f02989 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureType.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureType.java @@ -6,6 +6,7 @@ package org.pgpainless.algorithm; import org.bouncycastle.openpgp.PGPSignature; +import javax.annotation.Nonnull; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -167,7 +168,9 @@ public enum SignatureType { * * @param code numeric id * @return signature type enum + * @throws IllegalArgumentException in case of an unmatched signature type code */ + @Nonnull public static SignatureType valueOf(int code) { SignatureType type = map.get(code); if (type != null) { diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/StreamEncoding.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/StreamEncoding.java index d47304f6..ad3de600 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/StreamEncoding.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/StreamEncoding.java @@ -5,10 +5,14 @@ package org.pgpainless.algorithm; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import org.bouncycastle.openpgp.PGPLiteralData; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * Enumeration of possible encoding formats of the content of the literal data packet. * @@ -78,11 +82,31 @@ public enum StreamEncoding { /** * Return the {@link StreamEncoding} corresponding to the provided code identifier. + * If no matching encoding is found, return null. * * @param code identifier * @return encoding enum */ + @Nullable public static StreamEncoding fromCode(int code) { return MAP.get((char) code); } + + /** + * Return the {@link StreamEncoding} corresponding to the provided code identifier. + * If no matching encoding is found, throw a {@link NoSuchElementException}. + * + * @param code identifier + * @return encoding enum + * + * @throws NoSuchElementException in case of an unmatched identifier + */ + @Nonnull + public static StreamEncoding requireFromCode(int code) { + StreamEncoding encoding = fromCode(code); + if (encoding == null) { + throw new NoSuchElementException("No StreamEncoding found for code " + code); + } + return encoding; + } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SymmetricKeyAlgorithm.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/SymmetricKeyAlgorithm.java index dcbf34cf..e04f21a5 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SymmetricKeyAlgorithm.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/SymmetricKeyAlgorithm.java @@ -5,10 +5,14 @@ package org.pgpainless.algorithm; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * Enumeration of possible symmetric encryption algorithms. * @@ -106,10 +110,29 @@ public enum SymmetricKeyAlgorithm { * @param id numeric algorithm id * @return symmetric key algorithm enum */ + @Nullable public static SymmetricKeyAlgorithm fromId(int id) { return MAP.get(id); } + /** + * Return the {@link SymmetricKeyAlgorithm} enum that corresponds to the provided numeric id. + * If an invalid id is provided, throw a {@link NoSuchElementException}. + * + * @param id numeric algorithm id + * @return symmetric key algorithm enum + * + * @throws NoSuchElementException if an unmatched id is provided + */ + @Nonnull + public static SymmetricKeyAlgorithm requireFromId(int id) { + SymmetricKeyAlgorithm algorithm = fromId(id); + if (algorithm == null) { + throw new NoSuchElementException("No SymmetricKeyAlgorithm found for id " + id); + } + return algorithm; + } + private final int algorithmId; SymmetricKeyAlgorithm(int algorithmId) { diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java index fbdd6229..d552ead8 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java @@ -14,6 +14,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -310,9 +311,13 @@ public final class DecryptionStreamFactory { private InputStream processPGPCompressedData(PGPCompressedData pgpCompressedData, int depth) throws PGPException, IOException { - CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.fromId(pgpCompressedData.getAlgorithm()); - LOGGER.debug("Depth {}: Encountered PGPCompressedData: {}", depth, compressionAlgorithm); - resultBuilder.setCompressionAlgorithm(compressionAlgorithm); + try { + CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.requireFromId(pgpCompressedData.getAlgorithm()); + LOGGER.debug("Depth {}: Encountered PGPCompressedData: {}", depth, compressionAlgorithm); + resultBuilder.setCompressionAlgorithm(compressionAlgorithm); + } catch (NoSuchElementException e) { + throw new PGPException("Unknown compression algorithm encountered.", e); + } InputStream inflatedDataStream = pgpCompressedData.getDataStream(); InputStream decodedDataStream = PGPUtil.getDecoderStream(inflatedDataStream); @@ -340,7 +345,7 @@ public final class DecryptionStreamFactory { resultBuilder.setFileName(pgpLiteralData.getFileName()) .setModificationDate(pgpLiteralData.getModificationTime()) - .setFileEncoding(StreamEncoding.fromCode(pgpLiteralData.getFormat())); + .setFileEncoding(StreamEncoding.requireFromCode(pgpLiteralData.getFormat())); if (onePassSignatureChecks.isEmpty() && onePassSignaturesWithMissingCert.isEmpty()) { LOGGER.debug("No OnePassSignatures found -> We are done"); diff --git a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/SigningOptions.java b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/SigningOptions.java index ab3898dc..0db93407 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/SigningOptions.java +++ b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/SigningOptions.java @@ -320,7 +320,7 @@ public final class SigningOptions { throws PGPException { SubkeyIdentifier signingKeyIdentifier = new SubkeyIdentifier(secretKey, signingSubkey.getKeyID()); PGPSecretKey signingSecretKey = secretKey.getSecretKey(signingSubkey.getKeyID()); - PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.fromId(signingSecretKey.getPublicKey().getAlgorithm()); + PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.requireFromId(signingSecretKey.getPublicKey().getAlgorithm()); int bitStrength = secretKey.getPublicKey().getBitStrength(); if (!PGPainless.getPolicy().getPublicKeyAlgorithmPolicy().isAcceptable(publicKeyAlgorithm, bitStrength)) { throw new IllegalArgumentException("Public key algorithm policy violation: " + diff --git a/pgpainless-core/src/main/java/org/pgpainless/implementation/BcImplementationFactory.java b/pgpainless-core/src/main/java/org/pgpainless/implementation/BcImplementationFactory.java index 67cc6881..c8e20521 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/implementation/BcImplementationFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/implementation/BcImplementationFactory.java @@ -58,7 +58,7 @@ public class BcImplementationFactory extends ImplementationFactory { int keyEncryptionAlgorithm = secretKey.getKeyEncryptionAlgorithm(); if (secretKey.getS2K() == null) { - return getPBESecretKeyEncryptor(SymmetricKeyAlgorithm.fromId(keyEncryptionAlgorithm), passphrase); + return getPBESecretKeyEncryptor(SymmetricKeyAlgorithm.requireFromId(keyEncryptionAlgorithm), passphrase); } int hashAlgorithm = secretKey.getS2K().getHashAlgorithm(); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyInfo.java b/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyInfo.java index a37eda24..d1a5f748 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyInfo.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyInfo.java @@ -65,7 +65,7 @@ public class KeyInfo { } public static String getCurveName(PGPPublicKey publicKey) { - PublicKeyAlgorithm algorithm = PublicKeyAlgorithm.fromId(publicKey.getAlgorithm()); + PublicKeyAlgorithm algorithm = PublicKeyAlgorithm.requireFromId(publicKey.getAlgorithm()); ECPublicBCPGKey key; switch (algorithm) { case ECDSA: { diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyRingInfo.java b/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyRingInfo.java index 971d5a8e..f1611aff 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyRingInfo.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyRingInfo.java @@ -567,8 +567,9 @@ public class KeyRingInfo { * * @return public key algorithm */ + @Nonnull public PublicKeyAlgorithm getAlgorithm() { - return PublicKeyAlgorithm.fromId(getPublicKey().getAlgorithm()); + return PublicKeyAlgorithm.requireFromId(getPublicKey().getAlgorithm()); } /** diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java index 7eb5a92f..f5a5292c 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java @@ -272,11 +272,11 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { KeyFlag... additionalKeyFlags) throws PGPException, IOException, NoSuchAlgorithmException { KeyFlag[] flags = concat(keyFlag, additionalKeyFlags); - PublicKeyAlgorithm subkeyAlgorithm = PublicKeyAlgorithm.fromId(subkey.getPublicKey().getAlgorithm()); + PublicKeyAlgorithm subkeyAlgorithm = PublicKeyAlgorithm.requireFromId(subkey.getPublicKey().getAlgorithm()); SignatureSubpacketsUtil.assureKeyCanCarryFlags(subkeyAlgorithm); // check key against public key algorithm policy - PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.fromId(subkey.getPublicKey().getAlgorithm()); + PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.requireFromId(subkey.getPublicKey().getAlgorithm()); int bitStrength = subkey.getPublicKey().getBitStrength(); if (!PGPainless.getPolicy().getPublicKeyAlgorithmPolicy().isAcceptable(publicKeyAlgorithm, bitStrength)) { throw new IllegalArgumentException("Public key algorithm policy violation: " + @@ -285,7 +285,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { PGPSecretKey primaryKey = secretKeyRing.getSecretKey(); KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing); - PublicKeyAlgorithm signingKeyAlgorithm = PublicKeyAlgorithm.fromId(primaryKey.getPublicKey().getAlgorithm()); + PublicKeyAlgorithm signingKeyAlgorithm = PublicKeyAlgorithm.requireFromId(primaryKey.getPublicKey().getAlgorithm()); HashAlgorithm hashAlgorithm = HashAlgorithmNegotiator .negotiateSignatureHashAlgorithm(PGPainless.getPolicy()) .negotiateHashAlgorithm(info.getPreferredHashAlgorithms()); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/util/OpenPgpKeyAttributeUtil.java b/pgpainless-core/src/main/java/org/pgpainless/key/util/OpenPgpKeyAttributeUtil.java index a775bc08..e97a2d7a 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/util/OpenPgpKeyAttributeUtil.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/util/OpenPgpKeyAttributeUtil.java @@ -42,7 +42,10 @@ public final class OpenPgpKeyAttributeUtil { continue; } for (int h : hashAlgos) { - hashAlgorithms.add(HashAlgorithm.fromId(h)); + HashAlgorithm algorithm = HashAlgorithm.fromId(h); + if (algorithm != null) { + hashAlgorithms.add(algorithm); + } } // Exit the loop after the first key signature with hash algorithms. break; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/util/PublicKeyParameterValidationUtil.java b/pgpainless-core/src/main/java/org/pgpainless/key/util/PublicKeyParameterValidationUtil.java index 5ee8135b..fbddb080 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/util/PublicKeyParameterValidationUtil.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/util/PublicKeyParameterValidationUtil.java @@ -42,7 +42,7 @@ public class PublicKeyParameterValidationUtil { public static void verifyPublicKeyParameterIntegrity(PGPPrivateKey privateKey, PGPPublicKey publicKey) throws KeyIntegrityException { - PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.fromId(publicKey.getAlgorithm()); + PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.requireFromId(publicKey.getAlgorithm()); boolean valid = true; // Algorithm specific validations @@ -97,7 +97,7 @@ public class PublicKeyParameterValidationUtil { */ private static boolean verifyCanSign(PGPPrivateKey privateKey, PGPPublicKey publicKey) { SecureRandom random = new SecureRandom(); - PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.fromId(publicKey.getAlgorithm()); + PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.requireFromId(publicKey.getAlgorithm()); PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator( ImplementationFactory.getInstance().getPGPContentSignerBuilder(publicKeyAlgorithm, HashAlgorithm.SHA256) ); diff --git a/pgpainless-core/src/main/java/org/pgpainless/policy/Policy.java b/pgpainless-core/src/main/java/org/pgpainless/policy/Policy.java index 58d6f6a2..e64899c0 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/policy/Policy.java +++ b/pgpainless-core/src/main/java/org/pgpainless/policy/Policy.java @@ -9,6 +9,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import javax.annotation.Nonnull; @@ -232,8 +233,13 @@ public final class Policy { * @return true if algorithm is acceptable, false otherwise */ public boolean isAcceptable(int algorithmId) { - SymmetricKeyAlgorithm algorithm = SymmetricKeyAlgorithm.fromId(algorithmId); - return isAcceptable(algorithm); + try { + SymmetricKeyAlgorithm algorithm = SymmetricKeyAlgorithm.requireFromId(algorithmId); + return isAcceptable(algorithm); + } catch (NoSuchElementException e) { + // Unknown algorithm is not acceptable + return false; + } } /** @@ -329,8 +335,13 @@ public final class Policy { * @return true if the hash algorithm is acceptable, false otherwise */ public boolean isAcceptable(int algorithmId) { - HashAlgorithm algorithm = HashAlgorithm.fromId(algorithmId); - return isAcceptable(algorithm); + try { + HashAlgorithm algorithm = HashAlgorithm.requireFromId(algorithmId); + return isAcceptable(algorithm); + } catch (NoSuchElementException e) { + // Unknown algorithm is not acceptable + return false; + } } /** @@ -382,7 +393,13 @@ public final class Policy { } public boolean isAcceptable(int compressionAlgorithmTag) { - return isAcceptable(CompressionAlgorithm.fromId(compressionAlgorithmTag)); + try { + CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.requireFromId(compressionAlgorithmTag); + return isAcceptable(compressionAlgorithm); + } catch (NoSuchElementException e) { + // Unknown algorithm is not acceptable + return false; + } } public boolean isAcceptable(CompressionAlgorithm compressionAlgorithm) { @@ -408,7 +425,13 @@ public final class Policy { } public boolean isAcceptable(int algorithmId, int bitStrength) { - return isAcceptable(PublicKeyAlgorithm.fromId(algorithmId), bitStrength); + try { + PublicKeyAlgorithm algorithm = PublicKeyAlgorithm.requireFromId(algorithmId); + return isAcceptable(algorithm, bitStrength); + } catch (NoSuchElementException e) { + // Unknown algorithm is not acceptable + return false; + } } public boolean isAcceptable(PublicKeyAlgorithm algorithm, int bitStrength) { diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/consumer/SignatureValidator.java b/pgpainless-core/src/main/java/org/pgpainless/signature/consumer/SignatureValidator.java index a8f1ec5b..3572fff0 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/consumer/SignatureValidator.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/consumer/SignatureValidator.java @@ -9,6 +9,7 @@ import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import org.bouncycastle.bcpg.sig.KeyFlags; @@ -92,7 +93,7 @@ public abstract class SignatureValidator { return new SignatureValidator() { @Override public void verify(PGPSignature signature) throws SignatureValidationException { - if (!PublicKeyAlgorithm.fromId(signature.getKeyAlgorithm()).isSigningCapable()) { + if (!PublicKeyAlgorithm.requireFromId(signature.getKeyAlgorithm()).isSigningCapable()) { // subkey is not signing capable -> No need to process embedded sigs return; } @@ -168,7 +169,7 @@ public abstract class SignatureValidator { return new SignatureValidator() { @Override public void verify(PGPSignature signature) throws SignatureValidationException { - PublicKeyAlgorithm algorithm = PublicKeyAlgorithm.fromId(signingKey.getAlgorithm()); + PublicKeyAlgorithm algorithm = PublicKeyAlgorithm.requireFromId(signingKey.getAlgorithm()); int bitStrength = signingKey.getBitStrength(); if (bitStrength == -1) { throw new SignatureValidationException("Cannot determine bit strength of signing key."); @@ -191,11 +192,14 @@ public abstract class SignatureValidator { return new SignatureValidator() { @Override public void verify(PGPSignature signature) throws SignatureValidationException { - HashAlgorithm hashAlgorithm = HashAlgorithm.fromId(signature.getHashAlgorithm()); - Policy.HashAlgorithmPolicy hashAlgorithmPolicy = getHashAlgorithmPolicyForSignature(signature, policy); - - if (!hashAlgorithmPolicy.isAcceptable(signature.getHashAlgorithm())) { - throw new SignatureValidationException("Signature uses unacceptable hash algorithm " + hashAlgorithm); + try { + HashAlgorithm hashAlgorithm = HashAlgorithm.requireFromId(signature.getHashAlgorithm()); + Policy.HashAlgorithmPolicy hashAlgorithmPolicy = getHashAlgorithmPolicyForSignature(signature, policy); + if (!hashAlgorithmPolicy.isAcceptable(signature.getHashAlgorithm())) { + throw new SignatureValidationException("Signature uses unacceptable hash algorithm " + hashAlgorithm); + } + } catch (NoSuchElementException e) { + throw new SignatureValidationException("Signature uses unknown hash algorithm " + signature.getHashAlgorithm()); } } }; @@ -255,8 +259,8 @@ public abstract class SignatureValidator { PGPSignatureSubpacketVector hashedSubpackets = signature.getHashedSubPackets(); for (int criticalTag : hashedSubpackets.getCriticalTags()) { try { - SignatureSubpacket.fromCode(criticalTag); - } catch (IllegalArgumentException e) { + SignatureSubpacket.requireFromCode(criticalTag); + } catch (NoSuchElementException e) { throw new SignatureValidationException("Signature contains unknown critical subpacket of type " + Long.toHexString(criticalTag)); } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java index ee34a6fc..2118c49c 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java @@ -33,7 +33,7 @@ public class SignatureSubpacketsHelper { public static SignatureSubpackets applyFrom(PGPSignatureSubpacketVector vector, SignatureSubpackets subpackets) { for (SignatureSubpacket subpacket : vector.toArray()) { - org.pgpainless.algorithm.SignatureSubpacket type = org.pgpainless.algorithm.SignatureSubpacket.fromCode(subpacket.getType()); + org.pgpainless.algorithm.SignatureSubpacket type = org.pgpainless.algorithm.SignatureSubpacket.requireFromCode(subpacket.getType()); switch (type) { case signatureCreationTime: case issuerKeyId: @@ -102,8 +102,8 @@ public class SignatureSubpacketsHelper { case signatureTarget: SignatureTarget target = (SignatureTarget) subpacket; subpackets.setSignatureTarget(target.isCritical(), - PublicKeyAlgorithm.fromId(target.getPublicKeyAlgorithm()), - HashAlgorithm.fromId(target.getHashAlgorithm()), + PublicKeyAlgorithm.requireFromId(target.getPublicKeyAlgorithm()), + HashAlgorithm.requireFromId(target.getHashAlgorithm()), target.getHashData()); break; case embeddedSignature: diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsUtil.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsUtil.java index bbf8972b..12c6f1de 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsUtil.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsUtil.java @@ -257,7 +257,10 @@ public final class SignatureSubpacketsUtil { PreferredAlgorithms preferences = getPreferredSymmetricAlgorithms(signature); if (preferences != null) { for (int code : preferences.getPreferences()) { - algorithms.add(SymmetricKeyAlgorithm.fromId(code)); + SymmetricKeyAlgorithm algorithm = SymmetricKeyAlgorithm.fromId(code); + if (algorithm != null) { + algorithms.add(algorithm); + } } } return algorithms; @@ -286,7 +289,10 @@ public final class SignatureSubpacketsUtil { PreferredAlgorithms preferences = getPreferredHashAlgorithms(signature); if (preferences != null) { for (int code : preferences.getPreferences()) { - algorithms.add(HashAlgorithm.fromId(code)); + HashAlgorithm algorithm = HashAlgorithm.fromId(code); + if (algorithm != null) { + algorithms.add(algorithm); + } } } return algorithms; @@ -315,7 +321,10 @@ public final class SignatureSubpacketsUtil { PreferredAlgorithms preferences = getPreferredCompressionAlgorithms(signature); if (preferences != null) { for (int code : preferences.getPreferences()) { - algorithms.add(CompressionAlgorithm.fromId(code)); + CompressionAlgorithm algorithm = CompressionAlgorithm.fromId(code); + if (algorithm != null) { + algorithms.add(algorithm); + } } } return algorithms; diff --git a/pgpainless-core/src/main/java/org/pgpainless/util/SessionKey.java b/pgpainless-core/src/main/java/org/pgpainless/util/SessionKey.java index 72bab826..397e1f0a 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/util/SessionKey.java +++ b/pgpainless-core/src/main/java/org/pgpainless/util/SessionKey.java @@ -24,7 +24,7 @@ public class SessionKey { * @param sessionKey BC session key */ public SessionKey(@Nonnull PGPSessionKey sessionKey) { - this(SymmetricKeyAlgorithm.fromId(sessionKey.getAlgorithm()), sessionKey.getKey()); + this(SymmetricKeyAlgorithm.requireFromId(sessionKey.getAlgorithm()), sessionKey.getKey()); } /** diff --git a/pgpainless-core/src/test/java/org/pgpainless/algorithm/FeatureTest.java b/pgpainless-core/src/test/java/org/pgpainless/algorithm/FeatureTest.java index 347322f8..e9d0b86e 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/algorithm/FeatureTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/algorithm/FeatureTest.java @@ -6,20 +6,37 @@ package org.pgpainless.algorithm; import org.junit.jupiter.api.Test; +import java.util.NoSuchElementException; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; public class FeatureTest { + @Test + public void testAll() { + for (Feature feature : Feature.values()) { + assertEquals(feature, Feature.fromId(feature.getFeatureId())); + assertEquals(feature, Feature.requireFromId(feature.getFeatureId())); + } + } + @Test public void testModificationDetection() { Feature modificationDetection = Feature.MODIFICATION_DETECTION; assertEquals(0x01, modificationDetection.getFeatureId()); assertEquals(modificationDetection, Feature.fromId((byte) 0x01)); + assertEquals(modificationDetection, Feature.requireFromId((byte) 0x01)); } @Test public void testFromInvalidIdIsNull() { assertNull(Feature.fromId((byte) 0x99)); } + + @Test + public void testRequireFromInvalidThrows() { + assertThrows(NoSuchElementException.class, () -> Feature.requireFromId((byte) 0x99)); + } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/signature/SignatureStructureTest.java b/pgpainless-core/src/test/java/org/pgpainless/signature/SignatureStructureTest.java index 84eecdb5..cf118822 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/signature/SignatureStructureTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/signature/SignatureStructureTest.java @@ -64,7 +64,7 @@ public class SignatureStructureTest { @Test public void testGetHashAlgorithm() { - assertEquals(HashAlgorithm.SHA256, HashAlgorithm.fromId(signature.getHashAlgorithm())); + assertEquals(HashAlgorithm.SHA256, HashAlgorithm.requireFromId(signature.getHashAlgorithm())); } @Test diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/DecryptImpl.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/DecryptImpl.java index bef260c4..38656c9b 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/DecryptImpl.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/DecryptImpl.java @@ -70,7 +70,7 @@ public class DecryptImpl implements Decrypt { public DecryptImpl withSessionKey(SessionKey sessionKey) throws SOPGPException.UnsupportedOption { consumerOptions.setSessionKey( new org.pgpainless.util.SessionKey( - SymmetricKeyAlgorithm.fromId(sessionKey.getAlgorithm()), + SymmetricKeyAlgorithm.requireFromId(sessionKey.getAlgorithm()), sessionKey.getKey())); return this; }