0
|
1
|
|
2 package com.trilead.ssh2.crypto.cipher;
|
|
3
|
|
4 import java.io.IOException;
|
|
5 import java.io.OutputStream;
|
|
6
|
|
7 /**
|
|
8 * CipherOutputStream.
|
|
9 *
|
|
10 * @author Christian Plattner, plattner@trilead.com
|
|
11 * @version $Id: CipherOutputStream.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $
|
|
12 */
|
|
13 public class CipherOutputStream {
|
|
14 BlockCipher currentCipher;
|
|
15 OutputStream bo;
|
|
16 byte[] buffer;
|
|
17 byte[] enc;
|
|
18 int blockSize;
|
|
19 int pos;
|
|
20
|
|
21 /*
|
|
22 * We cannot use java.io.BufferedOutputStream, since that is not available
|
|
23 * in J2ME. Everything could be improved here alot.
|
|
24 */
|
|
25
|
|
26 final int BUFF_SIZE = 2048;
|
|
27 byte[] out_buffer = new byte[BUFF_SIZE];
|
|
28 int out_buffer_pos = 0;
|
|
29
|
|
30 public CipherOutputStream(BlockCipher tc, OutputStream bo) {
|
|
31 this.bo = bo;
|
|
32 changeCipher(tc);
|
|
33 }
|
|
34
|
|
35 private void internal_write(byte[] src, int off, int len) throws IOException {
|
|
36 while (len > 0) {
|
|
37 int space = BUFF_SIZE - out_buffer_pos;
|
|
38 int copy = (len > space) ? space : len;
|
|
39 System.arraycopy(src, off, out_buffer, out_buffer_pos, copy);
|
|
40 off += copy;
|
|
41 out_buffer_pos += copy;
|
|
42 len -= copy;
|
|
43
|
|
44 if (out_buffer_pos >= BUFF_SIZE) {
|
|
45 bo.write(out_buffer, 0, BUFF_SIZE);
|
|
46 out_buffer_pos = 0;
|
|
47 }
|
|
48 }
|
|
49 }
|
|
50
|
|
51 private void internal_write(int b) throws IOException {
|
|
52 out_buffer[out_buffer_pos++] = (byte) b;
|
|
53
|
|
54 if (out_buffer_pos >= BUFF_SIZE) {
|
|
55 bo.write(out_buffer, 0, BUFF_SIZE);
|
|
56 out_buffer_pos = 0;
|
|
57 }
|
|
58 }
|
|
59
|
|
60 public void flush() throws IOException {
|
|
61 if (pos != 0)
|
|
62 throw new IOException("FATAL: cannot flush since crypto buffer is not aligned.");
|
|
63
|
|
64 if (out_buffer_pos > 0) {
|
|
65 bo.write(out_buffer, 0, out_buffer_pos);
|
|
66 out_buffer_pos = 0;
|
|
67 }
|
|
68
|
|
69 bo.flush();
|
|
70 }
|
|
71
|
|
72 public void changeCipher(BlockCipher bc) {
|
|
73 this.currentCipher = bc;
|
|
74 blockSize = bc.getBlockSize();
|
|
75 buffer = new byte[blockSize];
|
|
76 enc = new byte[blockSize];
|
|
77 pos = 0;
|
|
78 }
|
|
79
|
|
80 private void writeBlock() throws IOException {
|
|
81 try {
|
|
82 currentCipher.transformBlock(buffer, 0, enc, 0);
|
|
83 }
|
|
84 catch (Exception e) {
|
|
85 throw(IOException) new IOException("Error while decrypting block.").initCause(e);
|
|
86 }
|
|
87
|
|
88 internal_write(enc, 0, blockSize);
|
|
89 pos = 0;
|
|
90 }
|
|
91
|
|
92 public void write(byte[] src, int off, int len) throws IOException {
|
|
93 while (len > 0) {
|
|
94 int avail = blockSize - pos;
|
|
95 int copy = Math.min(avail, len);
|
|
96 System.arraycopy(src, off, buffer, pos, copy);
|
|
97 pos += copy;
|
|
98 off += copy;
|
|
99 len -= copy;
|
|
100
|
|
101 if (pos >= blockSize)
|
|
102 writeBlock();
|
|
103 }
|
|
104 }
|
|
105
|
|
106 public void write(int b) throws IOException {
|
|
107 buffer[pos++] = (byte) b;
|
|
108
|
|
109 if (pos >= blockSize)
|
|
110 writeBlock();
|
|
111 }
|
|
112
|
|
113 public void writePlain(int b) throws IOException {
|
|
114 if (pos != 0)
|
|
115 throw new IOException("Cannot write plain since crypto buffer is not aligned.");
|
|
116
|
|
117 internal_write(b);
|
|
118 }
|
|
119
|
|
120 public void writePlain(byte[] b, int off, int len) throws IOException {
|
|
121 if (pos != 0)
|
|
122 throw new IOException("Cannot write plain since crypto buffer is not aligned.");
|
|
123
|
|
124 internal_write(b, off, len);
|
|
125 }
|
|
126 }
|