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 }