Home | History | Annotate | Download | only in cipher
      1 /*
      2  * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
      3  * Please refer to the LICENSE.txt for licensing details.
      4  */
      5 package ch.ethz.ssh2.crypto.cipher;
      6 
      7 import java.io.IOException;
      8 import java.io.InputStream;
      9 
     10 /**
     11  * CipherInputStream.
     12  *
     13  * @author Christian Plattner
     14  * @version $Id: CipherInputStream.java 11 2011-05-27 14:14:06Z dkocher (at) sudo.ch $
     15  */
     16 public class CipherInputStream
     17 {
     18 	BlockCipher currentCipher;
     19 	InputStream bi;
     20 	byte[] buffer;
     21 	byte[] enc;
     22 	int blockSize;
     23 	int pos;
     24 
     25 	/*
     26 	 * We cannot use java.io.BufferedInputStream, since that is not available in
     27 	 * J2ME. Everything could be improved alot here.
     28 	 */
     29 
     30 	private static final int BUFF_SIZE = 8192;
     31 	byte[] input_buffer = new byte[BUFF_SIZE];
     32 	int input_buffer_pos = 0;
     33 	int input_buffer_size = 0;
     34 
     35 	public CipherInputStream(BlockCipher tc, InputStream bi)
     36 	{
     37 		this.bi = bi;
     38 		changeCipher(tc);
     39 	}
     40 
     41 	private int fill_buffer() throws IOException
     42 	{
     43 		input_buffer_pos = 0;
     44 		input_buffer_size = 0;
     45 		input_buffer_size = bi.read(input_buffer, 0, BUFF_SIZE);
     46 		return input_buffer_size;
     47 	}
     48 
     49 	private int internal_read(byte[] b, int off, int len) throws IOException
     50 	{
     51 		if (input_buffer_size < 0)
     52 		{
     53 			return -1;
     54 		}
     55 
     56 		if (input_buffer_pos >= input_buffer_size)
     57 		{
     58 			if (fill_buffer() <= 0)
     59 			{
     60 				return -1;
     61 			}
     62 		}
     63 
     64 		int avail = input_buffer_size - input_buffer_pos;
     65 		int thiscopy = (len > avail) ? avail : len;
     66 
     67 		System.arraycopy(input_buffer, input_buffer_pos, b, off, thiscopy);
     68 		input_buffer_pos += thiscopy;
     69 
     70 		return thiscopy;
     71 	}
     72 
     73 	public void changeCipher(BlockCipher bc)
     74 	{
     75 		this.currentCipher = bc;
     76 		blockSize = bc.getBlockSize();
     77 		buffer = new byte[blockSize];
     78 		enc = new byte[blockSize];
     79 		pos = blockSize;
     80 	}
     81 
     82 	private void getBlock() throws IOException
     83 	{
     84 		int n = 0;
     85 		while (n < blockSize)
     86 		{
     87 			int len = internal_read(enc, n, blockSize - n);
     88 			if (len < 0)
     89 			{
     90 				throw new IOException("Cannot read full block, EOF reached.");
     91 			}
     92 			n += len;
     93 		}
     94 
     95 		try
     96 		{
     97 			currentCipher.transformBlock(enc, 0, buffer, 0);
     98 		}
     99 		catch (Exception e)
    100 		{
    101 			throw new IOException("Error while decrypting block.");
    102 		}
    103 		pos = 0;
    104 	}
    105 
    106 	public int read(byte[] dst) throws IOException
    107 	{
    108 		return read(dst, 0, dst.length);
    109 	}
    110 
    111 	public int read(byte[] dst, int off, int len) throws IOException
    112 	{
    113 		int count = 0;
    114 
    115 		while (len > 0)
    116 		{
    117 			if (pos >= blockSize)
    118 			{
    119 				getBlock();
    120 			}
    121 
    122 			int avail = blockSize - pos;
    123 			int copy = Math.min(avail, len);
    124 			System.arraycopy(buffer, pos, dst, off, copy);
    125 			pos += copy;
    126 			off += copy;
    127 			len -= copy;
    128 			count += copy;
    129 		}
    130 		return count;
    131 	}
    132 
    133 	public int read() throws IOException
    134 	{
    135 		if (pos >= blockSize)
    136 		{
    137 			getBlock();
    138 		}
    139 		return buffer[pos++] & 0xff;
    140 	}
    141 
    142 	public int readPlain(byte[] b, int off, int len) throws IOException
    143 	{
    144 		if (pos != blockSize)
    145 		{
    146 			throw new IOException("Cannot read plain since crypto buffer is not aligned.");
    147 		}
    148 		int n = 0;
    149 		while (n < len)
    150 		{
    151 			int cnt = internal_read(b, off + n, len - n);
    152 			if (cnt < 0)
    153 			{
    154 				throw new IOException("Cannot fill buffer, EOF reached.");
    155 			}
    156 			n += cnt;
    157 		}
    158 		return n;
    159 	}
    160 }
    161