org.bouncycastle.openpgp.PGPEncryptedData.java Source code

Java tutorial

Introduction

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

Source

package org.bouncycastle.openpgp;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.bouncycastle.bcpg.InputStreamPacket;
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.openpgp.operator.PGPDataDecryptor;
import org.bouncycastle.openpgp.operator.PGPDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
import org.bouncycastle.util.Arrays;

/**
 * A PGP encrypted data object.
 * <p>
 * Encrypted data packets are decrypted using a {@link PGPDataDecryptor} obtained from a
 * {@link PGPDataDecryptorFactory}.
 * </p>
 */
public abstract class PGPEncryptedData implements SymmetricKeyAlgorithmTags {
    protected class TruncatedStream extends InputStream {
        int[] lookAhead = new int[22];
        int bufPtr;
        InputStream in;

        TruncatedStream(InputStream in) throws IOException {
            for (int i = 0; i != lookAhead.length; i++) {
                if ((lookAhead[i] = in.read()) < 0) {
                    throw new EOFException();
                }
            }

            bufPtr = 0;
            this.in = in;
        }

        public int read() throws IOException {
            int ch = in.read();

            if (ch >= 0) {
                int c = lookAhead[bufPtr];

                lookAhead[bufPtr] = ch;
                bufPtr = (bufPtr + 1) % lookAhead.length;

                return c;
            }

            return -1;
        }

        int[] getLookAhead() {
            int[] tmp = new int[lookAhead.length];
            int count = 0;

            for (int i = bufPtr; i != lookAhead.length; i++) {
                tmp[count++] = lookAhead[i];
            }
            for (int i = 0; i != bufPtr; i++) {
                tmp[count++] = lookAhead[i];
            }

            return tmp;
        }
    }

    InputStreamPacket encData;
    InputStream encStream;
    TruncatedStream truncStream;
    PGPDigestCalculator integrityCalculator;

    PGPEncryptedData(InputStreamPacket encData) {
        this.encData = encData;
    }

    /**
     * Return the raw input stream for the data stream.
     * <p>
     * Note this stream is shared with all other encryption methods in the same
     * {@link PGPEncryptedDataList} and with any decryption methods in sub-classes, so consuming
     * this stream will affect decryption.
     * </p>
     * @return the encrypted data in this packet.
     */
    public InputStream getInputStream() {
        return encData.getInputStream();
    }

    /**
     * Checks whether the packet is integrity protected.
     *
     * @return <code>true</code> if there is a modification detection code package associated with
     *         this stream
     */
    public boolean isIntegrityProtected() {
        return (encData instanceof SymmetricEncIntegrityPacket);
    }

    /**
     * Verifies the integrity of the packet against the modification detection code associated with
     * it in the stream.
     * <p>
     * Note: This can only be called after the message has been read.
     * </p>
     * @return <code>true</code> if the message verifies, <code>false</code> otherwise.
     * @throws PGPException if the message is not {@link #isIntegrityProtected() integrity
     *             protected}.
     */
    public boolean verify() throws PGPException, IOException {
        if (!this.isIntegrityProtected()) {
            throw new PGPException("data not integrity protected.");
        }

        //
        // make sure we are at the end.
        //
        while (encStream.read() >= 0) {
            // do nothing
        }

        //
        // process the MDC packet
        //
        int[] lookAhead = truncStream.getLookAhead();

        OutputStream dOut = integrityCalculator.getOutputStream();

        dOut.write((byte) lookAhead[0]);
        dOut.write((byte) lookAhead[1]);

        byte[] digest = integrityCalculator.getDigest();
        byte[] streamDigest = new byte[digest.length];

        for (int i = 0; i != streamDigest.length; i++) {
            streamDigest[i] = (byte) lookAhead[i + 2];
        }

        return Arrays.constantTimeAreEqual(digest, streamDigest);
    }
}