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