KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > Acme > Crypto > EncryptedOutputStream


1 // EncryptedOutputStream - an OutputStream that supports encryption
2
//
3
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions
7
// are met:
8
// 1. Redistributions of source code must retain the above copyright
9
// notice, this list of conditions and the following disclaimer.
10
// 2. Redistributions in binary form must reproduce the above copyright
11
// notice, this list of conditions and the following disclaimer in the
12
// documentation and/or other materials provided with the distribution.
13
//
14
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
// SUCH DAMAGE.
25
//
26
// Visit the ACME Labs Java page for up-to-date versions of this and other
27
// fine Java utilities: http://www.acme.com/java/
28

29 package Acme.Crypto;
30
31 import java.io.*;
32
33 /// An OutputStream that supports encryption.
34
// <P>
35
// This class encapsulates a StreamCipher or BlockCipher as an OutputStream.
36
// You set up your cipher, pass it and the underlying stream to the
37
// EncryptedOutputStream constructor, and then write your cleartext to
38
// this stream. It gets encrypted and sent to the underlying stream.
39
// Decryption is done by an EncryptedInputStream.
40
// <P>
41
// When used with a StreamCipher, no output protocol is necessary, each
42
// byte of cleartext turns into one byte of ciphertext. When used with a
43
// BlockCipher it's more complicated. First, the raw BlockCipher gets
44
// encapsulated into a CbcBlockCipher, which needs an initialization
45
// vector; so each encrypted stream automatically starts off with such
46
// a vector. After that, the stream is a series of (block,bytecount)
47
// pairs. Each block of cleartext is encrypted into a block of ciphertext,
48
// sent to the stream, and then one more byte is sent that says how
49
// many bytes in the block are valid. Generally the bytecount will
50
// be equal to the block size, but it can be less if the stream gets
51
// flushed or closed on a partial block.
52
// <P>
53
// <A HREF="../../../resources/classes/Acme/Crypto/EncryptedOutputStream.java">Fetch the software.</A><BR>
54
// <A HREF="../../../resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
55
// <P>
56
// @see EncryptedInputStream
57
// @see StreamCipher
58
// @see BlockCipher
59
// @see CbcBlockCipher
60

61 public class EncryptedOutputStream extends FilterOutputStream
62     {
63
64     // The basic block cipher to use.
65
private BlockCipher blockCipher = null;
66
67     // The stream cipher to use.
68
private StreamCipher streamCipher = null;
69
70     // The cipher to use.
71
private Cipher cipher;
72
73     // The CBC block cipher to use.
74
private CbcBlockCipher cbcBlockCipher;
75
76     // Number of bytes in a block.
77
private int blockSize;
78
79     // Number of bytes available for ciphertext in a block.
80
private int cryptoSize;
81
82     // Block of bytes to be encrypted.
83
private byte[] clearText;
84
85     // Block of bytes that have been encrypted.
86
private byte[] cipherText;
87
88     // How many valid bytes are in the clearText block.
89
private int byteCount;
90
91     /// Constructor for block ciphers.
92
// @param blockCipher The cipher to use, e.g. DesCipher, IdeaCipher
93
// @param out The raw output stream that we will be encrypting to.
94
public EncryptedOutputStream( BlockCipher blockCipher, OutputStream out ) throws IOException
95     {
96     super( out );
97     this.blockCipher = blockCipher;
98     this.blockSize = blockCipher.blockSize();
99     cbcBlockCipher = new CbcBlockCipher( blockCipher );
100     cryptoSize = blockSize;
101     clearText = new byte[blockSize];
102     cipherText = new byte[blockSize];
103     byteCount = 0;
104     this.cipher = blockCipher;
105     // Set a random IV and send it.
106
out.write( cbcBlockCipher.setRandomIv(), 0, blockSize );
107     }
108
109     /// Constructor for stream ciphers.
110
// @param streamCipher The cipher to use, e.g. Rc4Cipher, Rot13Cipher
111
// @param out The raw output stream that we will be encrypting to.
112
public EncryptedOutputStream( StreamCipher streamCipher, OutputStream out )
113     {
114     super( out );
115     this.streamCipher = streamCipher;
116     this.blockSize = 1;
117     this.cipher = streamCipher;
118     }
119     
120
121     /// Set the key.
122
public void setKey( String JavaDoc keyStr )
123     {
124     cipher.setKey( keyStr );
125     }
126
127
128     // Whether we are currently encrypting output or not.
129
private boolean encrypting = true;
130
131     /// Encrypting can be enabled or disabled temporarily.
132
public void setEncrypting( boolean encrypting ) throws IOException
133     {
134     if ( this.encrypting && ! encrypting )
135         flush();
136     this.encrypting = encrypting;
137     }
138
139
140     private void sendBlock() throws IOException
141     {
142     // Fill up the block with random bytes, if necessary.
143
for ( int i = byteCount; i < cryptoSize; ++i )
144         clearText[i] = (byte) ( Math.random() * 256.0 );
145     // Encrypt it.
146
cbcBlockCipher.encrypt( clearText, 0, cipherText, 0 );
147     // Send the block.
148
out.write( cipherText, 0, blockSize );
149     // Write out a count of valid bytes.
150
out.write( (byte) byteCount );
151     byteCount = 0;
152     }
153
154     /// Write a byte.
155
public void write( int b ) throws IOException
156     {
157     if ( encrypting )
158         {
159         if ( blockCipher != null )
160         {
161         clearText[byteCount++] = (byte) b;
162         if ( byteCount >= cryptoSize )
163             sendBlock();
164         }
165         else
166         // Stream cipher.
167
out.write( streamCipher.encrypt( (byte) b ) );
168         }
169     else
170         // Not encrypting.
171
out.write( b );
172     }
173     
174     /// Write some bytes.
175
public void write( byte b[], int off, int len ) throws IOException
176     {
177     if ( encrypting )
178         {
179         if ( blockCipher != null )
180         {
181         for ( int i = off; i < off + len; ++i )
182             {
183             clearText[byteCount++] = b[i];
184             if ( byteCount >= cryptoSize )
185             sendBlock();
186             }
187         }
188         else
189         {
190         // Stream cipher.
191
byte[] cipherText = new byte[len];
192         streamCipher.encrypt( b, off, cipherText, 0, len );
193         out.write( cipherText, 0, len );
194         }
195         }
196     else
197         // Not encrypting.
198
out.write( b, off, len );
199     }
200
201
202     /// Flush the stream. This will write any buffered output bytes.
203
public void flush() throws IOException
204     {
205     if ( encrypting && blockCipher != null && byteCount != 0 )
206         sendBlock();
207     out.flush();
208     }
209
210     }
211
Popular Tags