pgpainless/pgpainless-core/src/main/java/org/pgpainless/key/collection/PGPKeyRingCollection.java

115 lines
4.8 KiB
Java

// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>, 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<PGPSecretKeyRing> secretKeyRings = new ArrayList<>();
List<PGPPublicKeyRing> 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<PGPKeyRing> collection, boolean isSilent)
throws PGPException {
List<PGPSecretKeyRing> secretKeyRings = new ArrayList<>();
List<PGPPublicKeyRing> 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();
}
}