1 /* 2 * Copyright (c) 1997, 2014, 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 overriden 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 */ getMoreData()112 private int getMoreData() throws IOException { 113 // Android-changed: The method was creating a new object every time update(byte[], int, int) 114 // or doFinal() was called resulting in the old object being GCed. With do(byte[], int) and 115 // update(byte[], int, int, byte[], int), we use already initialized obuffer. 116 if (done) return -1; 117 ofinish = 0; 118 ostart = 0; 119 int expectedOutputSize = cipher.getOutputSize(ibuffer.length); 120 if (obuffer == null || expectedOutputSize > obuffer.length) { 121 obuffer = new byte[expectedOutputSize]; 122 } 123 int readin = input.read(ibuffer); 124 if (readin == -1) { 125 done = true; 126 try { 127 // doFinal resets the cipher and it is the final call that is made. If there isn't 128 // any more byte available, it returns 0. In case of any exception is raised, 129 // obuffer will get reset and therefore, it is equivalent to no bytes returned. 130 ofinish = cipher.doFinal(obuffer, 0); 131 } catch (IllegalBlockSizeException | BadPaddingException e) { 132 obuffer = null; 133 throw new IOException(e); 134 } catch (ShortBufferException e) { 135 obuffer = null; 136 throw new IllegalStateException("ShortBufferException is not expected", e); 137 } 138 } else { 139 // update returns number of bytes stored in obuffer. 140 try { 141 ofinish = cipher.update(ibuffer, 0, readin, obuffer, 0); 142 } catch (IllegalStateException e) { 143 obuffer = null; 144 throw e; 145 } catch (ShortBufferException e) { 146 // Should not reset the value of ofinish as the cipher is still not invalidated. 147 obuffer = null; 148 throw new IllegalStateException("ShortBufferException is not expected", e); 149 } 150 } 151 return ofinish; 152 } 153 154 /** 155 * Constructs a CipherInputStream from an InputStream and a 156 * Cipher. 157 * <br>Note: if the specified input stream or cipher is 158 * null, a NullPointerException may be thrown later when 159 * they are used. 160 * @param is the to-be-processed input stream 161 * @param c an initialized Cipher object 162 */ CipherInputStream(InputStream is, Cipher c)163 public CipherInputStream(InputStream is, Cipher c) { 164 super(is); 165 input = is; 166 cipher = c; 167 } 168 169 /** 170 * Constructs a CipherInputStream from an InputStream without 171 * specifying a Cipher. This has the effect of constructing a 172 * CipherInputStream using a NullCipher. 173 * <br>Note: if the specified input stream is null, a 174 * NullPointerException may be thrown later when it is used. 175 * @param is the to-be-processed input stream 176 */ CipherInputStream(InputStream is)177 protected CipherInputStream(InputStream is) { 178 super(is); 179 input = is; 180 cipher = new NullCipher(); 181 } 182 183 /** 184 * Reads the next byte of data from this input stream. The value 185 * byte is returned as an <code>int</code> in the range 186 * <code>0</code> to <code>255</code>. If no byte is available 187 * because the end of the stream has been reached, the value 188 * <code>-1</code> is returned. This method blocks until input data 189 * is available, the end of the stream is detected, or an exception 190 * is thrown. 191 * <p> 192 * 193 * @return the next byte of data, or <code>-1</code> if the end of the 194 * stream is reached. 195 * @exception IOException if an I/O error occurs. 196 * @since JCE1.2 197 */ read()198 public int read() throws IOException { 199 if (ostart >= ofinish) { 200 // we loop for new data as the spec says we are blocking 201 int i = 0; 202 while (i == 0) i = getMoreData(); 203 if (i == -1) return -1; 204 } 205 return ((int) obuffer[ostart++] & 0xff); 206 }; 207 208 /** 209 * Reads up to <code>b.length</code> bytes of data from this input 210 * stream into an array of bytes. 211 * <p> 212 * The <code>read</code> method of <code>InputStream</code> calls 213 * the <code>read</code> method of three arguments with the arguments 214 * <code>b</code>, <code>0</code>, and <code>b.length</code>. 215 * 216 * @param b the buffer into which the data is read. 217 * @return the total number of bytes read into the buffer, or 218 * <code>-1</code> is there is no more data because the end of 219 * the stream has been reached. 220 * @exception IOException if an I/O error occurs. 221 * @see java.io.InputStream#read(byte[], int, int) 222 * @since JCE1.2 223 */ read(byte b[])224 public int read(byte b[]) throws IOException { 225 return read(b, 0, b.length); 226 } 227 228 /** 229 * Reads up to <code>len</code> bytes of data from this input stream 230 * into an array of bytes. This method blocks until some input is 231 * available. If the first argument is <code>null,</code> up to 232 * <code>len</code> bytes are read and discarded. 233 * 234 * @param b the buffer into which the data is read. 235 * @param off the start offset in the destination array 236 * <code>buf</code> 237 * @param len the maximum number of bytes read. 238 * @return the total number of bytes read into the buffer, or 239 * <code>-1</code> if there is no more data because the end of 240 * the stream has been reached. 241 * @exception IOException if an I/O error occurs. 242 * @see java.io.InputStream#read() 243 * @since JCE1.2 244 */ read(byte b[], int off, int len)245 public int read(byte b[], int off, int len) throws IOException { 246 if (ostart >= ofinish) { 247 // we loop for new data as the spec says we are blocking 248 int i = 0; 249 while (i == 0) i = getMoreData(); 250 if (i == -1) return -1; 251 } 252 if (len <= 0) { 253 return 0; 254 } 255 int available = ofinish - ostart; 256 if (len < available) available = len; 257 if (b != null) { 258 System.arraycopy(obuffer, ostart, b, off, available); 259 } 260 ostart = ostart + available; 261 return available; 262 } 263 264 /** 265 * Skips <code>n</code> bytes of input from the bytes that can be read 266 * from this input stream without blocking. 267 * 268 * <p>Fewer bytes than requested might be skipped. 269 * The actual number of bytes skipped is equal to <code>n</code> or 270 * the result of a call to 271 * {@link #available() available}, 272 * whichever is smaller. 273 * If <code>n</code> is less than zero, no bytes are skipped. 274 * 275 * <p>The actual number of bytes skipped is returned. 276 * 277 * @param n the number of bytes to be skipped. 278 * @return the actual number of bytes skipped. 279 * @exception IOException if an I/O error occurs. 280 * @since JCE1.2 281 */ skip(long n)282 public long skip(long n) throws IOException { 283 int available = ofinish - ostart; 284 if (n > available) { 285 n = available; 286 } 287 if (n < 0) { 288 return 0; 289 } 290 ostart += n; 291 return n; 292 } 293 294 /** 295 * Returns the number of bytes that can be read from this input 296 * stream without blocking. The <code>available</code> method of 297 * <code>InputStream</code> returns <code>0</code>. This method 298 * <B>should</B> be overridden by subclasses. 299 * 300 * @return the number of bytes that can be read from this input stream 301 * without blocking. 302 * @exception IOException if an I/O error occurs. 303 * @since JCE1.2 304 */ available()305 public int available() throws IOException { 306 return (ofinish - ostart); 307 } 308 309 /** 310 * Closes this input stream and releases any system resources 311 * associated with the stream. 312 * <p> 313 * The <code>close</code> method of <code>CipherInputStream</code> 314 * calls the <code>close</code> method of its underlying input 315 * stream. 316 * 317 * @exception IOException if an I/O error occurs. 318 * @since JCE1.2 319 */ close()320 public void close() throws IOException { 321 if (closed) { 322 return; 323 } 324 325 closed = true; 326 input.close(); 327 328 // Android-removed: Removed a now-inaccurate comment 329 if (!done) { 330 try { 331 cipher.doFinal(); 332 } 333 catch (BadPaddingException | IllegalBlockSizeException ex) { 334 // Android-changed: Added throw if bad tag is seen. See b/31590622. 335 if (ex instanceof AEADBadTagException) { 336 throw new IOException(ex); 337 } 338 } 339 } 340 ostart = 0; 341 ofinish = 0; 342 } 343 344 /** 345 * Tests if this input stream supports the <code>mark</code> 346 * and <code>reset</code> methods, which it does not. 347 * 348 * @return <code>false</code>, since this class does not support the 349 * <code>mark</code> and <code>reset</code> methods. 350 * @see java.io.InputStream#mark(int) 351 * @see java.io.InputStream#reset() 352 * @since JCE1.2 353 */ markSupported()354 public boolean markSupported() { 355 return false; 356 } 357 } 358