1 package org.apache.fulcrum.jce.crypto;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.ByteArrayInputStream;
23 import java.io.ByteArrayOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.security.GeneralSecurityException;
28
29
30
31
32
33
34
35
36
37 public class SmartDecryptingInputStream extends ByteArrayInputStream
38 {
39
40 private static final String[] ENCODINGS = { "ISO-8859-1", "UTF-8", "UTF-16" };
41
42
43
44
45
46
47
48
49
50 public SmartDecryptingInputStream(
51 CryptoStreamFactory cryptoStreamFactory,
52 InputStream is )
53 throws IOException, GeneralSecurityException
54 {
55 this( cryptoStreamFactory, is, null );
56 }
57
58
59
60
61
62
63
64
65
66
67
68 public SmartDecryptingInputStream(
69 CryptoStreamFactory cryptoStreamFactory,
70 InputStream is,
71 char[] password )
72 throws IOException, GeneralSecurityException
73 {
74 super( new byte[0] );
75
76 byte[] content = null;
77 byte[] plain = null;
78
79
80
81 ByteArrayOutputStream baosCipher = new ByteArrayOutputStream();
82 ByteArrayOutputStream baosPlain = new ByteArrayOutputStream();
83 this.copy( is, baosCipher );
84
85 content = baosCipher.toByteArray();
86 plain = content;
87
88 if( this.isEncrypted(content) == true )
89 {
90 InputStream cis = null;
91 ByteArrayInputStream bais = new ByteArrayInputStream(content);
92
93 if( ( password != null ) && ( password.length > 0 ) )
94 {
95 cis = cryptoStreamFactory.getInputStream( bais, password );
96 }
97 else
98 {
99 cis = cryptoStreamFactory.getInputStream( bais );
100 }
101
102 copy( cis, baosPlain );
103 plain = baosPlain.toByteArray();
104 }
105
106
107
108 if( plain != null )
109 {
110 this.buf = plain;
111 this.pos = 0;
112 this.count = buf.length;
113 }
114 }
115
116
117
118
119
120
121
122
123
124
125
126 private boolean isEncrypted( byte[] content )
127 throws IOException
128 {
129 if( content.length == 0 )
130 {
131 return false;
132 }
133 else if( ( content.length % 8 ) != 0 )
134 {
135
136
137
138 return false;
139 }
140 else if( this.isPDF(content) )
141 {
142 return false;
143 }
144 else if( this.isXML(content) )
145 {
146 return false;
147 }
148 else if( this.isZip(content) )
149 {
150 return false;
151 }
152 else if( this.isUtf16Text(content) )
153 {
154 return false;
155 }
156 else
157 {
158 for( int i=0; i<content.length; i++ )
159 {
160
161
162 char ch = (char) content[i];
163
164 if( this.isAsciiControl(ch) )
165 {
166 return true;
167 }
168 }
169
170 return false;
171 }
172 }
173
174
175
176
177
178
179
180
181
182 public long copy( InputStream is, OutputStream os )
183 throws IOException
184 {
185 byte[] buf = new byte[1024];
186 int n = 0;
187 long total = 0;
188
189 while ((n = is.read(buf)) > 0)
190 {
191 os.write(buf, 0, n);
192 total += n;
193 }
194
195 is.close();
196 os.flush();
197 os.close();
198
199 return total;
200 }
201
202
203
204
205
206
207
208 private int count( byte[] content, byte value )
209 {
210 int result = 0;
211
212 for( int i=0; i<content.length; i++ )
213 {
214 if( content[i] == value )
215 {
216 result++;
217 }
218 }
219
220 return result;
221 }
222
223
224
225
226
227
228 private boolean hasByteOrderMark( byte[] content )
229 {
230
231
232 int firstUnsigned = content[0] & 0xFF;
233 int second = content[1] & 0xFF;
234 if( ((firstUnsigned == 0xFF) && (second == 0xFE)) ||
235 ((firstUnsigned == 0xFE) && (second == 0xFF)))
236 {
237 return true;
238 }
239 else
240 {
241 return false;
242 }
243 }
244
245
246
247
248
249
250
251
252 private boolean isUtf16Text( byte[] content ) throws IOException
253 {
254 if( content.length < 2 )
255 {
256 return false;
257 }
258
259 if( this.hasByteOrderMark( content ) )
260 {
261
262
263 int estimate = (content.length-2)/3;
264
265 if( this.count(content,(byte)0) > estimate )
266 {
267 return true;
268 }
269 }
270
271 return false;
272 }
273
274
275
276
277
278
279
280
281
282 private boolean isXML( byte[] content ) throws IOException
283 {
284 if( content.length < 3 )
285 {
286 return false;
287 }
288
289 for( int i=0; i<ENCODINGS.length; i++ )
290 {
291 String currEncoding = ENCODINGS[i];
292
293 String temp = new String( content, currEncoding );
294
295 if( ( temp.indexOf("<?xml") >= 0 ) && ( temp.indexOf("?>") > 0 ) )
296 {
297 return true;
298 }
299 }
300
301 return false;
302 }
303
304
305
306
307
308
309
310
311 private boolean isZip( byte[] content )
312 {
313 if( content.length < 64 )
314 {
315 return false;
316 }
317 else
318 {
319
320
321 if( ( content[0] == (byte) 0x50 ) &&
322 ( content[1] == (byte) 0x4B ) &&
323 ( content[2] == (byte) 0x03 ) &&
324 ( content[3] == (byte) 0x04 ) )
325 {
326 return true;
327 }
328 else
329 {
330 return false;
331 }
332 }
333 }
334
335
336
337
338
339
340
341
342 private boolean isPDF(byte[] content) throws IOException
343 {
344 if( content.length < 64 )
345 {
346 return false;
347 }
348 else
349 {
350
351
352 if( ( content[0] == (byte) 0x25 ) &&
353 ( content[1] == (byte) 0x50 ) &&
354 ( content[2] == (byte) 0x44 ) &&
355 ( content[3] == (byte) 0x46 ) &&
356 ( content[4] == (byte) 0x2D ) &&
357 ( content[5] == (byte) 0x31 ) &&
358 ( content[6] == (byte) 0x2E ) )
359 {
360 return true;
361 }
362 else
363 {
364 return false;
365 }
366 }
367 }
368
369
370
371
372
373
374 private boolean isAsciiControl(char ch)
375 {
376 if( ( ch >= 0x0000 ) && ( ch <= 0x001F) )
377 {
378 return true;
379 }
380 else
381 {
382 return true;
383 }
384 }
385 }