00001 // EncryptedInputStream - an InputStream that supports encryption 00002 // 00003 // Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved. 00004 // 00005 // Redistribution and use in source and binary forms, with or without 00006 // modification, are permitted provided that the following conditions 00007 // are met: 00008 // 1. Redistributions of source code must retain the above copyright 00009 // notice, this list of conditions and the following disclaimer. 00010 // 2. Redistributions in binary form must reproduce the above copyright 00011 // notice, this list of conditions and the following disclaimer in the 00012 // documentation and/or other materials provided with the distribution. 00013 // 00014 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 00015 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00016 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00017 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 00018 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00019 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00020 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00021 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00022 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00023 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00024 // SUCH DAMAGE. 00025 // 00026 // Visit the ACME Labs Java page for up-to-date versions of this and other 00027 // fine Java utilities: http://www.acme.com/java/ 00028 00029 package Acme.Crypto; 00030 00031 import java.io.*; 00032 00034 // <P> 00035 // This class encapsulates a StreamCipher or BlockCipher as an InputStream. 00036 // You set up your cipher, pass it and the underlying stream to the 00037 // EncryptedInputStream constructor, and then read your cleartext from 00038 // this stream. It gets read from the underlying stream and decrypted. 00039 // Encryption is done by an EncryptedOutputStream. 00040 // <P> 00041 // When used with a StreamCipher, no input protocol is necessary, each 00042 // byte of ciphertext turns into one byte of cleartext. When used with a 00043 // BlockCipher it's more complicated. First, the raw BlockCipher gets 00044 // encapsulated into a CbcBlockCipher, which needs an initialization 00045 // vector; so each encrypted stream automatically starts off with such 00046 // a vector. After that, the stream is a series of (block,bytecount) 00047 // pairs. Each block of ciphertext is read from the stream, decrypted 00048 // into a block of cleartext, and then one more byte is read that says how 00049 // many bytes in the block are valid. Generally the bytecount will 00050 // be equal to the block size, but it can be less if the stream gets 00051 // flushed or closed on a partial block. 00052 // <P> 00053 // <A HREF="/resources/classes/Acme/Crypto/EncryptedInputStream.java">Fetch the software.</A><BR> 00054 // <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A> 00055 // <P> 00056 // @see EncryptedOutputStream 00057 // @see StreamCipher 00058 // @see BlockCipher 00059 // @see CbcBlockCipher 00060 00061 public class EncryptedInputStream extends FilterInputStream 00062 { 00063 00064 // The basic block cipher to use. 00065 private BlockCipher blockCipher = null; 00066 00067 // The stream cipher to use. 00068 private StreamCipher streamCipher = null; 00069 00070 // The cipher to use. 00071 private Cipher cipher; 00072 00073 // The CBC block cipher to use. 00074 private CbcBlockCipher cbcBlockCipher = null; 00075 00076 // Number of bytes in a block. 00077 private int blockSize; 00078 00079 // Number of bytes available for ciphertext in a block. 00080 private int cryptoSize; 00081 00082 // Block of bytes to be decrypted. 00083 private byte[] cipherText; 00084 00085 // Block of bytes that have been decrypted. 00086 private byte[] clearText; 00087 00088 // How many valid bytes are in the cipherText block. 00089 private int byteCount; 00090 00091 // How many decrypted bytes have been read. 00092 private int bytesRead; 00093 00095 // @param blockCipher The cipher to use, e.g. DesCipher, IdeaCipher 00096 // @param in The raw input stream that we will be decrypting. 00097 public EncryptedInputStream( BlockCipher blockCipher, InputStream in ) 00098 { 00099 super( in ); 00100 this.blockCipher = blockCipher; 00101 this.blockSize = blockCipher.blockSize(); 00102 cbcBlockCipher = new CbcBlockCipher( blockCipher ); 00103 this.cryptoSize = blockSize; 00104 cipherText = new byte[blockSize]; 00105 clearText = new byte[blockSize]; 00106 byteCount = 0; 00107 bytesRead = 0; 00108 this.cipher = blockCipher; 00109 } 00110 00112 // @param streamCipher The cipher to use, e.g. Rc4Cipher, Rot13Cipher 00113 // @param in The raw input stream that we will be decrypting. 00114 public EncryptedInputStream( StreamCipher streamCipher, InputStream in ) 00115 { 00116 super( in ); 00117 this.streamCipher = streamCipher; 00118 this.cipher = streamCipher; 00119 } 00120 00121 00122 private boolean inited = false; 00123 00124 private void init() throws IOException 00125 { 00126 if ( ! inited ) 00127 { 00128 inited = true; 00129 if ( blockCipher != null ) 00130 { 00131 // Read the IV from the stream and set it. 00132 byte[] iv = new byte[blockSize]; 00133 int r = Acme.Utils.read( in, iv, 0, blockSize ); 00134 if ( r == -1 || r != blockSize ) 00135 throw new IOException( "truncated initialization vector" ); 00136 cbcBlockCipher.setIv( iv ); 00137 } 00138 } 00139 } 00140 00141 00143 public void setKey( String keyStr ) 00144 { 00145 cipher.setKey( keyStr ); 00146 } 00147 00148 00149 // Whether we are currently decrypting input or not. 00150 private boolean decrypting = true; 00151 00153 public void setDecrypting( boolean decrypting ) throws IOException 00154 { 00155 if ( this.decrypting && ! decrypting ) 00156 { 00157 // !!! do something about unread decrypted bytes? 00158 } 00159 this.decrypting = decrypting; 00160 } 00161 00162 00163 // Read an encrypted block. Returns -1 on EOF. 00164 private int getBlock() throws IOException 00165 { 00166 int r = Acme.Utils.read( in, cipherText, 0, blockSize ); 00167 if ( r == -1 ) 00168 return -1; 00169 if ( r != blockSize ) 00170 throw new IOException( "truncated ciphertext block" ); 00171 // Decrypt the block. 00172 cbcBlockCipher.decrypt( cipherText, 0, clearText, 0 ); 00173 // Get the byte count. 00174 byteCount = in.read(); 00175 if ( byteCount == -1 ) 00176 throw new IOException( "missing ciphertext bytecount" ); 00177 if ( byteCount == 0 || byteCount > cryptoSize ) 00178 throw new IOException( "invalid ciphertext bytecount" ); 00179 bytesRead = 0; 00180 return byteCount; 00181 } 00182 00184 // @return -1 on EOF. 00185 public int read() throws IOException 00186 { 00187 init(); 00188 if ( decrypting ) 00189 { 00190 if ( blockCipher != null ) 00191 { 00192 if ( bytesRead >= byteCount ) 00193 if ( getBlock() == -1 ) 00194 return -1; 00195 return clearText[bytesRead++] & 0xff; 00196 } 00197 else 00198 { 00199 // Stream cipher. 00200 int r = in.read(); 00201 if ( r == -1 ) 00202 return -1; 00203 return streamCipher.decrypt( (byte) r ) & 0xff; 00204 } 00205 } 00206 else 00207 // Not decrypting. 00208 return in.read(); 00209 } 00210 00212 // of java.io.InputStream.read(byte[], int, int). The 00213 // standard version catches and ignores IOExceptions from 00214 // below; this version sends them on to the caller. 00215 public int read( byte[] b, int off, int len ) throws IOException 00216 { 00217 init(); 00218 if ( decrypting ) 00219 { 00220 if ( blockCipher != null ) 00221 // It would be tricky to optimize this to decrypt whole blocks. 00222 return Acme.Utils.read( this, b, off, len ); 00223 else 00224 { 00225 // Stream cipher. 00226 byte[] cipherText = new byte[len]; 00227 int r = Acme.Utils.read( in, cipherText, 0, len ); 00228 if ( r == -1 ) 00229 return -1; 00230 streamCipher.decrypt( cipherText, 0, b, off, r ); 00231 return r; 00232 } 00233 } 00234 else 00235 // Not decrypting. 00236 return Acme.Utils.read( in, b, off, len ); 00237 } 00238 00239 }