From e57e74163c8c860493553b3d110b4261db383cb2 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 23 Aug 2023 13:15:00 +0200 Subject: [PATCH] Finish Policy conversion and move kotlin classes to src/kotlin/ --- .../algorithm/negotiation/package-info.java | 8 - .../pgpainless/algorithm/package-info.java | 8 - .../authentication/package-info.java | 8 - .../java/org/pgpainless/policy/Policy.java | 732 ------------------ .../java/org/pgpainless/policy/Policy2.kt | 132 ---- .../org/pgpainless/policy/package-info.java | 8 - .../org/pgpainless/PGPainless.kt | 4 + .../org/pgpainless/algorithm/AEADAlgorithm.kt | 0 .../pgpainless/algorithm/AlgorithmSuite.kt | 0 .../pgpainless/algorithm/CertificationType.kt | 0 .../algorithm/CompressionAlgorithm.kt | 0 .../algorithm/DocumentSignatureType.kt | 0 .../pgpainless/algorithm/EncryptionPurpose.kt | 0 .../org/pgpainless/algorithm/Feature.kt | 0 .../org/pgpainless/algorithm/HashAlgorithm.kt | 0 .../org/pgpainless/algorithm/KeyFlag.kt | 0 .../org/pgpainless/algorithm/OpenPgpPacket.kt | 0 .../algorithm/PublicKeyAlgorithm.kt | 0 .../pgpainless/algorithm/RevocationState.kt | 0 .../algorithm/RevocationStateType.kt | 0 .../algorithm/SignatureSubpacket.kt | 0 .../org/pgpainless/algorithm/SignatureType.kt | 0 .../pgpainless/algorithm/StreamEncoding.kt | 0 .../algorithm/SymmetricKeyAlgorithm.kt | 0 .../pgpainless/algorithm/Trustworthiness.kt | 0 .../negotiation/HashAlgorithmNegotiator.kt | 0 .../SymmetricKeyAlgorithmNegotiator.kt | 0 .../authentication/CertificateAuthenticity.kt | 0 .../authentication/CertificateAuthority.kt | 0 .../org/pgpainless/key/OpenPgpFingerprint.kt | 4 + .../pgpainless/key/OpenPgpV4Fingerprint.kt | 4 + .../pgpainless/key/OpenPgpV5Fingerprint.kt | 0 .../pgpainless/key/OpenPgpV6Fingerprint.kt | 0 .../org/pgpainless/key/SubkeyIdentifier.kt | 0 .../org/pgpainless/key/_64DigitFingerprint.kt | 0 .../kotlin/org/pgpainless/policy/Policy.kt | 359 +++++++++ 36 files changed, 371 insertions(+), 896 deletions(-) delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/negotiation/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/authentication/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/policy/Policy.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/policy/Policy2.kt delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/policy/package-info.java rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/PGPainless.kt (98%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/AEADAlgorithm.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/AlgorithmSuite.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/CertificationType.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/CompressionAlgorithm.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/DocumentSignatureType.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/EncryptionPurpose.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/Feature.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/HashAlgorithm.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/KeyFlag.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/OpenPgpPacket.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/PublicKeyAlgorithm.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/RevocationState.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/RevocationStateType.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/SignatureSubpacket.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/SignatureType.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/StreamEncoding.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/SymmetricKeyAlgorithm.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/Trustworthiness.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/negotiation/HashAlgorithmNegotiator.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/algorithm/negotiation/SymmetricKeyAlgorithmNegotiator.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/authentication/CertificateAuthenticity.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/authentication/CertificateAuthority.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/key/OpenPgpFingerprint.kt (98%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/key/OpenPgpV4Fingerprint.kt (94%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/key/OpenPgpV5Fingerprint.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/key/OpenPgpV6Fingerprint.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/key/SubkeyIdentifier.kt (100%) rename pgpainless-core/src/main/{java => kotlin}/org/pgpainless/key/_64DigitFingerprint.kt (100%) create mode 100644 pgpainless-core/src/main/kotlin/org/pgpainless/policy/Policy.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/negotiation/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/negotiation/package-info.java deleted file mode 100644 index 3969d8df..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/negotiation/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -/** - * Classes related to algorithm negotiation. - */ -package org.pgpainless.algorithm.negotiation; diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/package-info.java deleted file mode 100644 index c2f5f5ff..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: 2018 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -/** - * Enums which map to OpenPGP's algorithm IDs. - */ -package org.pgpainless.algorithm; diff --git a/pgpainless-core/src/main/java/org/pgpainless/authentication/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/authentication/package-info.java deleted file mode 100644 index 495ab1f7..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/authentication/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -/** - * Classes and interfaces related to certificate authenticity. - */ -package org.pgpainless.authentication; diff --git a/pgpainless-core/src/main/java/org/pgpainless/policy/Policy.java b/pgpainless-core/src/main/java/org/pgpainless/policy/Policy.java deleted file mode 100644 index 35787138..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/policy/Policy.java +++ /dev/null @@ -1,732 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.policy; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; - -import javax.annotation.Nonnull; - -import org.pgpainless.algorithm.AlgorithmSuite; -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.HashAlgorithm; -import org.pgpainless.algorithm.PublicKeyAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.util.DateUtil; -import org.pgpainless.util.NotationRegistry; - -/** - * Policy class used to configure acceptable algorithm suites etc. - */ -public final class Policy { - - private static Policy INSTANCE; - - private HashAlgorithmPolicy signatureHashAlgorithmPolicy = - HashAlgorithmPolicy.smartSignatureHashAlgorithmPolicy(); - private HashAlgorithmPolicy revocationSignatureHashAlgorithmPolicy = - HashAlgorithmPolicy.smartSignatureHashAlgorithmPolicy(); - private SymmetricKeyAlgorithmPolicy symmetricKeyEncryptionAlgorithmPolicy = - SymmetricKeyAlgorithmPolicy.symmetricKeyEncryptionPolicy2022(); - private SymmetricKeyAlgorithmPolicy symmetricKeyDecryptionAlgorithmPolicy = - SymmetricKeyAlgorithmPolicy.symmetricKeyDecryptionPolicy2022(); - private CompressionAlgorithmPolicy compressionAlgorithmPolicy = - CompressionAlgorithmPolicy.anyCompressionAlgorithmPolicy(); - private PublicKeyAlgorithmPolicy publicKeyAlgorithmPolicy = - PublicKeyAlgorithmPolicy.bsi2021PublicKeyAlgorithmPolicy(); - private final NotationRegistry notationRegistry = new NotationRegistry(); - - private AlgorithmSuite keyGenerationAlgorithmSuite = AlgorithmSuite.getDefaultAlgorithmSuite(); - - // Signers User-ID is soon to be deprecated. - private SignerUserIdValidationLevel signerUserIdValidationLevel = SignerUserIdValidationLevel.DISABLED; - - private boolean enableKeyParameterValidation = false; - - public enum SignerUserIdValidationLevel { - /** - * PGPainless will verify {@link org.bouncycastle.bcpg.sig.SignerUserID} subpackets in signatures strictly. - * This means, that signatures with Signer's User-ID subpackets containing a value that does not match the signer key's - * user-id exactly, will be rejected. - * E.g. Signer's user-id "alice@pgpainless.org", User-ID: "Alice <alice@pgpainless.org>" does not - * match exactly and is therefore rejected. - */ - STRICT, - - /** - * PGPainless will ignore {@link org.bouncycastle.bcpg.sig.SignerUserID} subpackets on signature. - */ - DISABLED - } - - Policy() { - } - - /** - * Return the singleton instance of PGPainless' policy. - * - * @return singleton instance - */ - public static Policy getInstance() { - if (INSTANCE == null) { - INSTANCE = new Policy(); - } - return INSTANCE; - } - - /** - * Return the hash algorithm policy for signatures. - * @return hash algorithm policy - */ - public HashAlgorithmPolicy getSignatureHashAlgorithmPolicy() { - return signatureHashAlgorithmPolicy; - } - - /** - * Set a custom hash algorithm policy for signatures. - * - * @param policy custom policy - */ - public void setSignatureHashAlgorithmPolicy(HashAlgorithmPolicy policy) { - if (policy == null) { - throw new NullPointerException("Policy cannot be null."); - } - this.signatureHashAlgorithmPolicy = policy; - } - - /** - * Return the hash algorithm policy for revocations. - * This policy is separate from {@link #getSignatureHashAlgorithmPolicy()}, as PGPainless by default uses a - * less strict policy when it comes to acceptable algorithms. - * - * @return revocation signature hash algorithm policy - */ - public HashAlgorithmPolicy getRevocationSignatureHashAlgorithmPolicy() { - return revocationSignatureHashAlgorithmPolicy; - } - - /** - * Set a custom hash algorithm policy for revocations. - * - * @param policy custom policy - */ - public void setRevocationSignatureHashAlgorithmPolicy(HashAlgorithmPolicy policy) { - if (policy == null) { - throw new NullPointerException("Policy cannot be null."); - } - this.revocationSignatureHashAlgorithmPolicy = policy; - } - - /** - * Return the symmetric encryption algorithm policy for encryption. - * This policy defines which symmetric algorithms are acceptable when producing encrypted messages. - * - * @return symmetric algorithm policy for encryption - */ - public SymmetricKeyAlgorithmPolicy getSymmetricKeyEncryptionAlgorithmPolicy() { - return symmetricKeyEncryptionAlgorithmPolicy; - } - - /** - * Return the symmetric encryption algorithm policy for decryption. - * This policy defines which symmetric algorithms are acceptable when decrypting encrypted messages. - * - * @return symmetric algorithm policy for decryption - */ - public SymmetricKeyAlgorithmPolicy getSymmetricKeyDecryptionAlgorithmPolicy() { - return symmetricKeyDecryptionAlgorithmPolicy; - } - - /** - * Set a custom symmetric encryption algorithm policy for encrypting messages. - * - * @param policy custom policy - */ - public void setSymmetricKeyEncryptionAlgorithmPolicy(SymmetricKeyAlgorithmPolicy policy) { - if (policy == null) { - throw new NullPointerException("Policy cannot be null."); - } - this.symmetricKeyEncryptionAlgorithmPolicy = policy; - } - - /** - * Set a custom symmetric encryption algorithm policy for decrypting messages. - * - * @param policy custom policy - */ - public void setSymmetricKeyDecryptionAlgorithmPolicy(SymmetricKeyAlgorithmPolicy policy) { - if (policy == null) { - throw new NullPointerException("Policy cannot be null."); - } - this.symmetricKeyDecryptionAlgorithmPolicy = policy; - } - - public CompressionAlgorithmPolicy getCompressionAlgorithmPolicy() { - return compressionAlgorithmPolicy; - } - - public void setCompressionAlgorithmPolicy(CompressionAlgorithmPolicy policy) { - if (policy == null) { - throw new NullPointerException("Compression policy cannot be null."); - } - this.compressionAlgorithmPolicy = policy; - } - - /** - * Return the current public key algorithm policy. - * - * @return public key algorithm policy - */ - public PublicKeyAlgorithmPolicy getPublicKeyAlgorithmPolicy() { - return publicKeyAlgorithmPolicy; - } - - /** - * Set a custom public key algorithm policy. - * - * @param publicKeyAlgorithmPolicy custom policy - */ - public void setPublicKeyAlgorithmPolicy(PublicKeyAlgorithmPolicy publicKeyAlgorithmPolicy) { - if (publicKeyAlgorithmPolicy == null) { - throw new NullPointerException("Public key algorithm policy cannot be null."); - } - this.publicKeyAlgorithmPolicy = publicKeyAlgorithmPolicy; - } - - public static final class SymmetricKeyAlgorithmPolicy { - - private final SymmetricKeyAlgorithm defaultSymmetricKeyAlgorithm; - private final List acceptableSymmetricKeyAlgorithms; - - public SymmetricKeyAlgorithmPolicy(SymmetricKeyAlgorithm defaultSymmetricKeyAlgorithm, List acceptableSymmetricKeyAlgorithms) { - this.defaultSymmetricKeyAlgorithm = defaultSymmetricKeyAlgorithm; - this.acceptableSymmetricKeyAlgorithms = Collections.unmodifiableList(acceptableSymmetricKeyAlgorithms); - } - - /** - * Return the default symmetric key algorithm. - * This algorithm is used as a fallback when no consensus about symmetric algorithms can be reached. - * - * @return default symmetric encryption algorithm - */ - public SymmetricKeyAlgorithm getDefaultSymmetricKeyAlgorithm() { - return defaultSymmetricKeyAlgorithm; - } - - /** - * Return true if the given symmetric encryption algorithm is acceptable by this policy. - * - * @param algorithm algorithm - * @return true if algorithm is acceptable, false otherwise - */ - public boolean isAcceptable(SymmetricKeyAlgorithm algorithm) { - return acceptableSymmetricKeyAlgorithms.contains(algorithm); - } - - /** - * Return true if the given symmetric encryption algorithm is acceptable by this policy. - * - * @param algorithmId algorithm - * @return true if algorithm is acceptable, false otherwise - */ - public boolean isAcceptable(int algorithmId) { - try { - SymmetricKeyAlgorithm algorithm = SymmetricKeyAlgorithm.requireFromId(algorithmId); - return isAcceptable(algorithm); - } catch (NoSuchElementException e) { - // Unknown algorithm is not acceptable - return false; - } - } - - /** - * The default symmetric encryption algorithm policy of PGPainless. - * - * @return default symmetric encryption algorithm policy - * @deprecated not expressive - will be removed in a future release - */ - @Deprecated - public static SymmetricKeyAlgorithmPolicy defaultSymmetricKeyEncryptionAlgorithmPolicy() { - return symmetricKeyEncryptionPolicy2022(); - } - - /** - * Policy for symmetric encryption algorithms in the context of message production (encryption). - * This suite contains algorithms that are deemed safe to use in 2022. - * - * @return 2022 symmetric key encryption algorithm policy - */ - public static SymmetricKeyAlgorithmPolicy symmetricKeyEncryptionPolicy2022() { - return new SymmetricKeyAlgorithmPolicy(SymmetricKeyAlgorithm.AES_128, Arrays.asList( - // Reject: Unencrypted, IDEA, TripleDES, CAST5, Blowfish - SymmetricKeyAlgorithm.AES_256, - SymmetricKeyAlgorithm.AES_192, - SymmetricKeyAlgorithm.AES_128, - SymmetricKeyAlgorithm.TWOFISH, - SymmetricKeyAlgorithm.CAMELLIA_256, - SymmetricKeyAlgorithm.CAMELLIA_192, - SymmetricKeyAlgorithm.CAMELLIA_128 - )); - } - - /** - * The default symmetric decryption algorithm policy of PGPainless. - * - * @return default symmetric decryption algorithm policy - * @deprecated not expressive - will be removed in a future update - */ - @Deprecated - public static SymmetricKeyAlgorithmPolicy defaultSymmetricKeyDecryptionAlgorithmPolicy() { - return symmetricKeyDecryptionPolicy2022(); - } - - /** - * Policy for symmetric key encryption algorithms in the context of message consumption (decryption). - * This suite contains algorithms that are deemed safe to use in 2022. - * - * @return 2022 symmetric key decryption algorithm policy - */ - public static SymmetricKeyAlgorithmPolicy symmetricKeyDecryptionPolicy2022() { - return new SymmetricKeyAlgorithmPolicy(SymmetricKeyAlgorithm.AES_128, Arrays.asList( - // Reject: Unencrypted, IDEA, TripleDES, Blowfish - SymmetricKeyAlgorithm.CAST5, - SymmetricKeyAlgorithm.AES_256, - SymmetricKeyAlgorithm.AES_192, - SymmetricKeyAlgorithm.AES_128, - SymmetricKeyAlgorithm.TWOFISH, - SymmetricKeyAlgorithm.CAMELLIA_256, - SymmetricKeyAlgorithm.CAMELLIA_192, - SymmetricKeyAlgorithm.CAMELLIA_128 - )); - } - - /** - * Select the best acceptable algorithm from the options list. - * The best algorithm is the first algorithm we encounter in our list of acceptable algorithms that - * is also contained in the list of options. - * - * - * @param options list of algorithm options - * @return best - */ - public SymmetricKeyAlgorithm selectBest(List options) { - for (SymmetricKeyAlgorithm acceptable : acceptableSymmetricKeyAlgorithms) { - if (options.contains(acceptable)) { - return acceptable; - } - } - return null; - } - } - - public static final class HashAlgorithmPolicy { - - private final HashAlgorithm defaultHashAlgorithm; - private final Map acceptableHashAlgorithmsAndTerminationDates; - - /** - * Create a {@link HashAlgorithmPolicy} which accepts all {@link HashAlgorithm HashAlgorithms} from the - * given map, if the queried usage date is BEFORE the respective termination date. - * A termination date value of
null
means no termination, resulting in the algorithm being - * acceptable, regardless of usage date. - * - * @param defaultHashAlgorithm default hash algorithm - * @param algorithmTerminationDates map of acceptable algorithms and their termination dates - */ - public HashAlgorithmPolicy(@Nonnull HashAlgorithm defaultHashAlgorithm, @Nonnull Map algorithmTerminationDates) { - this.defaultHashAlgorithm = defaultHashAlgorithm; - this.acceptableHashAlgorithmsAndTerminationDates = algorithmTerminationDates; - } - - /** - * Create a {@link HashAlgorithmPolicy} which accepts all {@link HashAlgorithm HashAlgorithms} listed in - * the given list, regardless of usage date. - * - * @param defaultHashAlgorithm default hash algorithm (e.g. used as fallback if negotiation fails) - * @param acceptableHashAlgorithms list of acceptable hash algorithms - */ - public HashAlgorithmPolicy(@Nonnull HashAlgorithm defaultHashAlgorithm, @Nonnull List acceptableHashAlgorithms) { - this(defaultHashAlgorithm, Collections.unmodifiableMap(listToMap(acceptableHashAlgorithms))); - } - - private static Map listToMap(@Nonnull List algorithms) { - Map algorithmsAndTerminationDates = new HashMap<>(); - for (HashAlgorithm algorithm : algorithms) { - algorithmsAndTerminationDates.put(algorithm, null); - } - return algorithmsAndTerminationDates; - } - - /** - * Return the default hash algorithm. - * This algorithm is used as a fallback when no consensus about hash algorithms can be reached. - * - * @return default hash algorithm - */ - public HashAlgorithm defaultHashAlgorithm() { - return defaultHashAlgorithm; - } - - /** - * Return true if the given hash algorithm is currently acceptable by this policy. - * - * @param hashAlgorithm hash algorithm - * @return true if the hash algorithm is acceptable, false otherwise - */ - public boolean isAcceptable(@Nonnull HashAlgorithm hashAlgorithm) { - return isAcceptable(hashAlgorithm, new Date()); - } - - /** - * Return true if the given hash algorithm is currently acceptable by this policy. - * - * @param algorithmId hash algorithm - * @return true if the hash algorithm is acceptable, false otherwise - */ - public boolean isAcceptable(int algorithmId) { - try { - HashAlgorithm algorithm = HashAlgorithm.requireFromId(algorithmId); - return isAcceptable(algorithm); - } catch (NoSuchElementException e) { - // Unknown algorithm is not acceptable - return false; - } - } - - /** - * Return true, if the given algorithm is acceptable for the given usage date. - * - * @param hashAlgorithm algorithm - * @param usageDate usage date (e.g. signature creation time) - * - * @return acceptance - */ - public boolean isAcceptable(@Nonnull HashAlgorithm hashAlgorithm, @Nonnull Date usageDate) { - if (!acceptableHashAlgorithmsAndTerminationDates.containsKey(hashAlgorithm)) { - return false; - } - - // Check termination date - Date terminationDate = acceptableHashAlgorithmsAndTerminationDates.get(hashAlgorithm); - if (terminationDate == null) { - return true; - } - - // Reject if usage date is past termination date - return terminationDate.after(usageDate); - } - - public boolean isAcceptable(int algorithmId, @Nonnull Date usageDate) { - try { - HashAlgorithm algorithm = HashAlgorithm.requireFromId(algorithmId); - return isAcceptable(algorithm, usageDate); - } catch (NoSuchElementException e) { - // Unknown algorithm is not acceptable - return false; - } - } - - /** - * The default signature hash algorithm policy of PGPainless. - * Note that this policy is only used for non-revocation signatures. - * For revocation signatures {@link #defaultRevocationSignatureHashAlgorithmPolicy()} is used instead. - * - * @return default signature hash algorithm policy - * @deprecated not expressive - will be removed in an upcoming release - */ - @Deprecated - public static HashAlgorithmPolicy defaultSignatureAlgorithmPolicy() { - return smartSignatureHashAlgorithmPolicy(); - } - - /** - * {@link HashAlgorithmPolicy} which takes the date of the algorithm usage into consideration. - * If the policy has a termination date for a given algorithm, and the usage date is after that termination - * date, the algorithm is rejected. - * - * This policy is inspired by Sequoia-PGP's collision resistant algorithm policy. - * - * @see Sequoia-PGP's Collision Resistant Algorithm Policy - * - * @return smart signature algorithm policy - */ - public static HashAlgorithmPolicy smartSignatureHashAlgorithmPolicy() { - Map algorithmDateMap = new HashMap<>(); - - algorithmDateMap.put(HashAlgorithm.MD5, DateUtil.parseUTCDate("1997-02-01 00:00:00 UTC")); - algorithmDateMap.put(HashAlgorithm.SHA1, DateUtil.parseUTCDate("2013-02-01 00:00:00 UTC")); - algorithmDateMap.put(HashAlgorithm.RIPEMD160, DateUtil.parseUTCDate("2013-02-01 00:00:00 UTC")); - algorithmDateMap.put(HashAlgorithm.SHA224, null); - algorithmDateMap.put(HashAlgorithm.SHA256, null); - algorithmDateMap.put(HashAlgorithm.SHA384, null); - algorithmDateMap.put(HashAlgorithm.SHA512, null); - - return new HashAlgorithmPolicy(HashAlgorithm.SHA512, algorithmDateMap); - } - - /** - * {@link HashAlgorithmPolicy} which only accepts signatures made using algorithms which are acceptable - * according to 2022 standards. - * - * Particularly this policy only accepts algorithms from the SHA2 family. - * - * @return static signature algorithm policy - */ - public static HashAlgorithmPolicy static2022SignatureHashAlgorithmPolicy() { - return new HashAlgorithmPolicy(HashAlgorithm.SHA512, Arrays.asList( - HashAlgorithm.SHA224, - HashAlgorithm.SHA256, - HashAlgorithm.SHA384, - HashAlgorithm.SHA512 - )); - } - - /** - * The default revocation signature hash algorithm policy of PGPainless. - * - * @return default revocation signature hash algorithm policy - * @deprecated not expressive - will be removed in an upcoming release - */ - @Deprecated - public static HashAlgorithmPolicy defaultRevocationSignatureHashAlgorithmPolicy() { - return smartSignatureHashAlgorithmPolicy(); - } - - /** - * Hash algorithm policy for revocation signatures, which accepts SHA1 and SHA2 algorithms, as well as RIPEMD160. - * - * @return static revocation signature hash algorithm policy - */ - public static HashAlgorithmPolicy static2022RevocationSignatureHashAlgorithmPolicy() { - return new HashAlgorithmPolicy(HashAlgorithm.SHA512, Arrays.asList( - HashAlgorithm.RIPEMD160, - HashAlgorithm.SHA1, - HashAlgorithm.SHA224, - HashAlgorithm.SHA256, - HashAlgorithm.SHA384, - HashAlgorithm.SHA512 - )); - } - } - - public static final class CompressionAlgorithmPolicy { - - private final CompressionAlgorithm defaultCompressionAlgorithm; - private final List acceptableCompressionAlgorithms; - - public CompressionAlgorithmPolicy(CompressionAlgorithm defaultCompressionAlgorithm, - List acceptableCompressionAlgorithms) { - this.defaultCompressionAlgorithm = defaultCompressionAlgorithm; - this.acceptableCompressionAlgorithms = Collections.unmodifiableList(acceptableCompressionAlgorithms); - } - - public CompressionAlgorithm defaultCompressionAlgorithm() { - return defaultCompressionAlgorithm; - } - - public boolean isAcceptable(int 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) { - return acceptableCompressionAlgorithms.contains(compressionAlgorithm); - } - - /** - * Default {@link CompressionAlgorithmPolicy} of PGPainless. - * The default compression algorithm policy accepts any compression algorithm. - * - * @return default algorithm policy - * @deprecated not expressive - might be removed in a future release - */ - @Deprecated - public static CompressionAlgorithmPolicy defaultCompressionAlgorithmPolicy() { - return anyCompressionAlgorithmPolicy(); - } - - /** - * Policy that accepts any known compression algorithm and offers {@link CompressionAlgorithm#ZIP} as - * default algorithm. - * - * @return compression algorithm policy - */ - public static CompressionAlgorithmPolicy anyCompressionAlgorithmPolicy() { - return new CompressionAlgorithmPolicy(CompressionAlgorithm.ZIP, Arrays.asList( - CompressionAlgorithm.UNCOMPRESSED, - CompressionAlgorithm.ZIP, - CompressionAlgorithm.BZIP2, - CompressionAlgorithm.ZLIB - )); - } - } - - public static final class PublicKeyAlgorithmPolicy { - - private final Map algorithmStrengths = new EnumMap<>(PublicKeyAlgorithm.class); - - public PublicKeyAlgorithmPolicy(Map minimalAlgorithmBitStrengths) { - this.algorithmStrengths.putAll(minimalAlgorithmBitStrengths); - } - - public boolean isAcceptable(int algorithmId, int 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) { - if (!algorithmStrengths.containsKey(algorithm)) { - return false; - } - - int minStrength = algorithmStrengths.get(algorithm); - return bitStrength >= minStrength; - } - - /** - * Return PGPainless' default public key algorithm policy. - * This policy is based upon recommendations made by the German Federal Office for Information Security (BSI). - * - * @return default algorithm policy - * @deprecated not expressive - might be removed in a future release - */ - @Deprecated - public static PublicKeyAlgorithmPolicy defaultPublicKeyAlgorithmPolicy() { - return bsi2021PublicKeyAlgorithmPolicy(); - } - - /** - * This policy is based upon recommendations made by the German Federal Office for Information Security (BSI). - * - * Basically this policy requires keys based on elliptic curves to have a bit strength of at least 250, - * and keys based on prime number factorization / discrete logarithm problems to have a strength of at least 2000 bits. - * - * @see BSI - Technical Guideline - Cryptographic Mechanisms: Recommendations and Key Lengths (2021-01) - * @see BlueKrypt | Cryptographic Key Length Recommendation - * - * @return default algorithm policy - */ - public static PublicKeyAlgorithmPolicy bsi2021PublicKeyAlgorithmPolicy() { - Map minimalBitStrengths = new EnumMap<>(PublicKeyAlgorithm.class); - // §5.4.1 - minimalBitStrengths.put(PublicKeyAlgorithm.RSA_GENERAL, 2000); - minimalBitStrengths.put(PublicKeyAlgorithm.RSA_SIGN, 2000); - minimalBitStrengths.put(PublicKeyAlgorithm.RSA_ENCRYPT, 2000); - // Note: ElGamal is not mentioned in the BSI document. - // We assume that the requirements are similar to other DH algorithms - minimalBitStrengths.put(PublicKeyAlgorithm.ELGAMAL_ENCRYPT, 2000); - minimalBitStrengths.put(PublicKeyAlgorithm.ELGAMAL_GENERAL, 2000); - // §5.4.2 - minimalBitStrengths.put(PublicKeyAlgorithm.DSA, 2000); - // §5.4.3 - minimalBitStrengths.put(PublicKeyAlgorithm.ECDSA, 250); - // Note: EdDSA is not mentioned in the BSI document. - // We assume that the requirements are similar to other EC algorithms. - minimalBitStrengths.put(PublicKeyAlgorithm.EDDSA, 250); - // §7.2.1 - minimalBitStrengths.put(PublicKeyAlgorithm.DIFFIE_HELLMAN, 2000); - // §7.2.2 - minimalBitStrengths.put(PublicKeyAlgorithm.ECDH, 250); - - return new PublicKeyAlgorithmPolicy(minimalBitStrengths); - } - } - - /** - * Return the {@link NotationRegistry} of PGPainless. - * The notation registry is used to decide, whether a Notation is known or not. - * Background: Critical unknown notations render signatures invalid. - * - * @return Notation registry - */ - public NotationRegistry getNotationRegistry() { - return notationRegistry; - } - - /** - * Return the current {@link AlgorithmSuite} which defines preferred algorithms used during key generation. - * @return current algorithm suite - */ - public @Nonnull AlgorithmSuite getKeyGenerationAlgorithmSuite() { - return keyGenerationAlgorithmSuite; - } - - /** - * Set a custom {@link AlgorithmSuite} which defines preferred algorithms used during key generation. - * - * @param algorithmSuite custom algorithm suite - */ - public void setKeyGenerationAlgorithmSuite(@Nonnull AlgorithmSuite algorithmSuite) { - this.keyGenerationAlgorithmSuite = algorithmSuite; - } - - /** - * Return the level of validation PGPainless shall do on {@link org.bouncycastle.bcpg.sig.SignerUserID} subpackets. - * By default, this value is {@link SignerUserIdValidationLevel#DISABLED}. - * - * @return the level of validation - */ - public SignerUserIdValidationLevel getSignerUserIdValidationLevel() { - return signerUserIdValidationLevel; - } - - /** - * Specify, how {@link org.bouncycastle.bcpg.sig.SignerUserID} subpackets on signatures shall be validated. - * - * @param signerUserIdValidationLevel level of verification PGPainless shall do on - * {@link org.bouncycastle.bcpg.sig.SignerUserID} subpackets. - * @return policy instance - */ - public Policy setSignerUserIdValidationLevel(SignerUserIdValidationLevel signerUserIdValidationLevel) { - if (signerUserIdValidationLevel == null) { - throw new NullPointerException("SignerUserIdValidationLevel cannot be null."); - } - this.signerUserIdValidationLevel = signerUserIdValidationLevel; - return this; - } - - /** - * Enable or disable validation of public key parameters when unlocking private keys. - * Disabled by default. - * When enabled, PGPainless will validate, whether public key parameters have been tampered with. - * This is a countermeasure against possible attacks described in the paper - * "Victory by KO: Attacking OpenPGP Using Key Overwriting" by Lara Bruseghini, Daniel Huigens, and Kenneth G. Paterson. - * Since these attacks are only possible in very special conditions (attacker has access to the encrypted private key), - * and the countermeasures are very costly, they are disabled by default, but can be enabled using this method. - * - * @see KOpenPGP.com - * @param enable boolean - * @return this - */ - public Policy setEnableKeyParameterValidation(boolean enable) { - this.enableKeyParameterValidation = enable; - return this; - } - - /** - * Return true, if countermeasures against the KOpenPGP attacks are enabled, false otherwise. - * - * @return true if countermeasures are enabled, false otherwise. - */ - public boolean isEnableKeyParameterValidation() { - return enableKeyParameterValidation; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/policy/Policy2.kt b/pgpainless-core/src/main/java/org/pgpainless/policy/Policy2.kt deleted file mode 100644 index e17b9653..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/policy/Policy2.kt +++ /dev/null @@ -1,132 +0,0 @@ -package org.pgpainless.policy - -import org.pgpainless.algorithm.CompressionAlgorithm -import org.pgpainless.algorithm.HashAlgorithm -import org.pgpainless.util.DateUtil -import java.util.* - -class Policy2 { - - /** - * Create a HashAlgorithmPolicy which accepts all [HashAlgorithms][HashAlgorithm] from the - * given map, if the queried usage date is BEFORE the respective termination date. - * A termination date value of
null
means no termination, resulting in the algorithm being - * acceptable, regardless of usage date. - * - * @param defaultHashAlgorithm default hash algorithm - * @param algorithmTerminationDates map of acceptable algorithms and their termination dates - */ - class HashAlgorithmPolicy( - val defaultHashAlgorithm: HashAlgorithm, - val acceptableHashAlgorithmsAndTerminationDates: Map) { - - /** - * Create a [HashAlgorithmPolicy] which accepts all [HashAlgorithms][HashAlgorithm] listed in - * the given list, regardless of usage date. - * - * @param defaultHashAlgorithm default hash algorithm (e.g. used as fallback if negotiation fails) - * @param acceptableHashAlgorithms list of acceptable hash algorithms - */ - constructor(defaultHashAlgorithm: HashAlgorithm, acceptableHashAlgorithms: List) : - this(defaultHashAlgorithm, acceptableHashAlgorithms.associateWith { null }) - - fun isAcceptable(hashAlgorithm: HashAlgorithm) = isAcceptable(hashAlgorithm, Date()) - - /** - * Return true, if the given algorithm is acceptable for the given usage date. - * - * @param hashAlgorithm algorithm - * @param referenceTime usage date (e.g. signature creation time) - * - * @return acceptance - */ - fun isAcceptable(hashAlgorithm: HashAlgorithm, referenceTime: Date): Boolean { - if (!acceptableHashAlgorithmsAndTerminationDates.containsKey(hashAlgorithm)) - return false - val terminationDate = acceptableHashAlgorithmsAndTerminationDates[hashAlgorithm] - if (terminationDate == null) { - return true - } - return terminationDate > referenceTime - } - - fun isAcceptable(algorithmId: Int, referenceTime: Date): Boolean { - HashAlgorithm.fromId(algorithmId).let { - if (it == null) { - return false - } - return isAcceptable(it, referenceTime) - } - } - - fun isAcceptable(algorithmId: Int) = isAcceptable(algorithmId, Date()) - - companion object { - @JvmStatic - val smartSignatureHashAlgorithmPolicy = HashAlgorithmPolicy(HashAlgorithm.SHA512, buildMap { - put(HashAlgorithm.MD5, DateUtil.parseUTCDate("1997-02-01 00:00:00 UTC")) - put(HashAlgorithm.SHA1, DateUtil.parseUTCDate("2013-02-01 00:00:00 UTC")) - put(HashAlgorithm.RIPEMD160, DateUtil.parseUTCDate("2013-02-01 00:00:00 UTC")) - put(HashAlgorithm.SHA224, null) - put(HashAlgorithm.SHA256, null) - put(HashAlgorithm.SHA384, null) - put(HashAlgorithm.SHA512, null) - put(HashAlgorithm.SHA3_256, null) - put(HashAlgorithm.SHA3_512, null) - }) - - /** - * [HashAlgorithmPolicy] which only accepts signatures made using algorithms which are acceptable - * according to 2022 standards. - * - * Particularly this policy only accepts algorithms from the SHA2 and SHA3 families. - * - * @return static signature algorithm policy - */ - @JvmStatic - val static2022SignatureHashAlgorithmPolicy = - HashAlgorithmPolicy(HashAlgorithm.SHA512, listOf( - HashAlgorithm.SHA224, - HashAlgorithm.SHA256, - HashAlgorithm.SHA384, - HashAlgorithm.SHA512, - HashAlgorithm.SHA3_256, - HashAlgorithm.SHA3_512)) - - /** - * Hash algorithm policy for revocation signatures, which accepts SHA1 and SHA2 algorithms, as well as RIPEMD160. - * - * @return static revocation signature hash algorithm policy - */ - @JvmStatic - val static2022RevocationSignatureHashAlgorithmPolicy = - HashAlgorithmPolicy(HashAlgorithm.SHA512, listOf( - HashAlgorithm.RIPEMD160, - HashAlgorithm.SHA1, - HashAlgorithm.SHA224, - HashAlgorithm.SHA256, - HashAlgorithm.SHA384, - HashAlgorithm.SHA512, - HashAlgorithm.SHA3_256, - HashAlgorithm.SHA3_512)) - } - } - - class CompressionAlgorithmPolicy( - val defaultCompressionAlgorithm: CompressionAlgorithm, - val acceptableCompressionAlgorithms: List) { - - fun isAcceptable(algorithm: CompressionAlgorithm) = acceptableCompressionAlgorithms.contains(algorithm) - fun isAcceptable(algorithmId: Int) = - } - - companion object { - private var INSTANCE: Policy2? = null - fun getInstance(): Policy2 { - if (INSTANCE == null) { - INSTANCE = Policy2() - } - return INSTANCE!! - } - } -} \ No newline at end of file diff --git a/pgpainless-core/src/main/java/org/pgpainless/policy/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/policy/package-info.java deleted file mode 100644 index dd248151..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/policy/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: 2018 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -/** - * Policy regarding used algorithms. - */ -package org.pgpainless.policy; diff --git a/pgpainless-core/src/main/java/org/pgpainless/PGPainless.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt similarity index 98% rename from pgpainless-core/src/main/java/org/pgpainless/PGPainless.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt index a52b38ae..6aa9799e 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/PGPainless.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + package org.pgpainless import org.bouncycastle.openpgp.PGPKeyRing diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/AEADAlgorithm.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/AEADAlgorithm.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/AEADAlgorithm.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/AEADAlgorithm.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/AlgorithmSuite.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/AlgorithmSuite.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/AlgorithmSuite.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/AlgorithmSuite.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/CertificationType.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/CertificationType.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/CertificationType.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/CertificationType.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/CompressionAlgorithm.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/CompressionAlgorithm.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/CompressionAlgorithm.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/CompressionAlgorithm.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/DocumentSignatureType.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/DocumentSignatureType.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/DocumentSignatureType.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/DocumentSignatureType.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/EncryptionPurpose.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/EncryptionPurpose.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/EncryptionPurpose.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/EncryptionPurpose.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/Feature.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/Feature.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/Feature.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/Feature.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/HashAlgorithm.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/HashAlgorithm.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/HashAlgorithm.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/HashAlgorithm.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/KeyFlag.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/KeyFlag.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/OpenPgpPacket.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/OpenPgpPacket.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/OpenPgpPacket.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/OpenPgpPacket.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/PublicKeyAlgorithm.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/PublicKeyAlgorithm.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/PublicKeyAlgorithm.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/PublicKeyAlgorithm.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/RevocationState.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/RevocationState.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/RevocationState.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/RevocationState.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/RevocationStateType.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/RevocationStateType.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/RevocationStateType.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/RevocationStateType.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureSubpacket.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/SignatureSubpacket.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureSubpacket.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/SignatureSubpacket.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureType.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/SignatureType.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/SignatureType.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/SignatureType.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/StreamEncoding.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/StreamEncoding.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/StreamEncoding.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/StreamEncoding.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SymmetricKeyAlgorithm.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/SymmetricKeyAlgorithm.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/SymmetricKeyAlgorithm.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/SymmetricKeyAlgorithm.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/Trustworthiness.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/Trustworthiness.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/Trustworthiness.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/Trustworthiness.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/negotiation/HashAlgorithmNegotiator.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/negotiation/HashAlgorithmNegotiator.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/negotiation/HashAlgorithmNegotiator.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/negotiation/HashAlgorithmNegotiator.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/negotiation/SymmetricKeyAlgorithmNegotiator.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/negotiation/SymmetricKeyAlgorithmNegotiator.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/algorithm/negotiation/SymmetricKeyAlgorithmNegotiator.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/negotiation/SymmetricKeyAlgorithmNegotiator.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/authentication/CertificateAuthenticity.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/authentication/CertificateAuthenticity.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/authentication/CertificateAuthenticity.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/authentication/CertificateAuthenticity.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/authentication/CertificateAuthority.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/authentication/CertificateAuthority.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/authentication/CertificateAuthority.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/authentication/CertificateAuthority.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpFingerprint.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpFingerprint.kt similarity index 98% rename from pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpFingerprint.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpFingerprint.kt index 9c7409de..c5a2a24f 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpFingerprint.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpFingerprint.kt @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + package org.pgpainless.key import org.bouncycastle.openpgp.PGPKeyRing diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV4Fingerprint.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV4Fingerprint.kt similarity index 94% rename from pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV4Fingerprint.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV4Fingerprint.kt index 72c31f4e..fe0c4364 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV4Fingerprint.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV4Fingerprint.kt @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + package org.pgpainless.key import org.bouncycastle.openpgp.PGPKeyRing diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV5Fingerprint.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV5Fingerprint.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV5Fingerprint.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV5Fingerprint.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV6Fingerprint.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV6Fingerprint.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV6Fingerprint.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/key/OpenPgpV6Fingerprint.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/SubkeyIdentifier.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/key/SubkeyIdentifier.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/_64DigitFingerprint.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/_64DigitFingerprint.kt similarity index 100% rename from pgpainless-core/src/main/java/org/pgpainless/key/_64DigitFingerprint.kt rename to pgpainless-core/src/main/kotlin/org/pgpainless/key/_64DigitFingerprint.kt diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/policy/Policy.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/policy/Policy.kt new file mode 100644 index 00000000..b7c9f39e --- /dev/null +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/policy/Policy.kt @@ -0,0 +1,359 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.policy + +import org.pgpainless.algorithm.* +import org.pgpainless.util.DateUtil +import org.pgpainless.util.NotationRegistry +import java.util.* + +class Policy( + var signatureHashAlgorithmPolicy: HashAlgorithmPolicy, + var revocationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy, + var symmetricKeyEncryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy, + var symmetricKeyDecryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy, + var compressionAlgorithmPolicy: CompressionAlgorithmPolicy, + var publicKeyAlgorithmPolicy: PublicKeyAlgorithmPolicy, + var notationRegistry: NotationRegistry) { + + constructor(): this( + HashAlgorithmPolicy.smartSignatureHashAlgorithmPolicy(), + HashAlgorithmPolicy.smartSignatureHashAlgorithmPolicy(), + SymmetricKeyAlgorithmPolicy.symmetricKeyEncryptionPolicy2022(), + SymmetricKeyAlgorithmPolicy.symmetricKeyDecryptionPolicy2022(), + CompressionAlgorithmPolicy.anyCompressionAlgorithmPolicy(), + PublicKeyAlgorithmPolicy.bsi2021PublicKeyAlgorithmPolicy(), + NotationRegistry()) + + var keyGenerationAlgorithmSuite = AlgorithmSuite.defaultAlgorithmSuite + var signerUserIdValidationLevel = SignerUserIdValidationLevel.DISABLED + var enableKeyParameterValidation = false + + fun isEnableKeyParameterValidation() = enableKeyParameterValidation + + + /** + * Create a HashAlgorithmPolicy which accepts all [HashAlgorithms][HashAlgorithm] from the + * given map, if the queried usage date is BEFORE the respective termination date. + * A termination date value of
null
means no termination, resulting in the algorithm being + * acceptable, regardless of usage date. + * + * @param defaultHashAlgorithm default hash algorithm + * @param algorithmTerminationDates map of acceptable algorithms and their termination dates + */ + class HashAlgorithmPolicy( + val defaultHashAlgorithm: HashAlgorithm, + val acceptableHashAlgorithmsAndTerminationDates: Map) { + + /** + * Create a [HashAlgorithmPolicy] which accepts all [HashAlgorithms][HashAlgorithm] listed in + * the given list, regardless of usage date. + * + * @param defaultHashAlgorithm default hash algorithm (e.g. used as fallback if negotiation fails) + * @param acceptableHashAlgorithms list of acceptable hash algorithms + */ + constructor(defaultHashAlgorithm: HashAlgorithm, acceptableHashAlgorithms: List) : + this(defaultHashAlgorithm, acceptableHashAlgorithms.associateWith { null }) + + fun isAcceptable(hashAlgorithm: HashAlgorithm) = isAcceptable(hashAlgorithm, Date()) + + /** + * Return true, if the given algorithm is acceptable for the given usage date. + * + * @param hashAlgorithm algorithm + * @param referenceTime usage date (e.g. signature creation time) + * + * @return acceptance + */ + fun isAcceptable(hashAlgorithm: HashAlgorithm, referenceTime: Date): Boolean { + if (!acceptableHashAlgorithmsAndTerminationDates.containsKey(hashAlgorithm)) + return false + val terminationDate = acceptableHashAlgorithmsAndTerminationDates[hashAlgorithm] ?: return true + return terminationDate > referenceTime + } + + fun isAcceptable(algorithmId: Int) = isAcceptable(algorithmId, Date()) + + fun isAcceptable(algorithmId: Int, referenceTime: Date): Boolean { + val algorithm = HashAlgorithm.fromId(algorithmId) ?: return false + return isAcceptable(algorithm, referenceTime) + } + + fun defaultHashAlgorithm() = defaultHashAlgorithm + + companion object { + @JvmStatic + fun smartSignatureHashAlgorithmPolicy() = HashAlgorithmPolicy( + HashAlgorithm.SHA512, buildMap { + put(HashAlgorithm.SHA3_512, null) + put(HashAlgorithm.SHA3_256, null) + put(HashAlgorithm.SHA512, null) + put(HashAlgorithm.SHA384, null) + put(HashAlgorithm.SHA256, null) + put(HashAlgorithm.SHA224, null) + put(HashAlgorithm.RIPEMD160, DateUtil.parseUTCDate("2013-02-01 00:00:00 UTC")) + put(HashAlgorithm.SHA1, DateUtil.parseUTCDate("2013-02-01 00:00:00 UTC")) + put(HashAlgorithm.MD5, DateUtil.parseUTCDate("1997-02-01 00:00:00 UTC")) + }) + + /** + * [HashAlgorithmPolicy] which only accepts signatures made using algorithms which are acceptable + * according to 2022 standards. + * + * Particularly this policy only accepts algorithms from the SHA2 and SHA3 families. + * + * @return static signature algorithm policy + */ + @JvmStatic + fun static2022SignatureHashAlgorithmPolicy() = HashAlgorithmPolicy( + HashAlgorithm.SHA512, + listOf( + HashAlgorithm.SHA3_512, + HashAlgorithm.SHA3_256, + HashAlgorithm.SHA512, + HashAlgorithm.SHA384, + HashAlgorithm.SHA256, + HashAlgorithm.SHA224) + ) + + /** + * Hash algorithm policy for revocation signatures, which accepts SHA1 and SHA2 algorithms, as well as RIPEMD160. + * + * @return static revocation signature hash algorithm policy + */ + @JvmStatic + fun static2022RevocationSignatureHashAlgorithmPolicy() = HashAlgorithmPolicy( + HashAlgorithm.SHA512, + listOf( + HashAlgorithm.SHA3_512, + HashAlgorithm.SHA3_256, + HashAlgorithm.SHA512, + HashAlgorithm.SHA384, + HashAlgorithm.SHA256, + HashAlgorithm.SHA224, + HashAlgorithm.SHA1, + HashAlgorithm.RIPEMD160 + ) + ) + } + } + + class SymmetricKeyAlgorithmPolicy( + val defaultSymmetricKeyAlgorithm: SymmetricKeyAlgorithm, + val acceptableSymmetricKeyAlgorithms: List) { + + fun isAcceptable(algorithm: SymmetricKeyAlgorithm) = acceptableSymmetricKeyAlgorithms.contains(algorithm) + fun isAcceptable(algorithmId: Int): Boolean { + val algorithm = SymmetricKeyAlgorithm.fromId(algorithmId) ?: return false + return isAcceptable(algorithm) + } + + fun selectBest(options: List): SymmetricKeyAlgorithm? { + for (acceptable in acceptableSymmetricKeyAlgorithms) { + if (options.contains(acceptable)) { + return acceptable + } + } + return null + } + + companion object { + + /** + * The default symmetric encryption algorithm policy of PGPainless. + * + * @return default symmetric encryption algorithm policy + * @deprecated not expressive - will be removed in a future release + */ + @JvmStatic + @Deprecated( + "Not expressive - will be removed in a future release", + ReplaceWith("symmetricKeyEncryptionPolicy2022")) + fun defaultSymmetricKeyEncryptionAlgorithmPolicy() = symmetricKeyEncryptionPolicy2022() + + /** + * Policy for symmetric encryption algorithms in the context of message production (encryption). + * This suite contains algorithms that are deemed safe to use in 2022. + * + * @return 2022 symmetric key encryption algorithm policy + */ + @JvmStatic + fun symmetricKeyEncryptionPolicy2022() = SymmetricKeyAlgorithmPolicy( + SymmetricKeyAlgorithm.AES_128, + // Reject: Unencrypted, IDEA, TripleDES, CAST5, Blowfish + listOf( + SymmetricKeyAlgorithm.AES_256, + SymmetricKeyAlgorithm.AES_192, + SymmetricKeyAlgorithm.AES_128, + SymmetricKeyAlgorithm.TWOFISH, + SymmetricKeyAlgorithm.CAMELLIA_256, + SymmetricKeyAlgorithm.CAMELLIA_192, + SymmetricKeyAlgorithm.CAMELLIA_128 + )) + + /** + * The default symmetric decryption algorithm policy of PGPainless. + * + * @return default symmetric decryption algorithm policy + * @deprecated not expressive - will be removed in a future update + */ + @JvmStatic + @Deprecated("not expressive - will be removed in a future update", + ReplaceWith("symmetricKeyDecryptionPolicy2022()")) + fun defaultSymmetricKeyDecryptionAlgorithmPolicy() = symmetricKeyDecryptionPolicy2022() + + /** + * Policy for symmetric key encryption algorithms in the context of message consumption (decryption). + * This suite contains algorithms that are deemed safe to use in 2022. + * + * @return 2022 symmetric key decryption algorithm policy + */ + @JvmStatic + fun symmetricKeyDecryptionPolicy2022() = SymmetricKeyAlgorithmPolicy( + SymmetricKeyAlgorithm.AES_128, + // Reject: Unencrypted, IDEA, TripleDES, Blowfish + listOf( + SymmetricKeyAlgorithm.AES_256, + SymmetricKeyAlgorithm.AES_192, + SymmetricKeyAlgorithm.AES_128, + SymmetricKeyAlgorithm.TWOFISH, + SymmetricKeyAlgorithm.CAMELLIA_256, + SymmetricKeyAlgorithm.CAMELLIA_192, + SymmetricKeyAlgorithm.CAMELLIA_128, + SymmetricKeyAlgorithm.CAST5 + )) + } + } + + class CompressionAlgorithmPolicy( + val defaultCompressionAlgorithm: CompressionAlgorithm, + val acceptableCompressionAlgorithms: List) { + + fun isAcceptable(algorithm: CompressionAlgorithm) = acceptableCompressionAlgorithms.contains(algorithm) + fun isAcceptable(algorithmId: Int): Boolean { + val algorithm = CompressionAlgorithm.fromId(algorithmId) ?: return false + return isAcceptable(algorithm) + } + + fun defaultCompressionAlgorithm() = defaultCompressionAlgorithm + + companion object { + + /** + * Default {@link CompressionAlgorithmPolicy} of PGPainless. + * The default compression algorithm policy accepts any compression algorithm. + * + * @return default algorithm policy + * @deprecated not expressive - might be removed in a future release + */ + @JvmStatic + @Deprecated("not expressive - might be removed in a future release", + ReplaceWith("anyCompressionAlgorithmPolicy()")) + fun defaultCompressionAlgorithmPolicy() = anyCompressionAlgorithmPolicy() + + /** + * Policy that accepts any known compression algorithm and offers [CompressionAlgorithm.ZIP] as + * default algorithm. + * + * @return compression algorithm policy + */ + @JvmStatic + fun anyCompressionAlgorithmPolicy() = CompressionAlgorithmPolicy( + CompressionAlgorithm.ZIP, + listOf(CompressionAlgorithm.UNCOMPRESSED, + CompressionAlgorithm.ZIP, + CompressionAlgorithm.BZIP2, + CompressionAlgorithm.ZLIB)) + } + } + + class PublicKeyAlgorithmPolicy(private val algorithmStrengths: Map) { + + fun isAcceptable(algorithm: PublicKeyAlgorithm, bitStrength: Int): Boolean { + return bitStrength >= (algorithmStrengths[algorithm] ?: return false) + } + + fun isAcceptable(algorithmId: Int, bitStrength: Int): Boolean { + val algorithm = PublicKeyAlgorithm.fromId(algorithmId) ?: return false + return isAcceptable(algorithm, bitStrength) + } + + companion object { + + /** + * Return PGPainless' default public key algorithm policy. + * This policy is based upon recommendations made by the German Federal Office for Information Security (BSI). + * + * @return default algorithm policy + * @deprecated not expressive - might be removed in a future release + */ + @JvmStatic + @Deprecated("not expressive - might be removed in a future release", + ReplaceWith("bsi2021PublicKeyAlgorithmPolicy()")) + fun defaultPublicKeyAlgorithmPolicy() = bsi2021PublicKeyAlgorithmPolicy() + + /** + * This policy is based upon recommendations made by the German Federal Office for Information Security (BSI). + * + * Basically this policy requires keys based on elliptic curves to have a bit strength of at least 250, + * and keys based on prime number factorization / discrete logarithm problems to have a strength of at least 2000 bits. + * + * @see BSI - Technical Guideline - Cryptographic Mechanisms: Recommendations and Key Lengths (2021-01) + * @see BlueKrypt | Cryptographic Key Length Recommendation + * + * @return default algorithm policy + */ + @JvmStatic + fun bsi2021PublicKeyAlgorithmPolicy() = PublicKeyAlgorithmPolicy(buildMap { + // §5.4.1 + put(PublicKeyAlgorithm.RSA_GENERAL, 2000) + put(PublicKeyAlgorithm.RSA_SIGN, 2000) + put(PublicKeyAlgorithm.RSA_ENCRYPT, 2000) + // Note: ElGamal is not mentioned in the BSI document. + // We assume that the requirements are similar to other DH algorithms + put(PublicKeyAlgorithm.ELGAMAL_ENCRYPT, 2000) + put(PublicKeyAlgorithm.ELGAMAL_GENERAL, 2000) + // §5.4.2 + put(PublicKeyAlgorithm.DSA, 2000) + // §5.4.3 + put(PublicKeyAlgorithm.ECDSA, 250) + // Note: EdDSA is not mentioned in the BSI document. + // We assume that the requirements are similar to other EC algorithms. + put(PublicKeyAlgorithm.EDDSA, 250) + // §7.2.1 + put(PublicKeyAlgorithm.DIFFIE_HELLMAN, 2000) + // §7.2.2 + put(PublicKeyAlgorithm.ECDH, 250) + }) + } + } + + enum class SignerUserIdValidationLevel { + /** + * PGPainless will verify {@link org.bouncycastle.bcpg.sig.SignerUserID} subpackets in signatures strictly. + * This means, that signatures with Signer's User-ID subpackets containing a value that does not match the signer key's + * user-id exactly, will be rejected. + * E.g. Signer's user-id "alice@pgpainless.org", User-ID: "Alice <alice@pgpainless.org>" does not + * match exactly and is therefore rejected. + */ + STRICT, + + /** + * PGPainless will ignore {@link org.bouncycastle.bcpg.sig.SignerUserID} subpackets on signature. + */ + DISABLED + } + + companion object { + + @Volatile + private var INSTANCE: Policy? = null + + @JvmStatic + fun getInstance() = INSTANCE ?: synchronized(this) { + INSTANCE ?: Policy().also { INSTANCE = it } + } + } +} \ No newline at end of file