From 678f296b5c3efd6022e725280813b879381d2197 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 3 Aug 2023 14:42:35 +0200 Subject: [PATCH] Introduce AEADAlgorithmCombination class --- .../algorithm/AEADAlgorithmCombination.java | 73 +++++++++++++++++++ .../subpackets/SelfSignatureSubpackets.java | 9 +-- .../subpackets/SignatureSubpackets.java | 16 ++-- .../subpackets/SignatureSubpacketsUtil.java | 35 +++++++++ 4 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/AEADAlgorithmCombination.java diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/AEADAlgorithmCombination.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/AEADAlgorithmCombination.java new file mode 100644 index 00000000..538e2795 --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/AEADAlgorithmCombination.java @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.algorithm; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites; + +public final class AEADAlgorithmCombination { + + private final AEADAlgorithm aeadAlgorithm; + private final SymmetricKeyAlgorithm symmetricKeyAlgorithm; + + /** + * AES-128 + OCB is a MUST implement and is therefore implicitly supported. + * + * @see + * Crypto-Refresh ยง 5.2.3.15. Preferred AEAD Ciphersuites + */ + public static AEADAlgorithmCombination AES_128_OCB = AEADAlgorithmCombination.from( + SymmetricKeyAlgorithm.AES_128, AEADAlgorithm.OCB); + + private AEADAlgorithmCombination(@Nonnull SymmetricKeyAlgorithm symmetricKeyAlgorithm, + @Nonnull AEADAlgorithm aeadAlgorithm) { + this.aeadAlgorithm = aeadAlgorithm; + this.symmetricKeyAlgorithm = symmetricKeyAlgorithm; + } + + @Nonnull + public AEADAlgorithm getAeadAlgorithm() { + return aeadAlgorithm; + } + + @Nonnull + public SymmetricKeyAlgorithm getSymmetricKeyAlgorithm() { + return symmetricKeyAlgorithm; + } + + public static AEADAlgorithmCombination from(@Nonnull SymmetricKeyAlgorithm symmetricKeyAlgorithm, + @Nonnull AEADAlgorithm aeadAlgorithm) { + return new AEADAlgorithmCombination(symmetricKeyAlgorithm, aeadAlgorithm); + } + + @Nullable + public static AEADAlgorithmCombination from(PreferredAEADCiphersuites.Combination combination) { + return fromIds(combination.getSymmetricAlgorithm(), combination.getAeadAlgorithm()); + } + + @Nonnull + public static AEADAlgorithmCombination requireFrom(PreferredAEADCiphersuites.Combination combination) { + return requireFromIds(combination.getSymmetricAlgorithm(), combination.getAeadAlgorithm()); + } + + @Nullable + public static AEADAlgorithmCombination fromIds(int symmetricAlgorithmId, int aeadAlgorithmId) { + SymmetricKeyAlgorithm symmetric = SymmetricKeyAlgorithm.fromId(symmetricAlgorithmId); + AEADAlgorithm aead = AEADAlgorithm.fromId(aeadAlgorithmId); + + if (symmetric == null || aead == null) { + return null; + } + + return new AEADAlgorithmCombination(symmetric, aead); + } + + @Nonnull + public static AEADAlgorithmCombination requireFromIds(int symmetricAlgorithmId, int aeadAlgorithmId) { + return from(SymmetricKeyAlgorithm.requireFromId(symmetricAlgorithmId), AEADAlgorithm.requireFromId(aeadAlgorithmId)); + } +} diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SelfSignatureSubpackets.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SelfSignatureSubpackets.java index 03beda4a..0b7c3700 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SelfSignatureSubpackets.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SelfSignatureSubpackets.java @@ -18,13 +18,12 @@ import org.bouncycastle.bcpg.sig.PreferredAlgorithms; import org.bouncycastle.bcpg.sig.PrimaryUserID; import org.bouncycastle.bcpg.sig.RevocationKey; import org.bouncycastle.openpgp.PGPPublicKey; -import org.pgpainless.algorithm.AEADAlgorithm; +import org.pgpainless.algorithm.AEADAlgorithmCombination; import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.Feature; import org.pgpainless.algorithm.HashAlgorithm; import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.util.Tuple; public interface SelfSignatureSubpackets extends BaseSignatureSubpackets { @@ -59,11 +58,11 @@ public interface SelfSignatureSubpackets extends BaseSignatureSubpackets { SelfSignatureSubpackets setKeyExpirationTime(@Nullable KeyExpirationTime keyExpirationTime); - SelfSignatureSubpackets setPreferredAEADCiphersuites(Tuple... algorithms); + SelfSignatureSubpackets setPreferredAEADCiphersuites(AEADAlgorithmCombination... algorithms); - SelfSignatureSubpackets setPreferredAEADCiphersuites(Set> algorithms); + SelfSignatureSubpackets setPreferredAEADCiphersuites(Set algorithms); - SelfSignatureSubpackets setPreferredAEADCiphersuites(boolean isCritical, Set> algorithms); + SelfSignatureSubpackets setPreferredAEADCiphersuites(boolean isCritical, Set algorithms); SelfSignatureSubpackets setPreferredAEADCiphersuites(@Nullable PreferredAEADCiphersuites algorithms); diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java index 03b29170..d8e76ceb 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java @@ -43,7 +43,7 @@ import org.bouncycastle.bcpg.sig.TrustSignature; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; -import org.pgpainless.algorithm.AEADAlgorithm; +import org.pgpainless.algorithm.AEADAlgorithmCombination; import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.Feature; import org.pgpainless.algorithm.HashAlgorithm; @@ -51,7 +51,6 @@ import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.PublicKeyAlgorithm; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.key.util.RevocationAttributes; -import org.pgpainless.util.Tuple; public class SignatureSubpackets implements BaseSignatureSubpackets, SelfSignatureSubpackets, CertificationSubpackets, RevocationSignatureSubpackets { @@ -318,23 +317,24 @@ public class SignatureSubpackets } @Override - public SelfSignatureSubpackets setPreferredAEADCiphersuites(Tuple... algorithms) { + public SelfSignatureSubpackets setPreferredAEADCiphersuites(AEADAlgorithmCombination... algorithms) { return setPreferredAEADCiphersuites(new LinkedHashSet<>(Arrays.asList(algorithms))); } @Override - public SelfSignatureSubpackets setPreferredAEADCiphersuites(Set> algorithms) { + public SelfSignatureSubpackets setPreferredAEADCiphersuites(Set algorithms) { return setPreferredAEADCiphersuites(false, algorithms); } @Override - public SelfSignatureSubpackets setPreferredAEADCiphersuites(boolean isCritical, Set> algorithms) { + public SelfSignatureSubpackets setPreferredAEADCiphersuites(boolean isCritical, Set algorithms) { List combinations = new ArrayList<>(); - Iterator> iterator = algorithms.iterator(); + Iterator iterator = algorithms.iterator(); while (iterator.hasNext()) { - Tuple tuple = iterator.next(); + AEADAlgorithmCombination combination = iterator.next(); combinations.add(new PreferredAEADCiphersuites.Combination( - tuple.getA().getAlgorithmId(), tuple.getB().getAlgorithmId())); + combination.getSymmetricKeyAlgorithm().getAlgorithmId(), + combination.getAeadAlgorithm().getAlgorithmId())); } PreferredAEADCiphersuites subpacket = new PreferredAEADCiphersuites( isCritical, combinations.toArray(new PreferredAEADCiphersuites.Combination[0])); 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 6d53ad1d..c3e9ea39 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 @@ -21,6 +21,7 @@ import org.bouncycastle.bcpg.sig.IssuerKeyID; import org.bouncycastle.bcpg.sig.KeyExpirationTime; import org.bouncycastle.bcpg.sig.KeyFlags; import org.bouncycastle.bcpg.sig.NotationData; +import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites; import org.bouncycastle.bcpg.sig.PreferredAlgorithms; import org.bouncycastle.bcpg.sig.PrimaryUserID; import org.bouncycastle.bcpg.sig.RegularExpression; @@ -37,6 +38,7 @@ import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureList; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; +import org.pgpainless.algorithm.AEADAlgorithmCombination; import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.Feature; import org.pgpainless.algorithm.HashAlgorithm; @@ -334,6 +336,39 @@ public final class SignatureSubpacketsUtil { return algorithms; } + public static @Nullable PreferredAEADCiphersuites getPreferredAEADAlgorithms(PGPSignature signature) { + org.bouncycastle.bcpg.SignatureSubpacket subpacket = hashed(signature, SignatureSubpacket.preferredAEADAlgorithms); + if (subpacket == null) { + return null; + } + + // Workaround for https://github.com/pgpainless/pgpainless/pull/399 + // TODO: Remove when BC 1.77 is released + if (subpacket instanceof PreferredAlgorithms) { + List combinationList = new ArrayList<>(); + int[] algorithms = ((PreferredAlgorithms) subpacket).getPreferences(); + for (int i = 0; i < algorithms.length; i += 2) { + combinationList.add(new PreferredAEADCiphersuites.Combination(algorithms[i], algorithms[i + 1])); + } + PreferredAEADCiphersuites aead = new PreferredAEADCiphersuites( + subpacket.isCritical(), combinationList.toArray(new PreferredAEADCiphersuites.Combination[0])); + return aead; + } + + return (PreferredAEADCiphersuites) subpacket; + } + + public static @Nonnull Set parsePreferredAEADAlgorithms(PGPSignature signature) { + Set algorithms = new LinkedHashSet<>(); + PreferredAEADCiphersuites preferences = getPreferredAEADAlgorithms(signature); + if (preferences != null) { + for (PreferredAEADCiphersuites.Combination combination : preferences.getAlgorithms()) { + algorithms.add(AEADAlgorithmCombination.from(combination)); + } + } + return algorithms; + } + /** * Return the primary user-id subpacket from the signatures hashed area. *