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); } }