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