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 }