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