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.OutputStream;
      9 
     10 /**
     11  * CipherOutputStream.
     12  *
     13  * @author Christian Plattner
     14  * @version $Id: CipherOutputStream.java 11 2011-05-27 14:14:06Z dkocher (at) sudo.ch $
     15  */
     16 public class CipherOutputStream
     17 {
     18 	BlockCipher currentCipher;
     19 	OutputStream bo;
     20 	byte[] buffer;
     21 	byte[] enc;
     22 	int blockSize;
     23 	int pos;
     24 
     25 	/*
     26 	 * We cannot use java.io.BufferedOutputStream, since that is not available
     27 	 * in J2ME. Everything could be improved here alot.
     28 	 */
     29 
     30 	private static final int BUFF_SIZE = 8192;
     31 	byte[] out_buffer = new byte[BUFF_SIZE];
     32 	int out_buffer_pos = 0;
     33 
     34 	public CipherOutputStream(BlockCipher tc, OutputStream bo)
     35 	{
     36 		this.bo = bo;
     37 		changeCipher(tc);
     38 	}
     39 
     40 	private void internal_write(byte[] src, int off, int len) throws IOException
     41 	{
     42 		while (len > 0)
     43 		{
     44 			int space = BUFF_SIZE - out_buffer_pos;
     45 			int copy = (len > space) ? space : len;
     46 
     47 			System.arraycopy(src, off, out_buffer, out_buffer_pos, copy);
     48 
     49 			off += copy;
     50 			out_buffer_pos += copy;
     51 			len -= copy;
     52 
     53 			if (out_buffer_pos >= BUFF_SIZE)
     54 			{
     55 				bo.write(out_buffer, 0, BUFF_SIZE);
     56 				out_buffer_pos = 0;
     57 			}
     58 		}
     59 	}
     60 
     61 	private void internal_write(int b) throws IOException
     62 	{
     63 		out_buffer[out_buffer_pos++] = (byte) b;
     64 		if (out_buffer_pos >= BUFF_SIZE)
     65 		{
     66 			bo.write(out_buffer, 0, BUFF_SIZE);
     67 			out_buffer_pos = 0;
     68 		}
     69 	}
     70 
     71 	public void flush() throws IOException
     72 	{
     73 		if (pos != 0)
     74 		{
     75 			throw new IOException("FATAL: cannot flush since crypto buffer is not aligned.");
     76 		}
     77 
     78 		if (out_buffer_pos > 0)
     79 		{
     80 			bo.write(out_buffer, 0, out_buffer_pos);
     81 			out_buffer_pos = 0;
     82 		}
     83 		bo.flush();
     84 	}
     85 
     86 	public void changeCipher(BlockCipher bc)
     87 	{
     88 		this.currentCipher = bc;
     89 		blockSize = bc.getBlockSize();
     90 		buffer = new byte[blockSize];
     91 		enc = new byte[blockSize];
     92 		pos = 0;
     93 	}
     94 
     95 	private void writeBlock() throws IOException
     96 	{
     97 		try
     98 		{
     99 			currentCipher.transformBlock(buffer, 0, enc, 0);
    100 		}
    101 		catch (Exception e)
    102 		{
    103 			throw (IOException) new IOException("Error while decrypting block.").initCause(e);
    104 		}
    105 
    106 		internal_write(enc, 0, blockSize);
    107 		pos = 0;
    108 	}
    109 
    110 	public void write(byte[] src, int off, int len) throws IOException
    111 	{
    112 		while (len > 0)
    113 		{
    114 			int avail = blockSize - pos;
    115 			int copy = Math.min(avail, len);
    116 
    117 			System.arraycopy(src, off, buffer, pos, copy);
    118 			pos += copy;
    119 			off += copy;
    120 			len -= copy;
    121 
    122 			if (pos >= blockSize)
    123 			{
    124 				writeBlock();
    125 			}
    126 		}
    127 	}
    128 
    129 	public void write(int b) throws IOException
    130 	{
    131 		buffer[pos++] = (byte) b;
    132 		if (pos >= blockSize)
    133 		{
    134 			writeBlock();
    135 		}
    136 	}
    137 
    138 	public void writePlain(int b) throws IOException
    139 	{
    140 		if (pos != 0)
    141 		{
    142 			throw new IOException("Cannot write plain since crypto buffer is not aligned.");
    143 		}
    144 		internal_write(b);
    145 	}
    146 
    147 	public void writePlain(byte[] b, int off, int len) throws IOException
    148 	{
    149 		if (pos != 0)
    150 		{
    151 			throw new IOException("Cannot write plain since crypto buffer is not aligned.");
    152 		}
    153 		internal_write(b, off, len);
    154 	}
    155 }
    156