| |
| package com.trilead.ssh2.crypto.cipher; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| |
| /** |
| * CipherInputStream. |
| * |
| * @author Christian Plattner, plattner@trilead.com |
| * @version $Id: CipherInputStream.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ |
| */ |
| public class CipherInputStream |
| { |
| BlockCipher currentCipher; |
| InputStream bi; |
| byte[] buffer; |
| byte[] enc; |
| int blockSize; |
| int pos; |
| |
| /* |
| * We cannot use java.io.BufferedInputStream, since that is not available in |
| * J2ME. Everything could be improved alot here. |
| */ |
| |
| final int BUFF_SIZE = 2048; |
| byte[] input_buffer = new byte[BUFF_SIZE]; |
| int input_buffer_pos = 0; |
| int input_buffer_size = 0; |
| |
| public CipherInputStream(BlockCipher tc, InputStream bi) |
| { |
| this.bi = bi; |
| changeCipher(tc); |
| } |
| |
| private int fill_buffer() throws IOException |
| { |
| input_buffer_pos = 0; |
| input_buffer_size = bi.read(input_buffer, 0, BUFF_SIZE); |
| return input_buffer_size; |
| } |
| |
| private int internal_read(byte[] b, int off, int len) throws IOException |
| { |
| if (input_buffer_size < 0) |
| return -1; |
| |
| if (input_buffer_pos >= input_buffer_size) |
| { |
| if (fill_buffer() <= 0) |
| return -1; |
| } |
| |
| int avail = input_buffer_size - input_buffer_pos; |
| int thiscopy = (len > avail) ? avail : len; |
| |
| System.arraycopy(input_buffer, input_buffer_pos, b, off, thiscopy); |
| input_buffer_pos += thiscopy; |
| |
| return thiscopy; |
| } |
| |
| public void changeCipher(BlockCipher bc) |
| { |
| this.currentCipher = bc; |
| blockSize = bc.getBlockSize(); |
| buffer = new byte[blockSize]; |
| enc = new byte[blockSize]; |
| pos = blockSize; |
| } |
| |
| private void getBlock() throws IOException |
| { |
| int n = 0; |
| while (n < blockSize) |
| { |
| int len = internal_read(enc, n, blockSize - n); |
| if (len < 0) |
| throw new IOException("Cannot read full block, EOF reached."); |
| n += len; |
| } |
| |
| try |
| { |
| currentCipher.transformBlock(enc, 0, buffer, 0); |
| } |
| catch (Exception e) |
| { |
| throw new IOException("Error while decrypting block."); |
| } |
| pos = 0; |
| } |
| |
| public int read(byte[] dst) throws IOException |
| { |
| return read(dst, 0, dst.length); |
| } |
| |
| public int read(byte[] dst, int off, int len) throws IOException |
| { |
| int count = 0; |
| |
| while (len > 0) |
| { |
| if (pos >= blockSize) |
| getBlock(); |
| |
| int avail = blockSize - pos; |
| int copy = Math.min(avail, len); |
| System.arraycopy(buffer, pos, dst, off, copy); |
| pos += copy; |
| off += copy; |
| len -= copy; |
| count += copy; |
| } |
| return count; |
| } |
| |
| public int read() throws IOException |
| { |
| if (pos >= blockSize) |
| { |
| getBlock(); |
| } |
| return buffer[pos++] & 0xff; |
| } |
| |
| public int readPlain(byte[] b, int off, int len) throws IOException |
| { |
| if (pos != blockSize) |
| throw new IOException("Cannot read plain since crypto buffer is not aligned."); |
| int n = 0; |
| while (n < len) |
| { |
| int cnt = internal_read(b, off + n, len - n); |
| if (cnt < 0) |
| throw new IOException("Cannot fill buffer, EOF reached."); |
| n += cnt; |
| } |
| return n; |
| } |
| } |