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