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