org.bouncycastle.openpgp.PGPObjectFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.bouncycastle.openpgp.PGPObjectFactory.java

Source

package org.bouncycastle.openpgp;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.PacketTags;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.util.Iterable;

/**
 * General class for reading a PGP object stream.
 * <p>
 * Note: if this class finds a {@link PGPPublicKey} or a {@link PGPSecretKey} it will create a
 * {@link PGPPublicKeyRing}, or a {@link PGPSecretKeyRing} for each key found. If all you are trying
 * to do is read a key ring file use either {@link PGPPublicKeyRingCollection} or
 * {@link PGPSecretKeyRingCollection}.
 * </p><p>
 * This factory supports reading the following types of objects: </p>
 * <ul>
 * <li>{@link PacketTags#SIGNATURE} - produces a {@link PGPSignatureList}</li>
 * <li>{@link PacketTags#SECRET_KEY} - produces a {@link PGPSecretKeyRing}</li>
 * <li>{@link PacketTags#PUBLIC_KEY} - produces a {@link PGPPublicKeyRing}</li>
 * <li>{@link PacketTags#PUBLIC_SUBKEY} - produces a {@link PGPPublicKey}</li>
 * <li>{@link PacketTags#COMPRESSED_DATA} - produces a {@link PGPCompressedData}</li>
 * <li>{@link PacketTags#LITERAL_DATA} - produces a {@link PGPLiteralData}</li>
 * <li>{@link PacketTags#PUBLIC_KEY_ENC_SESSION} - produces a {@link PGPEncryptedDataList}</li>
 * <li>{@link PacketTags#SYMMETRIC_KEY_ENC_SESSION} - produces a {@link PGPEncryptedDataList}</li>
 * <li>{@link PacketTags#ONE_PASS_SIGNATURE} - produces a {@link PGPOnePassSignatureList}</li>
 * <li>{@link PacketTags#MARKER} - produces a {@link PGPMarker}</li>
 * </ul>
 *
 */
public class PGPObjectFactory implements Iterable {
    private BCPGInputStream in;
    private KeyFingerPrintCalculator fingerPrintCalculator;

    /**
     * Create an object factory suitable for reading PGP objects such as keys, key rings and key
     * ring collections, or PGP encrypted data.
     *
     * @param in stream to read PGP data from.
     * @param fingerPrintCalculator calculator to use in key finger print calculations.
     */
    public PGPObjectFactory(InputStream in, KeyFingerPrintCalculator fingerPrintCalculator) {
        this.in = new BCPGInputStream(in);
        this.fingerPrintCalculator = fingerPrintCalculator;
    }

    /**
     * Create an object factory suitable for reading PGP objects such as keys, key rings and key
     * ring collections, or PGP encrypted data.
     *
     * @param bytes PGP encoded data.
     * @param fingerPrintCalculator calculator to use in key finger print calculations.
     */
    public PGPObjectFactory(byte[] bytes, KeyFingerPrintCalculator fingerPrintCalculator) {
        this(new ByteArrayInputStream(bytes), fingerPrintCalculator);
    }

    /**
     * Return the next object in the stream, or <code>null</code> if the end of stream is reached.
     *
     * @return one of the supported objects - see class docs for details.
     * @throws IOException if an error occurs reading from the wrapped stream or parsing data.
     */
    public Object nextObject() throws IOException {
        List l;

        switch (in.nextPacketTag()) {
        case -1:
            return null;
        case PacketTags.SIGNATURE:
            l = new ArrayList();

            while (in.nextPacketTag() == PacketTags.SIGNATURE) {
                try {
                    l.add(new PGPSignature(in));
                } catch (PGPException e) {
                    throw new IOException("can't create signature object: " + e);
                }
            }

            return new PGPSignatureList((PGPSignature[]) l.toArray(new PGPSignature[l.size()]));
        case PacketTags.SECRET_KEY:
            try {
                return new PGPSecretKeyRing(in, fingerPrintCalculator);
            } catch (PGPException e) {
                throw new IOException("can't create secret key object: " + e);
            }
        case PacketTags.PUBLIC_KEY:
            return new PGPPublicKeyRing(in, fingerPrintCalculator);
        case PacketTags.PUBLIC_SUBKEY:
            try {
                return PGPPublicKeyRing.readSubkey(in, fingerPrintCalculator);
            } catch (PGPException e) {
                throw new IOException("processing error: " + e.getMessage());
            }
        case PacketTags.COMPRESSED_DATA:
            return new PGPCompressedData(in);
        case PacketTags.LITERAL_DATA:
            return new PGPLiteralData(in);
        case PacketTags.PUBLIC_KEY_ENC_SESSION:
        case PacketTags.SYMMETRIC_KEY_ENC_SESSION:
            return new PGPEncryptedDataList(in);
        case PacketTags.ONE_PASS_SIGNATURE:
            l = new ArrayList();

            while (in.nextPacketTag() == PacketTags.ONE_PASS_SIGNATURE) {
                try {
                    l.add(new PGPOnePassSignature(in));
                } catch (PGPException e) {
                    throw new IOException("can't create one pass signature object: " + e);
                }
            }

            return new PGPOnePassSignatureList(
                    (PGPOnePassSignature[]) l.toArray(new PGPOnePassSignature[l.size()]));
        case PacketTags.MARKER:
            return new PGPMarker(in);
        case PacketTags.EXPERIMENTAL_1:
        case PacketTags.EXPERIMENTAL_2:
        case PacketTags.EXPERIMENTAL_3:
        case PacketTags.EXPERIMENTAL_4:
            return in.readPacket();
        }

        throw new IOException("unknown object in stream: " + in.nextPacketTag());
    }

    /**
     * Support method for Iterable where available.
     */
    public Iterator iterator() {
        return new Iterator() {
            private boolean triedNext = false;
            private Object obj = null;

            public boolean hasNext() {
                if (!triedNext) {
                    triedNext = true;
                    obj = getObject();
                }
                return obj != null;
            }

            public Object next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                triedNext = false;

                return obj;
            }

            public void remove() {
                throw new UnsupportedOperationException("Cannot remove element from factory.");
            }

            private Object getObject() {
                try {
                    return PGPObjectFactory.this.nextObject();
                } catch (IOException e) {
                    throw new PGPRuntimeOperationException("Iterator failed to get next object: " + e.getMessage(),
                            e);
                }
            }
        };
    }
}