blob: c9055ab5548b369d7996005fd6263fd3a9e422b7 [file] [log] [blame]
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;
}
}