1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.crypto;
  27 
  28 import java.io.*;
  29 
  30 /**
  31  * A CipherInputStream is composed of an InputStream and a Cipher so
  32  * that read() methods return data that are read in from the
  33  * underlying InputStream but have been additionally processed by the
  34  * Cipher.  The Cipher must be fully initialized before being used by
  35  * a CipherInputStream.
  36  *
  37  * <p> For example, if the Cipher is initialized for decryption, the
  38  * CipherInputStream will attempt to read in data and decrypt them,
  39  * before returning the decrypted data.
  40  *
  41  * <p> This class adheres strictly to the semantics, especially the
  42  * failure semantics, of its ancestor classes
  43  * java.io.FilterInputStream and java.io.InputStream.  This class has
  44  * exactly those methods specified in its ancestor classes, and
  45  * overrides them all.  Moreover, this class catches all exceptions
  46  * that are not thrown by its ancestor classes.  In particular, the
  47  * <code>skip</code> method skips, and the <code>available</code>
  48  * method counts only data that have been processed by the encapsulated Cipher.
  49  *
  50  * <p> It is crucial for a programmer using this class not to use
  51  * methods that are not defined or overriden in this class (such as a
  52  * new method or constructor that is later added to one of the super
  53  * classes), because the design and implementation of those methods
  54  * are unlikely to have considered security impact with regard to
  55  * CipherInputStream.
  56  *
  57  * @author  Li Gong
  58  * @see     java.io.InputStream
  59  * @see     java.io.FilterInputStream
  60  * @see     javax.crypto.Cipher
  61  * @see     javax.crypto.CipherOutputStream
  62  *
  63  * @since 1.4
  64  */
  65 
  66 public class CipherInputStream extends FilterInputStream {
  67 
  68     // the cipher engine to use to process stream data
  69     private Cipher cipher;
  70 
  71     // the underlying input stream
  72     private InputStream input;
  73 
  74     /* the buffer holding data that have been read in from the
  75        underlying stream, but have not been processed by the cipher
  76        engine. the size 512 bytes is somewhat randomly chosen */
  77     private byte[] ibuffer = new byte[512];
  78 
  79     // having reached the end of the underlying input stream
  80     private boolean done = false;
  81 
  82     /* the buffer holding data that have been processed by the cipher
  83        engine, but have not been read out */
  84     private byte[] obuffer;
  85     // the offset pointing to the next "new" byte
  86     private int ostart = 0;
  87     // the offset pointing to the last "new" byte
  88     private int ofinish = 0;
  89     // stream status
  90     private boolean closed = false;
  91 
  92     /**
  93      * private convenience function.
  94      *
  95      * Entry condition: ostart = ofinish
  96      *
  97      * Exit condition: ostart <= ofinish
  98      *
  99      * return (ofinish-ostart) (we have this many bytes for you)
 100      * return 0 (no data now, but could have more later)
 101      * return -1 (absolutely no more data)
 102      */
 103     private int getMoreData() throws IOException {
 104         if (done) return -1;
 105         int readin = input.read(ibuffer);
 106         if (readin == -1) {
 107             done = true;
 108             try {
 109                 obuffer = cipher.doFinal();
 110             }
 111             catch (IllegalBlockSizeException e) {obuffer = null;}
 112             catch (BadPaddingException e) {obuffer = null;}
 113             if (obuffer == null)
 114                 return -1;
 115             else {
 116                 ostart = 0;
 117                 ofinish = obuffer.length;
 118                 return ofinish;
 119             }
 120         }
 121         try {
 122             obuffer = cipher.update(ibuffer, 0, readin);
 123         } catch (IllegalStateException e) {obuffer = null;};
 124         ostart = 0;
 125         if (obuffer == null)
 126             ofinish = 0;
 127         else ofinish = obuffer.length;
 128         return ofinish;
 129     }
 130 
 131     /**
 132      * Constructs a CipherInputStream from an InputStream and a
 133      * Cipher.
 134      * <br>Note: if the specified input stream or cipher is
 135      * null, a NullPointerException may be thrown later when
 136      * they are used.
 137      * @param is the to-be-processed input stream
 138      * @param c an initialized Cipher object
 139      */
 140     public CipherInputStream(InputStream is, Cipher c) {
 141         super(is);
 142         input = is;
 143         cipher = c;
 144     }
 145 
 146     /**
 147      * Constructs a CipherInputStream from an InputStream without
 148      * specifying a Cipher. This has the effect of constructing a
 149      * CipherInputStream using a NullCipher.
 150      * <br>Note: if the specified input stream is null, a
 151      * NullPointerException may be thrown later when it is used.
 152      * @param is the to-be-processed input stream
 153      */
 154     protected CipherInputStream(InputStream is) {
 155         super(is);
 156         input = is;
 157         cipher = new NullCipher();
 158     }
 159 
 160     /**
 161      * Reads the next byte of data from this input stream. The value
 162      * byte is returned as an <code>int</code> in the range
 163      * <code>0</code> to <code>255</code>. If no byte is available
 164      * because the end of the stream has been reached, the value
 165      * <code>-1</code> is returned. This method blocks until input data
 166      * is available, the end of the stream is detected, or an exception
 167      * is thrown.
 168      * <p>
 169      *
 170      * @return  the next byte of data, or <code>-1</code> if the end of the
 171      *          stream is reached.
 172      * @exception  IOException  if an I/O error occurs.
 173      * @since 1.4, JCE1.2
 174      */
 175     public int read() throws IOException {
 176         if (ostart >= ofinish) {
 177             // we loop for new data as the spec says we are blocking
 178             int i = 0;
 179             while (i == 0) i = getMoreData();
 180             if (i == -1) return -1;
 181         }
 182         return ((int) obuffer[ostart++] & 0xff);
 183     };
 184 
 185     /**
 186      * Reads up to <code>b.length</code> bytes of data from this input
 187      * stream into an array of bytes.
 188      * <p>
 189      * The <code>read</code> method of <code>InputStream</code> calls
 190      * the <code>read</code> method of three arguments with the arguments
 191      * <code>b</code>, <code>0</code>, and <code>b.length</code>.
 192      *
 193      * @param      b   the buffer into which the data is read.
 194      * @return     the total number of bytes read into the buffer, or
 195      *             <code>-1</code> is there is no more data because the end of
 196      *             the stream has been reached.
 197      * @exception  IOException  if an I/O error occurs.
 198      * @see        java.io.InputStream#read(byte[], int, int)
 199      * @since      1.4, JCE1.2
 200      */
 201     public int read(byte b[]) throws IOException {
 202         return read(b, 0, b.length);
 203     }
 204 
 205     /**
 206      * Reads up to <code>len</code> bytes of data from this input stream
 207      * into an array of bytes. This method blocks until some input is
 208      * available. If the first argument is <code>null,</code> up to
 209      * <code>len</code> bytes are read and discarded.
 210      *
 211      * @param      b     the buffer into which the data is read.
 212      * @param      off   the start offset in the destination array
 213      *                   <code>buf</code>
 214      * @param      len   the maximum number of bytes read.
 215      * @return     the total number of bytes read into the buffer, or
 216      *             <code>-1</code> if there is no more data because the end of
 217      *             the stream has been reached.
 218      * @exception  IOException  if an I/O error occurs.
 219      * @see        java.io.InputStream#read()
 220      * @since      1.4, JCE1.2
 221      */
 222     public int read(byte b[], int off, int len) throws IOException {
 223         if (ostart >= ofinish) {
 224             // we loop for new data as the spec says we are blocking
 225             int i = 0;
 226             while (i == 0) i = getMoreData();
 227             if (i == -1) return -1;
 228         }
 229         if (len <= 0) {
 230             return 0;
 231         }
 232         int available = ofinish - ostart;
 233         if (len < available) available = len;
 234         if (b != null) {
 235             System.arraycopy(obuffer, ostart, b, off, available);
 236         }
 237         ostart = ostart + available;
 238         return available;
 239     }
 240 
 241     /**
 242      * Skips <code>n</code> bytes of input from the bytes that can be read
 243      * from this input stream without blocking.
 244      *
 245      * <p>Fewer bytes than requested might be skipped.
 246      * The actual number of bytes skipped is equal to <code>n</code> or
 247      * the result of a call to
 248      * {@link #available() available},
 249      * whichever is smaller.
 250      * If <code>n</code> is less than zero, no bytes are skipped.
 251      *
 252      * <p>The actual number of bytes skipped is returned.
 253      *
 254      * @param      n the number of bytes to be skipped.
 255      * @return     the actual number of bytes skipped.
 256      * @exception  IOException  if an I/O error occurs.
 257      * @since 1.4, JCE1.2
 258      */
 259     public long skip(long n) throws IOException {
 260         int available = ofinish - ostart;
 261         if (n > available) {
 262             n = available;
 263         }
 264         if (n < 0) {
 265             return 0;
 266         }
 267         ostart += n;
 268         return n;
 269     }
 270 
 271     /**
 272      * Returns the number of bytes that can be read from this input
 273      * stream without blocking. The <code>available</code> method of
 274      * <code>InputStream</code> returns <code>0</code>. This method
 275      * <B>should</B> be overridden by subclasses.
 276      *
 277      * @return     the number of bytes that can be read from this input stream
 278      *             without blocking.
 279      * @exception  IOException  if an I/O error occurs.
 280      * @since      1.4, JCE1.2
 281      */
 282     public int available() throws IOException {
 283         return (ofinish - ostart);
 284     }
 285 
 286     /**
 287      * Closes this input stream and releases any system resources
 288      * associated with the stream.
 289      * <p>
 290      * The <code>close</code> method of <code>CipherInputStream</code>
 291      * calls the <code>close</code> method of its underlying input
 292      * stream.
 293      *
 294      * @exception  IOException  if an I/O error occurs.
 295      * @since 1.4, JCE1.2
 296      */
 297     public void close() throws IOException {
 298         if (closed) {
 299             return;
 300         }
 301 
 302         closed = true;
 303         input.close();
 304         try {
 305             // throw away the unprocessed data
 306             if (!done) {
 307                 cipher.doFinal();
 308             }
 309         }
 310         catch (BadPaddingException | IllegalBlockSizeException ex) {
 311         }
 312         ostart = 0;
 313         ofinish = 0;
 314     }
 315 
 316     /**
 317      * Tests if this input stream supports the <code>mark</code>
 318      * and <code>reset</code> methods, which it does not.
 319      *
 320      * @return  <code>false</code>, since this class does not support the
 321      *          <code>mark</code> and <code>reset</code> methods.
 322      * @see     java.io.InputStream#mark(int)
 323      * @see     java.io.InputStream#reset()
 324      * @since   1.4, JCE1.2
 325      */
 326     public boolean markSupported() {
 327         return false;
 328     }
 329 }