1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package javax.crypto; 19 20 import java.io.FilterInputStream; 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.security.GeneralSecurityException; 24 25 /** 26 * This class wraps an {@code InputStream} and a cipher so that {@code read()} 27 * methods return data that are read from the underlying {@code InputStream} and 28 * processed by the cipher. 29 * <p> 30 * The cipher must be initialized for the requested operation before being used 31 * by a {@code CipherInputStream}. For example, if a cipher initialized for 32 * decryption is used with a {@code CipherInputStream}, the {@code 33 * CipherInputStream} tries to read the data an decrypt them before returning. 34 */ 35 public class CipherInputStream extends FilterInputStream { 36 37 private final Cipher cipher; 38 private final int I_BUFFER_SIZE = 20; 39 private final byte[] i_buffer = new byte[I_BUFFER_SIZE]; 40 private int index; // index of the bytes to return from o_buffer 41 private byte[] o_buffer; 42 private boolean finished; 43 44 /** 45 * Creates a new {@code CipherInputStream} instance for an {@code 46 * InputStream} and a cipher. 47 * 48 * <p><strong>Warning:</strong> passing a null source creates an invalid 49 * {@code CipherInputStream}. All read operations on such a stream will 50 * fail. 51 * 52 * @param is 53 * the input stream to read data from. 54 * @param c 55 * the cipher to process the data with. 56 */ CipherInputStream(InputStream is, Cipher c)57 public CipherInputStream(InputStream is, Cipher c) { 58 super(is); 59 this.cipher = c; 60 } 61 62 /** 63 * Creates a new {@code CipherInputStream} instance for an {@code 64 * InputStream} without a cipher. 65 * <p> 66 * A {@code NullCipher} is created and used to process the data. 67 * 68 * @param is 69 * the input stream to read data from. 70 */ CipherInputStream(InputStream is)71 protected CipherInputStream(InputStream is) { 72 this(is, new NullCipher()); 73 } 74 75 /** 76 * Reads the next byte from this cipher input stream. 77 * 78 * @return the next byte, or {@code -1} if the end of the stream is reached. 79 * @throws IOException 80 * if an error occurs. 81 */ 82 @Override read()83 public int read() throws IOException { 84 if (finished) { 85 return ((o_buffer == null) || (index == o_buffer.length)) 86 ? -1 87 : o_buffer[index++] & 0xFF; 88 } 89 if ((o_buffer != null) && (index < o_buffer.length)) { 90 return o_buffer[index++] & 0xFF; 91 } 92 index = 0; 93 o_buffer = null; 94 int num_read; 95 while (o_buffer == null) { 96 if ((num_read = in.read(i_buffer)) == -1) { 97 try { 98 o_buffer = cipher.doFinal(); 99 } catch (Exception e) { 100 throw new IOException(e.getMessage()); 101 } 102 finished = true; 103 break; 104 } 105 o_buffer = cipher.update(i_buffer, 0, num_read); 106 } 107 return read(); 108 } 109 110 /** 111 * Reads the next {@code b.length} bytes from this input stream into buffer 112 * {@code b}. 113 * 114 * @param b 115 * the buffer to be filled with data. 116 * @return the number of bytes filled into buffer {@code b}, or {@code -1} 117 * if the end of the stream is reached. 118 * @throws IOException 119 * if an error occurs. 120 */ 121 @Override read(byte[] b)122 public int read(byte[] b) throws IOException { 123 return read(b, 0, b.length); 124 } 125 126 /** 127 * Reads the next {@code len} bytes from this input stream into buffer 128 * {@code b} starting at offset {@code off}. 129 * <p> 130 * if {@code b} is {@code null}, the next {@code len} bytes are read and 131 * discarded. 132 * 133 * @param b 134 * the buffer to be filled with data. 135 * @param off 136 * the offset to start in the buffer. 137 * @param len 138 * the maximum number of bytes to read. 139 * @return the number of bytes filled into buffer {@code b}, or {@code -1} 140 * of the of the stream is reached. 141 * @throws IOException 142 * if an error occurs. 143 * @throws NullPointerException 144 * if the underlying input stream is {@code null}. 145 */ 146 @Override read(byte[] b, int off, int len)147 public int read(byte[] b, int off, int len) throws IOException { 148 if (in == null) { 149 throw new NullPointerException("Underlying input stream is null"); 150 } 151 152 int read_b; 153 int i; 154 for (i=0; i<len; i++) { 155 if ((read_b = read()) == -1) { 156 return (i == 0) ? -1 : i; 157 } 158 if (b != null) { 159 b[off+i] = (byte) read_b; 160 } 161 } 162 return i; 163 } 164 165 /** 166 * Skips up to n bytes from this input stream. 167 * <p> 168 * The number of bytes skipped depends on the result of a call to 169 * {@link CipherInputStream#available() available}. The smaller of n and the 170 * result are the number of bytes being skipped. 171 * 172 * @param n 173 * the number of bytes that should be skipped. 174 * @return the number of bytes actually skipped. 175 * @throws IOException 176 * if an error occurs 177 */ 178 @Override skip(long n)179 public long skip(long n) throws IOException { 180 long i = 0; 181 int available = available(); 182 if (available < n) { 183 n = available; 184 } 185 while ((i < n) && (read() != -1)) { 186 i++; 187 } 188 return i; 189 } 190 191 @Override available()192 public int available() throws IOException { 193 return 0; 194 } 195 196 /** 197 * Closes this {@code CipherInputStream}, also closes the underlying input 198 * stream and call {@code doFinal} on the cipher object. 199 * 200 * @throws IOException 201 * if an error occurs. 202 */ 203 @Override close()204 public void close() throws IOException { 205 in.close(); 206 try { 207 cipher.doFinal(); 208 } catch (GeneralSecurityException ignore) { 209 //do like RI does 210 } 211 212 } 213 214 /** 215 * Returns whether this input stream supports {@code mark} and 216 * {@code reset}, which it does not. 217 * 218 * @return false, since this input stream does not support {@code mark} and 219 * {@code reset}. 220 */ 221 @Override markSupported()222 public boolean markSupported() { 223 return false; 224 } 225 } 226