Main Page | Packages | Class Hierarchy | Class List | Directories | File List | Class Members | Related Pages

EncryptedInputStream.java

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     }

Generated on Wed Dec 14 21:05:32 2005 for OpenMobileIS by  doxygen 1.4.4