148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/*
248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Please refer to the LICENSE.txt for licensing details.
448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */
548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodpackage ch.ethz.ssh2.crypto.cipher;
648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.IOException;
848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.InputStream;
948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
1048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/**
1148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * CipherInputStream.
1248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood *
1348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @author Christian Plattner
1448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @version $Id: CipherInputStream.java 11 2011-05-27 14:14:06Z dkocher@sudo.ch $
1548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */
1648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodpublic class CipherInputStream
1748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood{
1848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	BlockCipher currentCipher;
1948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	InputStream bi;
2048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	byte[] buffer;
2148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	byte[] enc;
2248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	int blockSize;
2348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	int pos;
2448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
2548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	/*
2648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	 * We cannot use java.io.BufferedInputStream, since that is not available in
2748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	 * J2ME. Everything could be improved alot here.
2848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	 */
2948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
3048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	private static final int BUFF_SIZE = 8192;
3148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	byte[] input_buffer = new byte[BUFF_SIZE];
3248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	int input_buffer_pos = 0;
3348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	int input_buffer_size = 0;
3448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
3548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public CipherInputStream(BlockCipher tc, InputStream bi)
3648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
3748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		this.bi = bi;
3848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		changeCipher(tc);
3948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
4048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
4148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	private int fill_buffer() throws IOException
4248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
4348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		input_buffer_pos = 0;
4448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		input_buffer_size = 0;
4548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		input_buffer_size = bi.read(input_buffer, 0, BUFF_SIZE);
4648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return input_buffer_size;
4748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
4848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
4948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	private int internal_read(byte[] b, int off, int len) throws IOException
5048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
5148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (input_buffer_size < 0)
5248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
5348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			return -1;
5448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
5548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
5648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (input_buffer_pos >= input_buffer_size)
5748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
5848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			if (fill_buffer() <= 0)
5948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			{
6048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				return -1;
6148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			}
6248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
6348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
6448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int avail = input_buffer_size - input_buffer_pos;
6548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int thiscopy = (len > avail) ? avail : len;
6648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
6748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		System.arraycopy(input_buffer, input_buffer_pos, b, off, thiscopy);
6848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		input_buffer_pos += thiscopy;
6948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
7048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return thiscopy;
7148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
7248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
7348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public void changeCipher(BlockCipher bc)
7448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
7548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		this.currentCipher = bc;
7648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		blockSize = bc.getBlockSize();
7748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		buffer = new byte[blockSize];
7848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		enc = new byte[blockSize];
7948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		pos = blockSize;
8048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
8148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
8248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	private void getBlock() throws IOException
8348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
8448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int n = 0;
8548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		while (n < blockSize)
8648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
8748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			int len = internal_read(enc, n, blockSize - n);
8848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			if (len < 0)
8948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			{
9048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				throw new IOException("Cannot read full block, EOF reached.");
9148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			}
9248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			n += len;
9348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
9448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
9548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		try
9648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
9748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			currentCipher.transformBlock(enc, 0, buffer, 0);
9848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
9948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		catch (Exception e)
10048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
10148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			throw new IOException("Error while decrypting block.");
10248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
10348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		pos = 0;
10448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
10548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
10648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public int read(byte[] dst) throws IOException
10748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
10848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return read(dst, 0, dst.length);
10948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
11048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
11148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public int read(byte[] dst, int off, int len) throws IOException
11248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
11348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int count = 0;
11448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
11548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		while (len > 0)
11648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
11748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			if (pos >= blockSize)
11848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			{
11948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				getBlock();
12048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			}
12148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
12248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			int avail = blockSize - pos;
12348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			int copy = Math.min(avail, len);
12448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			System.arraycopy(buffer, pos, dst, off, copy);
12548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			pos += copy;
12648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			off += copy;
12748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			len -= copy;
12848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			count += copy;
12948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
13048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return count;
13148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
13248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
13348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public int read() throws IOException
13448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
13548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (pos >= blockSize)
13648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
13748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			getBlock();
13848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
13948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return buffer[pos++] & 0xff;
14048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
14148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
14248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public int readPlain(byte[] b, int off, int len) throws IOException
14348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
14448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (pos != blockSize)
14548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
14648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			throw new IOException("Cannot read plain since crypto buffer is not aligned.");
14748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
14848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int n = 0;
14948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		while (n < len)
15048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
15148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			int cnt = internal_read(b, off + n, len - n);
15248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			if (cnt < 0)
15348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			{
15448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				throw new IOException("Cannot fill buffer, EOF reached.");
15548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			}
15648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			n += cnt;
15748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
15848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return n;
15948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
16048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood}
161