1 package org.jastacry.layer;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.OutputStream;
7 import java.security.InvalidAlgorithmParameterException;
8 import java.security.InvalidKeyException;
9 import java.security.NoSuchAlgorithmException;
10 import java.security.SecureRandom;
11
12 import javax.crypto.BadPaddingException;
13 import javax.crypto.Cipher;
14 import javax.crypto.IllegalBlockSizeException;
15 import javax.crypto.NoSuchPaddingException;
16 import javax.crypto.SecretKey;
17 import javax.crypto.SecretKeyFactory;
18 import javax.crypto.spec.IvParameterSpec;
19 import javax.crypto.spec.PBEKeySpec;
20 import javax.crypto.spec.SecretKeySpec;
21
22 import org.jastacry.JastacryException;
23
24
25
26
27
28
29
30
31 public abstract class AbstractCipherLayer extends AbstractBasicLayer
32 {
33
34
35
36
37 private static final int ONEBLOCKSIZE = 256;
38
39
40
41
42 protected static final int BITSPERBYTE = 8;
43
44
45
46
47 protected PBEKeySpec pbeKeySpec;
48
49
50
51
52 protected SecretKeyFactory keyFac;
53
54
55
56
57 protected SecretKey pbeKey;
58
59
60
61
62 protected SecretKeySpec pbeSecretKeySpec;
63
64
65
66
67 protected String strAlg;
68
69
70
71
72 protected String strKeyAlg;
73
74
75
76
77 protected char[] chPasswd;
78
79
80
81
82 protected int iterCount;
83
84
85
86
87 protected int currentKeysize;
88
89
90
91
92 protected int currentIvLen;
93
94
95
96
97 protected byte[] ivBytes;
98
99
100
101
102 protected int currentSaltLen;
103
104
105
106
107 protected byte[] salt;
108
109
110
111
112
113
114
115 public AbstractCipherLayer(final Class<?> cClass, final String layerName)
116 {
117 super(cClass, layerName);
118 }
119
120
121
122
123
124
125 protected abstract String getMyAlg();
126
127
128
129
130
131
132 protected abstract String getMyKeyAlg();
133
134
135
136
137
138
139 protected abstract int getMySaltLen();
140
141
142
143
144
145
146 protected abstract int getMyIvLen();
147
148
149
150
151
152
153 protected abstract int getMyCount();
154
155
156
157
158
159
160 protected abstract int getMyKeysize();
161
162
163
164
165 protected final void getSalt()
166 {
167 salt = new byte[currentSaltLen];
168 new SecureRandom().nextBytes(salt);
169 }
170
171
172
173
174 protected final void getIv()
175 {
176 ivBytes = new byte[currentIvLen];
177 }
178
179
180
181
182 protected final void init()
183 {
184 this.strAlg = getMyAlg();
185 this.strKeyAlg = getMyKeyAlg();
186 this.currentSaltLen = getMySaltLen();
187 this.currentIvLen = getMyIvLen();
188 this.iterCount = getMyCount();
189 this.currentKeysize = getMyKeysize();
190 }
191
192
193
194
195
196
197 protected abstract void setupPbe() throws JastacryException;
198
199
200
201
202
203
204
205 private void writeIv(final OutputStream outputStream, final Cipher pbeCipher) throws IOException
206 {
207 if (0 == currentIvLen)
208 {
209 logger.trace("No IV to write");
210 }
211 else
212 {
213 ivBytes = pbeCipher.getIV();
214
215 if (null == ivBytes)
216 {
217 logger.error("IV empty");
218 }
219 else
220 {
221 outputStream.write(ivBytes, 0, currentIvLen);
222 }
223 }
224 }
225
226
227
228
229
230
231 private void readIv(final InputStream inputStream) throws IOException
232 {
233 int iReadBytes;
234 if (0 == currentIvLen)
235 {
236 logger.trace("No IV to read");
237 }
238 else
239 {
240 ivBytes = new byte[currentIvLen];
241 iReadBytes = inputStream.read(ivBytes, 0, currentIvLen);
242 if (currentIvLen != iReadBytes)
243 {
244 logger.error("read {} bytes of IV, expecting {}.", iReadBytes, currentIvLen);
245 }
246 }
247 }
248
249
250
251
252
253
254 private void writeSalt(final OutputStream outputStream) throws IOException
255 {
256 outputStream.write(salt, 0, currentSaltLen);
257 }
258
259
260
261
262
263
264 private void readSalt(final InputStream inputStream) throws IOException
265 {
266 int iReadBytes;
267 salt = new byte[currentSaltLen];
268 iReadBytes = inputStream.read(salt, 0, currentSaltLen);
269 if (currentSaltLen != iReadBytes)
270 {
271 logger.error("read {} bytes of salt, expecting {}.", iReadBytes, currentSaltLen);
272 }
273 }
274
275
276
277
278
279
280
281
282 @Override
283 public final void encStream(final InputStream inputStream, final OutputStream outputStream) throws JastacryException
284 {
285 Cipher pbeCipher;
286 try
287 {
288 getSalt();
289 setupPbe();
290
291 pbeCipher = Cipher.getInstance(strAlg);
292 pbeCipher.init(Cipher.ENCRYPT_MODE, pbeSecretKeySpec);
293
294 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
295
296 int nRead;
297 final byte[] data = new byte[ONEBLOCKSIZE];
298
299 while ((nRead = inputStream.read(data, 0, data.length)) != -1)
300 {
301 buffer.write(data, 0, nRead);
302 }
303
304 buffer.flush();
305
306 final byte[] bInput = buffer.toByteArray();
307
308
309 final byte[] ciphertext = pbeCipher.doFinal(bInput);
310 writeIv(outputStream, pbeCipher);
311 writeSalt(outputStream);
312
313 outputStream.write(ciphertext);
314 outputStream.close();
315 }
316 catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException
317 | JastacryException | BadPaddingException | IOException e)
318 {
319 logger.catching(e);
320 throw (JastacryExceptionl#JastacryException">JastacryException) new JastacryException("encStream failed").initCause(e);
321 }
322
323 }
324
325
326
327
328
329
330
331
332 @Override
333 public final void decStream(final InputStream inputStream, final OutputStream outputStream) throws JastacryException
334 {
335
336 Cipher pbeCipher;
337 try
338 {
339 readIv(inputStream);
340 readSalt(inputStream);
341
342
343 setupPbe();
344
345 pbeCipher = Cipher.getInstance(strAlg);
346 if (0 == currentIvLen)
347 {
348 pbeCipher.init(Cipher.DECRYPT_MODE, pbeSecretKeySpec);
349 }
350 else
351 {
352 pbeCipher.init(Cipher.DECRYPT_MODE, pbeSecretKeySpec, new IvParameterSpec(ivBytes));
353 }
354
355 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
356
357 int nRead = 0;
358 final byte[] data = new byte[ONEBLOCKSIZE];
359
360 while ((nRead = inputStream.read(data, 0, data.length)) != -1)
361 {
362 buffer.write(data, 0, nRead);
363 }
364
365 buffer.flush();
366
367 final byte[] bInput = buffer.toByteArray();
368
369
370 final byte[] ciphertext = pbeCipher.doFinal(bInput);
371 outputStream.write(ciphertext);
372 outputStream.close();
373 }
374 catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException
375 | BadPaddingException | InvalidAlgorithmParameterException | JastacryException | IOException e)
376 {
377 logger.catching(e);
378 throw (JastacryExceptionl#JastacryException">JastacryException) new JastacryException("decStream failed").initCause(e);
379 }
380 }
381
382 @Override
383 public final void encodeAndDecode(final InputStream inputStream, final OutputStream outputStream) throws JastacryException
384 {
385 throw new UnsupportedOperationException();
386 }
387
388 }