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