diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/collection/PGPKeyRingCollection.java b/pgpainless-core/src/main/java/org/pgpainless/key/collection/PGPKeyRingCollection.java deleted file mode 100644 index 6cf7102d..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/collection/PGPKeyRingCollection.java +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Paul Schaub , 2021 Flowcrypt a.s. -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.key.collection; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import javax.annotation.Nonnull; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPKeyRing; -import org.bouncycastle.openpgp.PGPMarker; -import org.bouncycastle.openpgp.PGPObjectFactory; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.pgpainless.implementation.ImplementationFactory; -import org.pgpainless.util.ArmorUtils; - -/** - * This class describes a logic of handling a collection of different {@link PGPKeyRing}. The logic was inspired by - * {@link PGPSecretKeyRingCollection} and {@link PGPPublicKeyRingCollection}. - */ -public class PGPKeyRingCollection { - - private final PGPSecretKeyRingCollection pgpSecretKeyRingCollection; - private final PGPPublicKeyRingCollection pgpPublicKeyRingCollection; - - public PGPKeyRingCollection(@Nonnull byte[] encoding, boolean isSilent) throws IOException, PGPException { - this(new ByteArrayInputStream(encoding), isSilent); - } - - /** - * Build a {@link PGPKeyRingCollection} from the passed in input stream. - * - * @param in input stream containing data - * @param isSilent flag indicating that unsupported objects will be ignored - * @throws IOException if a problem parsing the base stream occurs - * @throws PGPException if an object is encountered which isn't a {@link PGPSecretKeyRing} or {@link PGPPublicKeyRing} - */ - public PGPKeyRingCollection(@Nonnull InputStream in, boolean isSilent) throws IOException, PGPException { - // Double getDecoderStream because of #96 - InputStream decoderStream = ArmorUtils.getDecoderStream(in); - PGPObjectFactory pgpFact = ImplementationFactory.getInstance().getPGPObjectFactory(decoderStream); - Object obj; - - List secretKeyRings = new ArrayList<>(); - List publicKeyRings = new ArrayList<>(); - - while ((obj = pgpFact.nextObject()) != null) { - if (obj instanceof PGPMarker) { - // Skip marker packets - continue; - } - if (obj instanceof PGPSecretKeyRing) { - secretKeyRings.add((PGPSecretKeyRing) obj); - } else if (obj instanceof PGPPublicKeyRing) { - publicKeyRings.add((PGPPublicKeyRing) obj); - } else if (!isSilent) { - throw new PGPException(obj.getClass().getName() + " found where " + - PGPSecretKeyRing.class.getSimpleName() + " or " + - PGPPublicKeyRing.class.getSimpleName() + " expected"); - } - } - - pgpSecretKeyRingCollection = new PGPSecretKeyRingCollection(secretKeyRings); - pgpPublicKeyRingCollection = new PGPPublicKeyRingCollection(publicKeyRings); - } - - public PGPKeyRingCollection(@Nonnull Collection collection, boolean isSilent) - throws PGPException { - List secretKeyRings = new ArrayList<>(); - List publicKeyRings = new ArrayList<>(); - - for (PGPKeyRing pgpKeyRing : collection) { - if (pgpKeyRing instanceof PGPSecretKeyRing) { - secretKeyRings.add((PGPSecretKeyRing) pgpKeyRing); - } else if (pgpKeyRing instanceof PGPPublicKeyRing) { - publicKeyRings.add((PGPPublicKeyRing) pgpKeyRing); - } else if (!isSilent) { - throw new PGPException(pgpKeyRing.getClass().getName() + " found where " + - PGPSecretKeyRing.class.getSimpleName() + " or " + - PGPPublicKeyRing.class.getSimpleName() + " expected"); - } - } - - pgpSecretKeyRingCollection = new PGPSecretKeyRingCollection(secretKeyRings); - pgpPublicKeyRingCollection = new PGPPublicKeyRingCollection(publicKeyRings); - } - - public @Nonnull PGPSecretKeyRingCollection getPGPSecretKeyRingCollection() { - return pgpSecretKeyRingCollection; - } - - public @Nonnull PGPPublicKeyRingCollection getPgpPublicKeyRingCollection() { - return pgpPublicKeyRingCollection; - } - - /** - * Return the number of rings in this collection. - * - * @return total size of {@link PGPSecretKeyRingCollection} and {@link PGPPublicKeyRingCollection} - * in this collection - */ - public int size() { - return pgpSecretKeyRingCollection.size() + pgpPublicKeyRingCollection.size(); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/collection/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/collection/package-info.java deleted file mode 100644 index b2f5b153..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/collection/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: 2018 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -/** - * OpenPGP key collections. - */ -package org.pgpainless.key.collection; diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/collection/PGPKeyRingCollection.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/collection/PGPKeyRingCollection.kt new file mode 100644 index 00000000..63151a4c --- /dev/null +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/collection/PGPKeyRingCollection.kt @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub , 2021 Flowcrypt a.s. +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.key.collection + +import org.bouncycastle.openpgp.* +import org.pgpainless.implementation.ImplementationFactory +import org.pgpainless.util.ArmorUtils +import java.io.InputStream + +/** + * This class describes a logic of handling a collection of different [PGPKeyRing]. The logic was inspired by + * [PGPSecretKeyRingCollection] and [PGPPublicKeyRingCollection]. + */ +class PGPKeyRingCollection( + val pgpSecretKeyRingCollection: PGPSecretKeyRingCollection, + val pgpPublicKeyRingCollection: PGPPublicKeyRingCollection +) { + + constructor(encoding: ByteArray, isSilent: Boolean): this(encoding.inputStream(), isSilent) + + constructor(inputStream: InputStream, isSilent: Boolean): this(parse(inputStream, isSilent)) + + constructor(collection: Collection, isSilent: Boolean): this(segment(collection, isSilent)) + + private constructor(arguments: Pair): this(arguments.first, arguments.second) + + /** + * The number of rings in this collection. + * + * @return total size of [PGPSecretKeyRingCollection] plus [PGPPublicKeyRingCollection] in this collection + */ + val size: Int + get() = pgpSecretKeyRingCollection.size() + pgpPublicKeyRingCollection.size() + + fun size() = size + + @Deprecated("Wrong case of PGP -> Pgp", ReplaceWith("getPgpSecretKeyRingCollection()")) + fun getPGPSecretKeyRingCollection() = pgpSecretKeyRingCollection + + companion object { + @JvmStatic + private fun parse(inputStream: InputStream, isSilent: Boolean): Pair { + val secretKeyRings = mutableListOf() + val certificates = mutableListOf() + // Double getDecoderStream because of #96 + val objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(ArmorUtils.getDecoderStream(inputStream)) + + for (obj in objectFactory) { + if (obj == null) { + break + } + + if (obj is PGPMarker) { + // Skip marker packets + continue + } + + if (obj is PGPSecretKeyRing) { + secretKeyRings.add(obj) + continue + } + + if (obj is PGPPublicKeyRing) { + certificates.add(obj) + continue + } + + if (!isSilent) { + throw PGPException("${obj.javaClass.name} found where ${PGPSecretKeyRing::class.java.simpleName}" + + " or ${PGPPublicKeyRing::class.java.simpleName} expected") + } + } + + return PGPSecretKeyRingCollection(secretKeyRings) to PGPPublicKeyRingCollection(certificates) + } + + @JvmStatic + private fun segment(collection: Collection, isSilent: Boolean): Pair { + val secretKeyRings = mutableListOf() + val certificates = mutableListOf() + + for (keyRing in collection) { + if (keyRing is PGPSecretKeyRing) { + secretKeyRings.add(keyRing) + } else if (keyRing is PGPPublicKeyRing) { + certificates.add(keyRing) + } else if (!isSilent) { + throw PGPException("${keyRing.javaClass.name} found where ${PGPSecretKeyRing::class.java.simpleName}" + + " or ${PGPPublicKeyRing::class.java.simpleName} expected") + } + } + + return PGPSecretKeyRingCollection(secretKeyRings) to PGPPublicKeyRingCollection(certificates) + } + } +} \ No newline at end of file diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/collection/PGPKeyRingCollectionTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/collection/PGPKeyRingCollectionTest.java index 89b0fccf..fd5530ba 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/collection/PGPKeyRingCollectionTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/collection/PGPKeyRingCollectionTest.java @@ -52,7 +52,7 @@ public class PGPKeyRingCollectionTest { // silent = true -> No exception, but not keys either PGPKeyRingCollection collection = new PGPKeyRingCollection(bytes, true); assertEquals(0, collection.getPgpPublicKeyRingCollection().size()); - assertEquals(0, collection.getPGPSecretKeyRingCollection().size()); + assertEquals(0, collection.getPgpSecretKeyRingCollection().size()); } @Test @@ -63,7 +63,7 @@ public class PGPKeyRingCollectionTest { Collection keys = Arrays.asList(first, second, secondPub); PGPKeyRingCollection collection = new PGPKeyRingCollection(keys, true); - assertEquals(2, collection.getPGPSecretKeyRingCollection().size()); + assertEquals(2, collection.getPgpSecretKeyRingCollection().size()); assertEquals(1, collection.getPgpPublicKeyRingCollection().size()); } }