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 */ 174 public int read() throws IOException { 175 if (ostart >= ofinish) { 176 // we loop for new data as the spec says we are blocking 177 int i = 0; 178 while (i == 0) i = getMoreData(); 179 if (i == -1) return -1; 180 } 181 return ((int) obuffer[ostart++] & 0xff); 182 }; 183 184 /** 185 * Reads up to <code>b.length</code> bytes of data from this input 186 * stream into an array of bytes. 187 * <p> 188 * The <code>read</code> method of <code>InputStream</code> calls 189 * the <code>read</code> method of three arguments with the arguments 190 * <code>b</code>, <code>0</code>, and <code>b.length</code>. 191 * 192 * @param b the buffer into which the data is read. 193 * @return the total number of bytes read into the buffer, or 194 * <code>-1</code> is there is no more data because the end of 195 * the stream has been reached. 196 * @exception IOException if an I/O error occurs. 197 * @see java.io.InputStream#read(byte[], int, int) 198 */ 199 public int read(byte b[]) throws IOException { 200 return read(b, 0, b.length); 201 } 202 203 /** 204 * Reads up to <code>len</code> bytes of data from this input stream 205 * into an array of bytes. This method blocks until some input is 206 * available. If the first argument is <code>null,</code> up to 207 * <code>len</code> bytes are read and discarded. 208 * 209 * @param b the buffer into which the data is read. 210 * @param off the start offset in the destination array 211 * <code>buf</code> 212 * @param len the maximum number of bytes read. 213 * @return the total number of bytes read into the buffer, or 214 * <code>-1</code> if there is no more data because the end of 215 * the stream has been reached. 216 * @exception IOException if an I/O error occurs. 217 * @see java.io.InputStream#read() 218 */ 219 public int read(byte b[], int off, int len) throws IOException { 220 if (ostart >= ofinish) { 221 // we loop for new data as the spec says we are blocking 222 int i = 0; 223 while (i == 0) i = getMoreData(); 224 if (i == -1) return -1; 225 } 226 if (len <= 0) { 227 return 0; 228 } 229 int available = ofinish - ostart; 230 if (len < available) available = len; 231 if (b != null) { 232 System.arraycopy(obuffer, ostart, b, off, available); 233 } 234 ostart = ostart + available; 235 return available; 236 } 237 238 /** 239 * Skips <code>n</code> bytes of input from the bytes that can be read 240 * from this input stream without blocking. 241 * 242 * <p>Fewer bytes than requested might be skipped. 243 * The actual number of bytes skipped is equal to <code>n</code> or 244 * the result of a call to 245 * {@link #available() available}, 246 * whichever is smaller. 247 * If <code>n</code> is less than zero, no bytes are skipped. 248 * 249 * <p>The actual number of bytes skipped is returned. 250 * 251 * @param n the number of bytes to be skipped. 252 * @return the actual number of bytes skipped. 253 * @exception IOException if an I/O error occurs. 254 */ 255 public long skip(long n) throws IOException { 256 int available = ofinish - ostart; 257 if (n > available) { 258 n = available; 259 } 260 if (n < 0) { 261 return 0; 262 } 263 ostart += n; 264 return n; 265 } 266 267 /** 268 * Returns the number of bytes that can be read from this input 269 * stream without blocking. The <code>available</code> method of 270 * <code>InputStream</code> returns <code>0</code>. This method 271 * <B>should</B> be overridden by subclasses. 272 * 273 * @return the number of bytes that can be read from this input stream 274 * without blocking. 275 * @exception IOException if an I/O error occurs. 276 */ 277 public int available() throws IOException { 278 return (ofinish - ostart); 279 } 280 281 /** 282 * Closes this input stream and releases any system resources 283 * associated with the stream. 284 * <p> 285 * The <code>close</code> method of <code>CipherInputStream</code> 286 * calls the <code>close</code> method of its underlying input 287 * stream. 288 * 289 * @exception IOException if an I/O error occurs. 290 */ 291 public void close() throws IOException { 292 if (closed) { 293 return; 294 } 295 296 closed = true; 297 input.close(); 298 try { 299 // throw away the unprocessed data 300 if (!done) { 301 cipher.doFinal(); 302 } 303 } 304 catch (BadPaddingException | IllegalBlockSizeException ex) { 305 } 306 ostart = 0; 307 ofinish = 0; 308 } 309 310 /** 311 * Tests if this input stream supports the <code>mark</code> 312 * and <code>reset</code> methods, which it does not. 313 * 314 * @return <code>false</code>, since this class does not support the 315 * <code>mark</code> and <code>reset</code> methods. 316 * @see java.io.InputStream#mark(int) 317 * @see java.io.InputStream#reset() 318 */ 319 public boolean markSupported() { 320 return false; 321 } 322 }