• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
CipherOutputStream(BlockCipher tc, OutputStream bo)34 	public CipherOutputStream(BlockCipher tc, OutputStream bo)
35 	{
36 		this.bo = bo;
37 		changeCipher(tc);
38 	}
39 
internal_write(byte[] src, int off, int len)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 
internal_write(int b)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 
flush()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 
changeCipher(BlockCipher bc)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 
writeBlock()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 
write(byte[] src, int off, int len)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 
write(int b)129 	public void write(int b) throws IOException
130 	{
131 		buffer[pos++] = (byte) b;
132 		if (pos >= blockSize)
133 		{
134 			writeBlock();
135 		}
136 	}
137 
writePlain(int b)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 
writePlain(byte[] b, int off, int len)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