From 1f8031e1e438362713bbdc47ac66ba29bd9e4be6 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 28 Nov 2024 14:38:54 +0100 Subject: [PATCH 01/12] PGPSignatureSubpacketGenerator: Add generics to the packet list --- .../PGPSignatureSubpacketGenerator.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java index 9acbba5128..c9898f4291 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java @@ -649,9 +649,9 @@ public boolean removePacketsOfType(int subpacketType) public boolean hasSubpacket( int type) { - for (int i = 0; i != packets.size(); i++) + for (SignatureSubpacket packet : packets) { - if (((SignatureSubpacket)packets.get(i)).getType() == type) + if (packet.getType() == type) { return true; } @@ -670,17 +670,17 @@ public boolean hasSubpacket( public SignatureSubpacket[] getSubpackets( int type) { - List list = new ArrayList(); + List list = new ArrayList<>(); - for (int i = 0; i != packets.size(); i++) + for (SignatureSubpacket packet : packets) { - if (((SignatureSubpacket)packets.get(i)).getType() == type) + if (packet.getType() == type) { - list.add(packets.get(i)); + list.add(packet); } } - return (SignatureSubpacket[])list.toArray(new SignatureSubpacket[]{}); + return list.toArray(new SignatureSubpacket[0]); } public PGPSignatureSubpacketVector generate() @@ -691,9 +691,9 @@ public PGPSignatureSubpacketVector generate() private boolean contains(int type) { - for (int i = 0; i < packets.size(); ++i) + for (SignatureSubpacket packet : packets) { - if (((SignatureSubpacket)packets.get(i)).getType() == type) + if (packet.getType() == type) { return true; } From bad96c1e673dc56c006ea60b4c355dfc03f59180 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 28 Nov 2024 14:45:04 +0100 Subject: [PATCH 02/12] PGPSignatureSubpacketVector: Add generics to the subpacket list --- .../openpgp/PGPSignatureSubpacketVector.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketVector.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketVector.java index 10e36a478e..078faa49f6 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketVector.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketVector.java @@ -116,7 +116,7 @@ public boolean hasSubpacket( public SignatureSubpacket[] getSubpackets( int type) { - List list = new ArrayList(); + List list = new ArrayList<>(); for (int i = 0; i != packets.length; i++) { @@ -126,20 +126,20 @@ public SignatureSubpacket[] getSubpackets( } } - return (SignatureSubpacket[])list.toArray(new SignatureSubpacket[]{}); + return list.toArray(new SignatureSubpacket[0]); } public PGPSignatureList getEmbeddedSignatures() throws PGPException { SignatureSubpacket[] sigs = getSubpackets(SignatureSubpacketTags.EMBEDDED_SIGNATURE); - ArrayList l = new ArrayList(); + ArrayList l = new ArrayList<>(); - for (int i = 0; i < sigs.length; i++) + for (SignatureSubpacket sig : sigs) { try { - l.add(new PGPSignature(SignaturePacket.fromByteArray(sigs[i].getData()))); + l.add(new PGPSignature(SignaturePacket.fromByteArray(sig.getData()))); } catch (IOException e) { @@ -147,7 +147,7 @@ public PGPSignatureList getEmbeddedSignatures() } } - return new PGPSignatureList((PGPSignature[])l.toArray(new PGPSignature[l.size()])); + return new PGPSignatureList(l.toArray(new PGPSignature[0])); } public NotationData[] getNotationDataOccurrences() @@ -179,7 +179,7 @@ public NotationData[] getNotationDataOccurences() public NotationData[] getNotationDataOccurrences(String notationName) { NotationData[] notations = getNotationDataOccurrences(); - List notationsWithName = new ArrayList(); + List notationsWithName = new ArrayList<>(); for (int i = 0; i != notations.length; i++) { NotationData notation = notations[i]; @@ -188,7 +188,7 @@ public NotationData[] getNotationDataOccurrences(String notationName) notationsWithName.add(notation); } } - return (NotationData[])notationsWithName.toArray(new NotationData[0]); + return notationsWithName.toArray(new NotationData[0]); } public long getIssuerKeyID() From af7734772daf8cbd1c027a41fdcd0a4ecfb1bd7f Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 28 Nov 2024 15:01:52 +0100 Subject: [PATCH 03/12] PGPKeyRingGenerator: Various improvements * Rename masterKey -> primaryKey * Add generics to list structures * sanitize primary and subkeys * properly instantiate signature generators by passing key version --- .../openpgp/PGPKeyRingGenerator.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRingGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRingGenerator.java index bb01c966b0..266db63d8f 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRingGenerator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRingGenerator.java @@ -153,7 +153,7 @@ public PGPKeyRingGenerator( this.keySignerBuilder = keySignerBuilder; PGPSignature certSig = (PGPSignature)originalSecretRing.getPublicKey().getSignatures().next(); - List hashedVec = new ArrayList(); + List hashedVec = new ArrayList(); PGPSignatureSubpacketVector existing = certSig.getHashedSubPackets(); for (int i = 0; i != existing.size(); i++) { @@ -164,7 +164,7 @@ public PGPKeyRingGenerator( hashedVec.add(existing.packets[i]); } this.hashedPcks = new PGPSignatureSubpacketVector( - (SignatureSubpacket[])hashedVec.toArray(new SignatureSubpacket[hashedVec.size()])); + hashedVec.toArray(new SignatureSubpacket[0])); this.unhashedPcks = certSig.getUnhashedSubPackets(); keys.addAll(originalSecretRing.keys); @@ -323,9 +323,7 @@ public void addSubKey( } sGen.setUnhashedSubpackets(unhashedPcks); - - List subSigs = new ArrayList(); - + List subSigs = new ArrayList(); subSigs.add(sGen.generateCertification(primaryKey.getPublicKey(), keyPair.getPublicKey())); // replace the public key packet structure with a public subkey one. @@ -362,14 +360,14 @@ public PGPSecretKeyRing generateSecretKeyRing() */ public PGPPublicKeyRing generatePublicKeyRing() { - Iterator it = keys.iterator(); - List pubKeys = new ArrayList(); + Iterator it = keys.iterator(); + List pubKeys = new ArrayList(); - pubKeys.add(((PGPSecretKey)it.next()).getPublicKey()); + pubKeys.add((it.next()).getPublicKey()); while (it.hasNext()) { - pubKeys.add(((PGPSecretKey)it.next()).getPublicKey()); + pubKeys.add((it.next()).getPublicKey()); } return new PGPPublicKeyRing(pubKeys); From 03261c041b34b123706b574eda027afbba99d5cc Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 28 Nov 2024 15:04:19 +0100 Subject: [PATCH 04/12] Add PublicKeyUtils This class contains methods for checking properties of public key algorithms --- .../org/bouncycastle/bcpg/PublicKeyUtils.java | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyUtils.java b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyUtils.java index 48c77ba566..84d6891834 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyUtils.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyUtils.java @@ -30,27 +30,26 @@ public static boolean isSigningAlgorithm(int publicKeyAlgorithm) } } -// /** -// * Return true, if the public key algorithm that corresponds to the given ID is capable of encryption. -// * -// * @param publicKeyAlgorithm public key algorithm id -// * @return true if algorithm can encrypt -// */ -// public static boolean isEncryptionAlgorithm(int publicKeyAlgorithm) -// { -// switch (publicKeyAlgorithm) -// { -// case PublicKeyAlgorithmTags.RSA_GENERAL: -// case PublicKeyAlgorithmTags.RSA_ENCRYPT: -// case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: -// case PublicKeyAlgorithmTags.ECDH: -// case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: -// case PublicKeyAlgorithmTags.DIFFIE_HELLMAN: -// case PublicKeyAlgorithmTags.X25519: -// case PublicKeyAlgorithmTags.X448: -// return true; -// default: -// return false; -// } -// } + /** + * Return true, if the public key algorithm that corresponds to the given ID is capable of encryption. + * @param publicKeyAlgorithm public key algorithm id + * @return true if algorithm can encrypt + */ + public static boolean isEncryptionAlgorithm(int publicKeyAlgorithm) + { + switch (publicKeyAlgorithm) + { + case PublicKeyAlgorithmTags.RSA_GENERAL: + case PublicKeyAlgorithmTags.RSA_ENCRYPT: + case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: + case PublicKeyAlgorithmTags.ECDH: + case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: + case PublicKeyAlgorithmTags.DIFFIE_HELLMAN: + case PublicKeyAlgorithmTags.X25519: + case PublicKeyAlgorithmTags.X448: + return true; + default: + return false; + } + } } From c849ef10cc7fabecf11168e1b87b2aff28209e0e Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 28 Nov 2024 15:07:59 +0100 Subject: [PATCH 05/12] Add missing javadoc --- .../bouncycastle/openpgp/operator/PGPAEADDataEncryptor.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPAEADDataEncryptor.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPAEADDataEncryptor.java index a2985263f3..6d791c992e 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPAEADDataEncryptor.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPAEADDataEncryptor.java @@ -4,8 +4,7 @@ /** * A data encryptor, using AEAD. * There are two different flavours of AEAD encryption used with OpenPGP. - * OpenPGP v5 AEAD is slightly different from v6 AEAD. - *

+ * LibrePGP (v5) AEAD is slightly different from RFC9580 (v6) AEAD. * {@link PGPAEADDataEncryptor} instances are generally not constructed directly, but obtained from a * {@link PGPDataEncryptorBuilder}. *

From 31bea539deff2ba8d16f0f49e0730511908b4d2f Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 28 Nov 2024 15:10:42 +0100 Subject: [PATCH 06/12] Introcude superclass AEADSecretKeyEncryptorBuilder Both the BcAEADSecretKeyEncryptorBuilder and JcaAEADSecretKeyEncryptorBuilder did not share a common super type. This patch added AEADSecretKeyEncryptorBuilder for this purpose. --- .../AEADSecretKeyEncryptorBuilder.java | 21 +++++++++++++++++++ .../bc/BcAEADSecretKeyEncryptorBuilder.java | 2 ++ .../JcaAEADSecretKeyEncryptorBuilder.java | 2 ++ 3 files changed, 25 insertions(+) create mode 100644 pg/src/main/java/org/bouncycastle/openpgp/operator/AEADSecretKeyEncryptorBuilder.java diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/AEADSecretKeyEncryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/AEADSecretKeyEncryptorBuilder.java new file mode 100644 index 0000000000..26b1c033a4 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/AEADSecretKeyEncryptorBuilder.java @@ -0,0 +1,21 @@ +package org.bouncycastle.openpgp.operator; + +import org.bouncycastle.bcpg.PublicKeyPacket; + +/** + * Implementation provider for AEAD-based {@link PBESecretKeyEncryptor PBESecretKeyEncryptors}. + */ +public interface AEADSecretKeyEncryptorBuilder +{ + /** + * Build a new {@link PBESecretKeyEncryptor} using the given passphrase. + * Note: As the AEAD protection mechanism includes the public key packet of the key into the calculation, + * if the key you want to protect is supposed to be a subkey, you need to convert it to one before + * calling this method. See {@link org.bouncycastle.openpgp.PGPKeyPair#asSubkey(KeyFingerPrintCalculator)}. + * + * @param passphrase passphrase + * @param pubKey public primary or subkey packet + * @return encryptor using AEAD + */ + PBESecretKeyEncryptor build(char[] passphrase, PublicKeyPacket pubKey); +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADSecretKeyEncryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADSecretKeyEncryptorBuilder.java index bf0b888836..a22d18743c 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADSecretKeyEncryptorBuilder.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADSecretKeyEncryptorBuilder.java @@ -8,9 +8,11 @@ import org.bouncycastle.bcpg.PublicKeyPacket; import org.bouncycastle.bcpg.S2K; import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.AEADSecretKeyEncryptorBuilder; import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; public class BcAEADSecretKeyEncryptorBuilder + implements AEADSecretKeyEncryptorBuilder { private int aeadAlgorithm; diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaAEADSecretKeyEncryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaAEADSecretKeyEncryptorBuilder.java index 9dd5490cc3..23de42d6af 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaAEADSecretKeyEncryptorBuilder.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaAEADSecretKeyEncryptorBuilder.java @@ -13,9 +13,11 @@ import org.bouncycastle.jcajce.util.NamedJcaJceHelper; import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.AEADSecretKeyEncryptorBuilder; import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; public class JcaAEADSecretKeyEncryptorBuilder + implements AEADSecretKeyEncryptorBuilder { private int aeadAlgorithm; private int symmetricAlgorithm; From e76db13cf36a5a0c1c0ad5e231d37ab832c52712 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 3 Dec 2024 12:04:42 +0100 Subject: [PATCH 07/12] Operator changes --- .../PBESecretKeyDecryptorBuilder.java | 9 ++++++++ .../PBESecretKeyDecryptorBuilderProvider.java | 15 ++++++++++++ .../bc/BcPBESecretKeyDecryptorBuilder.java | 2 ++ ...cPBESecretKeyDecryptorBuilderProvider.java | 14 +++++++++++ .../JcePBESecretKeyDecryptorBuilder.java | 2 ++ ...ePBESecretKeyDecryptorBuilderProvider.java | 23 +++++++++++++++++++ 6 files changed, 65 insertions(+) create mode 100644 pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilder.java create mode 100644 pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilderProvider.java create mode 100644 pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilderProvider.java create mode 100644 pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilderProvider.java diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilder.java new file mode 100644 index 0000000000..b19389b50e --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilder.java @@ -0,0 +1,9 @@ +package org.bouncycastle.openpgp.operator; + +import org.bouncycastle.openpgp.PGPException; + +public interface PBESecretKeyDecryptorBuilder +{ + PBESecretKeyDecryptor build(char[] passphrase) + throws PGPException; +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilderProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilderProvider.java new file mode 100644 index 0000000000..e94ddb551b --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilderProvider.java @@ -0,0 +1,15 @@ +package org.bouncycastle.openpgp.operator; + +import org.bouncycastle.openpgp.PGPException; + +/** + * Provider for {@link PBESecretKeyDecryptorBuilder} instances. + * The purpose of this class is to act as an abstract factory, whose subclasses can decide, which concrete + * implementation of {@link PBESecretKeyDecryptorBuilder} (builder for objects that can unlock encrypted + * secret keys) to return. + */ +public interface PBESecretKeyDecryptorBuilderProvider +{ + PBESecretKeyDecryptorBuilder provide() + throws PGPException; +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilder.java index cd1d20b1c3..fe986d32a0 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilder.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilder.java @@ -3,9 +3,11 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilder; import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; public class BcPBESecretKeyDecryptorBuilder + implements PBESecretKeyDecryptorBuilder { private PGPDigestCalculatorProvider calculatorProvider; diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilderProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilderProvider.java new file mode 100644 index 0000000000..a42c56b7c6 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilderProvider.java @@ -0,0 +1,14 @@ +package org.bouncycastle.openpgp.operator.bc; + +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilder; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilderProvider; + +public class BcPBESecretKeyDecryptorBuilderProvider + implements PBESecretKeyDecryptorBuilderProvider +{ + @Override + public PBESecretKeyDecryptorBuilder provide() + { + return new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilder.java index d99af1cc70..d08c9fc190 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilder.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilder.java @@ -15,9 +15,11 @@ import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilder; import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; public class JcePBESecretKeyDecryptorBuilder + implements PBESecretKeyDecryptorBuilder { private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); private PGPDigestCalculatorProvider calculatorProvider; diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilderProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilderProvider.java new file mode 100644 index 0000000000..bc67caa84c --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilderProvider.java @@ -0,0 +1,23 @@ +package org.bouncycastle.openpgp.operator.jcajce; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilder; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilderProvider; + +public class JcePBESecretKeyDecryptorBuilderProvider + implements PBESecretKeyDecryptorBuilderProvider +{ + private final JcaPGPDigestCalculatorProviderBuilder digestCalculatorProviderBuilder; + + public JcePBESecretKeyDecryptorBuilderProvider(JcaPGPDigestCalculatorProviderBuilder digestCalculatorProviderBuilder) + { + this.digestCalculatorProviderBuilder = digestCalculatorProviderBuilder; + } + + @Override + public PBESecretKeyDecryptorBuilder provide() + throws PGPException + { + return new JcePBESecretKeyDecryptorBuilder(digestCalculatorProviderBuilder.build()); + } +} From bbc24ded89c602bd414135e6e8534bf711310640 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 3 Dec 2024 12:05:01 +0100 Subject: [PATCH 08/12] KeyIdentifier changes --- .../org/bouncycastle/bcpg/KeyIdentifier.java | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/pg/src/main/java/org/bouncycastle/bcpg/KeyIdentifier.java b/pg/src/main/java/org/bouncycastle/bcpg/KeyIdentifier.java index 927751b7ab..6fb2ce63f1 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/KeyIdentifier.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/KeyIdentifier.java @@ -1,6 +1,5 @@ package org.bouncycastle.bcpg; -import java.util.Iterator; import java.util.List; import org.bouncycastle.util.Arrays; @@ -17,6 +16,11 @@ public class KeyIdentifier private final byte[] fingerprint; private final long keyId; + public KeyIdentifier(String hexEncoded) + { + this(Hex.decode(hexEncoded)); + } + /** * Create a new {@link KeyIdentifier} based on a keys fingerprint. * For fingerprints matching the format of a v4, v5 or v6 key, the constructor will @@ -157,6 +161,26 @@ public boolean matches(KeyIdentifier other) } } + public static boolean matches(List identifiers, KeyIdentifier identifier, boolean explicit) + { + for (KeyIdentifier candidate : identifiers) + { + if (!explicit && candidate.isWildcard()) + { + return true; + } + + if (candidate.getFingerprint() != null && + Arrays.constantTimeAreEqual(candidate.getFingerprint(), identifier.getFingerprint())) + { + return true; + } + + return candidate.getKeyId() == identifier.getKeyId(); + } + return false; + } + /** * Return true, if this {@link KeyIdentifier} is present in the given list of {@link KeyIdentifier} . * This will return true if a fingerprint matches, or if a key-id matches, @@ -167,9 +191,9 @@ public boolean matches(KeyIdentifier other) */ public boolean isPresentIn(List others) { - for (Iterator it = others.iterator(); it.hasNext();) + for (KeyIdentifier other : others) { - if (this.matches((KeyIdentifier)it.next())) + if (this.matches(other)) { return true; } @@ -178,6 +202,35 @@ public boolean isPresentIn(List others) return false; } + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (this == obj) + { + return true; + } + if (!(obj instanceof KeyIdentifier)) + { + return false; + } + KeyIdentifier other = (KeyIdentifier) obj; + if (getFingerprint() != null && other.getFingerprint() != null) + { + return Arrays.constantTimeAreEqual(getFingerprint(), other.getFingerprint()); + } + return getKeyId() == other.getKeyId(); + } + + @Override + public int hashCode() + { + return (int) getKeyId(); + } + public String toString() { if (isWildcard()) From 0b6c1d6ef641536704bed1dd4994fb2d95d4d8a7 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 3 Dec 2024 12:05:26 +0100 Subject: [PATCH 09/12] PGPEncryptedDataGenerator: Allow extraction of session-key --- .../openpgp/PGPEncryptedDataGenerator.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataGenerator.java index 8bf0ca6d7e..a650449c5a 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataGenerator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataGenerator.java @@ -89,6 +89,7 @@ public class PGPEncryptedDataGenerator // If true, force generation of a session key, even if we only have a single password-based encryption method // and could therefore use the S2K output as session key directly. private boolean forceSessionKey = true; + private SessionKeyExtractionCallback sessionKeyExtractionCallback = null; /** * Base constructor. @@ -178,6 +179,11 @@ private byte[] createSessionInfo( return sessionInfo; } + public void setSessionKeyExtractionCallback(SessionKeyExtractionCallback callback) + { + this.sessionKeyExtractionCallback = callback; + } + /** * Create an OutputStream based on the configured methods. *

@@ -252,6 +258,11 @@ else if (directS2K) messageKey = sessionKey; } + if (sessionKeyExtractionCallback != null) + { + sessionKeyExtractionCallback.extractSessionKey(new PGPSessionKey(defAlgorithm, sessionKey)); + } + PGPDataEncryptor dataEncryptor = dataEncryptorBuilder.build(messageKey); digestCalc = dataEncryptor.getIntegrityCalculator(); @@ -579,4 +590,9 @@ public void close() this.finish(); } } + + public interface SessionKeyExtractionCallback + { + void extractSessionKey(PGPSessionKey sessionKey); + } } From 81d47ab53b6aa22e4cc556792ce7637bc870abe6 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 3 Dec 2024 12:44:01 +0100 Subject: [PATCH 10/12] PGPEncryptedDataList: Expose encrypted data packet --- .../java/org/bouncycastle/openpgp/PGPEncryptedDataList.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataList.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataList.java index 2f55f519e7..7c2cf62c20 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataList.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataList.java @@ -154,6 +154,11 @@ public PGPEncryptedData get( return (PGPEncryptedData)methods.get(index); } + public InputStreamPacket getEncryptedData() + { + return data; + } + /** * Gets the number of encryption methods in this list. */ From 0ffd502fe6a312033ac940491069897a3087cfd4 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 3 Dec 2024 12:44:53 +0100 Subject: [PATCH 11/12] PGPSignature: Add isRevocation, isHardRevocation methods --- .../bouncycastle/openpgp/PGPSignature.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java index 79419f1a11..996b4e2876 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java @@ -23,6 +23,8 @@ import org.bouncycastle.bcpg.TrustPacket; import org.bouncycastle.bcpg.sig.IssuerFingerprint; import org.bouncycastle.bcpg.sig.IssuerKeyID; +import org.bouncycastle.bcpg.sig.RevocationReason; +import org.bouncycastle.bcpg.sig.RevocationReasonTags; import org.bouncycastle.math.ec.rfc8032.Ed25519; import org.bouncycastle.math.ec.rfc8032.Ed448; import org.bouncycastle.openpgp.operator.PGPContentVerifier; @@ -905,6 +907,37 @@ public static boolean isCertification(int signatureType) || PGPSignature.POSITIVE_CERTIFICATION == signatureType; } + public static boolean isRevocation(int signatureType) + { + return PGPSignature.KEY_REVOCATION == signatureType + || PGPSignature.CERTIFICATION_REVOCATION == signatureType + || PGPSignature.SUBKEY_REVOCATION == signatureType; + } + + public boolean isHardRevocation() + { + if (!isRevocation(getSignatureType())) + { + return false; // no revocation + } + + if (!hasSubpackets()) + { + return true; // consider missing subpackets (and therefore missing reason) as hard revocation + } + + // only consider reasons from the hashed packet area + RevocationReason reason = getHashedSubPackets() != null ? + getHashedSubPackets().getRevocationReason() : null; + if (reason == null) + { + return true; // missing reason packet is hard + } + + return reason.getRevocationReason() == RevocationReasonTags.NO_REASON // No reason is hard + || reason.getRevocationReason() == RevocationReasonTags.KEY_COMPROMISED; // key compromise is hard + } + /** * Return true, if the cryptographic signature encoding of the two signatures match. * From 9b96a7d4e112e2fa3217fdc49fae25bbbaf204d8 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 3 Dec 2024 12:06:37 +0100 Subject: [PATCH 12/12] Fix typo in isNotNull error message --- .../java/org/bouncycastle/bcpg/test/AbstractPacketTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pg/src/test/java/org/bouncycastle/bcpg/test/AbstractPacketTest.java b/pg/src/test/java/org/bouncycastle/bcpg/test/AbstractPacketTest.java index ca4b36710d..6c160d7dd9 100644 --- a/pg/src/test/java/org/bouncycastle/bcpg/test/AbstractPacketTest.java +++ b/pg/src/test/java/org/bouncycastle/bcpg/test/AbstractPacketTest.java @@ -118,7 +118,7 @@ public void isNull(String message, Object value) */ public void isNotNull(Object value) { - isNotNull("Value is not null.", value); + isNotNull("Value is null.", value); } /**