001: package ch.ethz.ssh2.crypto.cipher;
002:
003: import java.io.IOException;
004: import java.io.OutputStream;
005:
006: /**
007: * CipherOutputStream.
008: *
009: * @author Christian Plattner, plattner@inf.ethz.ch
010: * @version $Id: CipherOutputStream.java,v 1.4 2005/12/05 17:13:27 cplattne Exp $
011: */
012: public class CipherOutputStream {
013: BlockCipher currentCipher;
014: OutputStream bo;
015: byte[] buffer;
016: byte[] enc;
017: int blockSize;
018: int pos;
019:
020: /*
021: * We cannot use java.io.BufferedOutputStream, since that is not available
022: * in J2ME. Everything could be improved here alot.
023: */
024:
025: final int BUFF_SIZE = 2048;
026: byte[] out_buffer = new byte[BUFF_SIZE];
027: int out_buffer_pos = 0;
028:
029: public CipherOutputStream(BlockCipher tc, OutputStream bo) {
030: this .bo = bo;
031: changeCipher(tc);
032: }
033:
034: private void internal_write(byte[] src, int off, int len)
035: throws IOException {
036: while (len > 0) {
037: int space = BUFF_SIZE - out_buffer_pos;
038: int copy = (len > space) ? space : len;
039:
040: System
041: .arraycopy(src, off, out_buffer, out_buffer_pos,
042: copy);
043:
044: off += copy;
045: out_buffer_pos += copy;
046: len -= copy;
047:
048: if (out_buffer_pos >= BUFF_SIZE) {
049: bo.write(out_buffer, 0, BUFF_SIZE);
050: out_buffer_pos = 0;
051: }
052: }
053: }
054:
055: private void internal_write(int b) throws IOException {
056: out_buffer[out_buffer_pos++] = (byte) b;
057: if (out_buffer_pos >= BUFF_SIZE) {
058: bo.write(out_buffer, 0, BUFF_SIZE);
059: out_buffer_pos = 0;
060: }
061: }
062:
063: public void flush() throws IOException {
064: if (pos != 0)
065: throw new IOException(
066: "FATAL: cannot flush since crypto buffer is not aligned.");
067:
068: if (out_buffer_pos > 0) {
069: bo.write(out_buffer, 0, out_buffer_pos);
070: out_buffer_pos = 0;
071: }
072: bo.flush();
073: }
074:
075: public void changeCipher(BlockCipher bc) {
076: this .currentCipher = bc;
077: blockSize = bc.getBlockSize();
078: buffer = new byte[blockSize];
079: enc = new byte[blockSize];
080: pos = 0;
081: }
082:
083: private void writeBlock() throws IOException {
084: try {
085: currentCipher.transformBlock(buffer, 0, enc, 0);
086: } catch (Exception e) {
087: throw (IOException) new IOException(
088: "Error while decrypting block.").initCause(e);
089: }
090:
091: internal_write(enc, 0, blockSize);
092: pos = 0;
093: }
094:
095: public void write(byte[] src, int off, int len) throws IOException {
096: while (len > 0) {
097: int avail = blockSize - pos;
098: int copy = Math.min(avail, len);
099:
100: System.arraycopy(src, off, buffer, pos, copy);
101: pos += copy;
102: off += copy;
103: len -= copy;
104:
105: if (pos >= blockSize)
106: writeBlock();
107: }
108: }
109:
110: public void write(int b) throws IOException {
111: buffer[pos++] = (byte) b;
112: if (pos >= blockSize)
113: writeBlock();
114: }
115:
116: public void writePlain(int b) throws IOException {
117: if (pos != 0)
118: throw new IOException(
119: "Cannot write plain since crypto buffer is not aligned.");
120: internal_write(b);
121: }
122:
123: public void writePlain(byte[] b, int off, int len)
124: throws IOException {
125: if (pos != 0)
126: throw new IOException(
127: "Cannot write plain since crypto buffer is not aligned.");
128: internal_write(b, off, len);
129: }
130: }
|