|
DESBaseCipherImpl |
|
1 /* $RCSfile: DESBaseCipherImpl.java,v $
2 * $Revision: 1.5 $
3 * $Date: 2002/11/23 11:09:57 $
4 * $Author: uwe_guenther $
5 * $State: Exp $
6 *
7 * Created on January 2, 2002 1:36 PM
8 *
9 * Copyright (C) 2001 Uwe Guenther <uwe@cscc.de>
10 *
11 * This file is part of the jhbci JCE-ServiceProvider. The jhbci JCE-
12 * ServiceProvider is a library, written in JavaTM, that should be
13 * used in HBCI banking applications (clients and may be servers),
14 * to do cryptographic operations.
15 *
16 * The jhbci library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
20 *
21 * The jhbci library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
25 *
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 */
31
32 package de.cscc.crypto.provider;
33
34 import java.security.AlgorithmParameters;
35 import java.security.InvalidAlgorithmParameterException;
36 import java.security.InvalidKeyException;
37 import java.security.InvalidParameterException;
38 import java.security.Key;
39 import java.security.NoSuchAlgorithmException;
40 import java.security.SecureRandom;
41 import java.security.spec.AlgorithmParameterSpec;
42
43 import javax.crypto.BadPaddingException;
44 import javax.crypto.Cipher;
45 import javax.crypto.IllegalBlockSizeException;
46 import javax.crypto.NoSuchPaddingException;
47 import javax.crypto.SecretKey;
48 import javax.crypto.ShortBufferException;
49
50 import de.cscc.crypto.provider.spec.DESOperationModeInitializationVectorSpec;
51
52 /**
53 * DESBaseCipherImpl Class.
54 *
55 * @author <a href=mailto:uwe@cscc.de>Uwe Günther</a>
56 * @version $Revision: 1.5 $
57 */
58 class DESBaseCipherImpl {
59
60 /**
61 * Internal opmode field. Takes values as
62 * Cipher.ENCRYPT_MODE, Cipher.DECRYPT_MODE,
63 * Cipher.WRAP_MODE, Cipher.UNWRAP_MODE.
64 */
65 int opmode;
66
67 /**
68 * Holds a reference to a concret
69 * subclass of DESCoreBlockCipher. This is the
70 * algorithm object that does the cipher work.
71 *
72 */
73 DESCoreBlockCipher cipher;
74
75 /**
76 * Holds a reference to a concret
77 * subclass of OperationMode. This is the
78 * algorithm object that does the operation
79 * mode work.
80 */
81 OperationMode mode;
82
83 /**
84 * Holds a reference to a concret
85 * subclass of Padding. This is the
86 * algorithm object that does the padding work.
87 */
88 Padding padding;
89
90 /**
91 * Contains the used cipher algorithm name,
92 * such as "DES1Key", "DESede2Key", "DESede3Key".
93 */
94 String cipherAlgorithm;
95
96 /**
97 * Contains the used operation mode algorithm name,
98 * such as CBC or ECB.
99 */
100 String modeAlgorithm = new String("CBC");
101
102 /**
103 * Contains the used padding algorithm name,
104 * such as ISO10126OctetPadding or NoPadding.
105 */
106 String paddingAlgorithm = new String("ISO10126OctetPadding");
107
108 /**
109 * Don't create an instance from these class. Should only be invoke from a
110 * subclass in the same package.
111 */
112 DESBaseCipherImpl() {}
113
114 /**
115 * Returns a string representation of the object.
116 * @return a string representation of the object.
117 */
118 public String toString() {
119
120 String returnValue ="";
121
122 returnValue += "opmode: [" + this.opmode + "]";
123 returnValue += "cipher: [" + this.cipher + "]";
124 returnValue += "mode: [" + this.mode + "]";
125 returnValue += "padding: [" + this.padding + "]";
126 returnValue += "cipherAlgorithm: [" + this.cipherAlgorithm + "]";
127 returnValue += "modeAlgorithm: [" + this.modeAlgorithm + "]";
128 returnValue += "paddingAlgorithm: [" + this.paddingAlgorithm + "]";
129
130 return returnValue;
131 }
132
133 /**
134 * Sets the mode of this cipher.
135 * @param mode the cipher mode.
136 * @throws NoSuchAlgorithmException if the requested cipher mode does not exist.
137 */
138 void setMode(String mode) throws NoSuchAlgorithmException {
139 if (mode.equalsIgnoreCase("ECB")) {
140 this.modeAlgorithm = "ECB";
141
142 } else if (mode.equalsIgnoreCase("CBC")) {
143 this.modeAlgorithm = "CBC";
144
145 } else {
146 throw new NoSuchAlgorithmException ("Operation mode " + mode
147 + " not supported.");
148 }
149 }
150
151 /**
152 * Sets the padding mechanism of this cipher.
153 * @param padding the padding mechanism.
154 * @throws NoSuchPaddingException if the requested padding mechanism does not exist.
155 */
156 void setPadding(String padding) throws NoSuchPaddingException {
157 if (padding.equalsIgnoreCase("NoPadding")) {
158 this.paddingAlgorithm = "NoPadding";
159
160 } else if (padding.equalsIgnoreCase("ISO10126OctetPadding")) {
161 this.paddingAlgorithm = "ISO10126OctetPadding";
162
163 } else {
164 throw new NoSuchPaddingException("Padding mechanism " + padding
165 + " not supported.");
166 }
167 }
168
169 /**
170 * Check if given opmode is valid, if not
171 * it throws a InvalidParamterException.
172 * @param opmode the given opmode to check.
173 * @throws InvalidParameterException if the given opmode isn't valid.
174 */
175 private void checkOpmode(int opmode) throws InvalidParameterException {
176 if (opmode != Cipher.ENCRYPT_MODE
177 && opmode != Cipher.DECRYPT_MODE
178 && opmode != Cipher.WRAP_MODE
179 && opmode != Cipher.UNWRAP_MODE) {
180
181 throw new InvalidParameterException("Wrong opmode: ENCRYPT_MODE, "
182 + "DECRYPT_MODE, WRAP_MODE or UNWRAP_MODE expected.");
183 }
184
185 return;
186 }
187
188 /**
189 * Check if given key is valid, if not
190 * it throws a InvalidParamterException.
191 * @param key the given key to check.
192 * @throws InvalidKeyException if the given key isn't valid.
193 */
194 private void checkKey(Key key) throws InvalidKeyException {
195 if (key == null){
196 throw new InvalidKeyException("No key given.");
197 }
198 if ((key instanceof SecretKey) == false){
199 throw new InvalidKeyException(
200 "Wrong Key: SecretKey expected.");
201 }
202 if (key.getAlgorithm().equalsIgnoreCase(this.cipherAlgorithm) == false){
203 throw new InvalidKeyException(
204 "Wrong Algorithm: " + this.cipherAlgorithm + " required.");
205 }
206 if (key.getFormat().equalsIgnoreCase("RAW") == false){
207 throw new InvalidKeyException("Wrong Format: RAW required.");
208 }
209 if (key.getEncoded().length != this.cipher.getKeyByteSize()){
210 throw new InvalidKeyException(
211 "Wrong Length: " +
212 this.cipher.getKeyByteSize() +
213 " expected.");
214 }
215
216 return;
217 }
218
219 /**
220 * Generates a new valid Iv from a given random source.
221 * @param random the random source.
222 * @return a valid Iv (byte[8]).
223 */
224 private byte[] generateIv(SecureRandom random) {
225 if (random == null){
226 random = new SecureRandom();
227 }
228
229 byte[] returnValue = new byte[8];
230 random.nextBytes(returnValue);
231 return returnValue;
232 }
233
234 /** Initializes this cipher with a key and a source of randomness.
235 * @param opmode the operation mode of this cipher.
236 * This is one of the following:
237 * javax.crypto.Cipher.ENCRYPT_MODE
238 * javax.crypto.Cipher.DECRYPT_MODE
239 * javax.crypto.Cipher.WRAP_MODE
240 * javax.crypto.Cipher.UNWRAP_MODE
241 * @param key the key to encrypt or to decrypt.
242 * @param random the source of randomness.
243 * @throws InvalidKeyException if the given key is inappropriate for
244 * initializing this cipher, or if this cipher is being initialized
245 * for decryption and requires algorithm parameters that cannot be
246 * determinated from the given key.
247 */
248 void init(int opmode, Key key, SecureRandom random)
249 throws InvalidKeyException {
250 //opmode
251 checkOpmode(opmode);
252 this.opmode = opmode;
253
254 //key
255 checkKey(key);
256 try{
257 if (this.cipherAlgorithm.equals("DES1Key")) {
258 this.cipher =new DESCore1KeyBlockCipher(key.getEncoded());
259
260 } else if (this.cipherAlgorithm.equals("DESede2Key")) {
261 this.cipher =new DESCoreEde2KeyBlockCipher(key.getEncoded());
262
263 } else if (this.cipherAlgorithm.equals("DESede3Key")) {
264 this.cipher =new DESCoreEde3KeyBlockCipher(key.getEncoded());
265 }
266
267 } catch (IllegalBlockSizeException cannothappen){
268 throw new Error("Can not happen.", cannothappen);
269 }
270
271 //OperationMode
272 if (this.modeAlgorithm.equals("ECB")) {
273 this.mode = new OperationModeECB(this.cipher);
274
275 } else if (this.modeAlgorithm.equals("CBC")) {
276 if (this.opmode == Cipher.ENCRYPT_MODE
277 || this.opmode == Cipher.WRAP_MODE) {
278 this.mode = new OperationModeCBC(this.cipher);
279 try{
280 this.mode.setIv(generateIv(random));
281 } catch (IllegalBlockSizeException cannothappen) {
282 throw new Error("Can not happen.", cannothappen);
283 }
284
285 } else if (this.opmode == Cipher.DECRYPT_MODE
286 || this.opmode == Cipher.UNWRAP_MODE) {
287
288 throw new InvalidKeyException("Need Iv for CBC DECRYPTION_MODE "
289 + "or UNWRAP_MODE.");
290 }
291 }
292
293 //padding
294 if (this.paddingAlgorithm.equals("ISO10126OctetPadding")) {
295 this.padding = new PaddingISO10126OctetPadding(this.mode);
296
297
298 } else if (this.paddingAlgorithm.equals("NoPadding")){
299 this.padding = new PaddingNoPadding(this.mode);
300
301 }
302
303 }
304
305 /**
306 * Initializes this cipher with a key, a set of algorithm parameters,
307 * and a source of randomness.
308 * @param opmode the operation mode of this cipher.
309 * This is one of the following:
310 * javax.crypto.Cipher.ENCRYPT_MODE
311 * javax.crypto.Cipher.DECRYPT_MODE
312 * javax.crypto.Cipher.WRAP_MODE
313 * javax.crypto.Cipher.UNWRAP_MODE
314 * @param key the key to encrypt or to decrypt.
315 * @param params the algorithm paramter.
316 * @param random the source of randomness.
317 * @throws InvalidKeyException if the given key is inappropriate for initializing
318 * this cipher.
319 * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate
320 * for this cipher, or if this cipher is being
321 * initialized for decryption and requires algorithm
322 * parameters and params is null.
323 */
324 void init(int opmode, Key key,
325 AlgorithmParameters params, SecureRandom random)
326 throws InvalidKeyException, InvalidAlgorithmParameterException {
327
328 throw new InvalidAlgorithmParameterException("Don't support "
329 + "AlogrithmParameters, use AlgorithmParamterSpec.");
330 }
331
332 /**
333 * Initializes this cipher with a key, a set of algorithm parameters,
334 * and a source of randomness.
335 * @param opmode the operation mode of this cipher.
336 * This is one of the following:
337 * javax.crypto.Cipher.ENCRYPT_MODE
338 * javax.crypto.Cipher.DECRYPT_MODE
339 * javax.crypto.Cipher.WRAP_MODE
340 * javax.crypto.Cipher.UNWRAP_MODE
341 * @param key the key to encrypt or to decrypt.
342 * @param params the algorithm paramter.
343 * @param random the source of randomness.
344 * @throws InvalidKeyException if the given key is inappropriate for initializing
345 * this cipher.
346 * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate
347 * for this cipher, or if this cipher is being
348 * initialized for decryption and requires algorithm
349 * parameters and params is null.
350 */
351 void init(int opmode, Key key,
352 AlgorithmParameterSpec params, SecureRandom random)
353 throws InvalidKeyException, InvalidAlgorithmParameterException {
354
355 //opmode
356 checkOpmode(opmode);
357 this.opmode = opmode;
358
359 //key
360 checkKey(key);
361 try{
362 if (this.cipherAlgorithm.equals("DES1Key")) {
363 this.cipher =new DESCore1KeyBlockCipher(key.getEncoded());
364
365 } else if (this.cipherAlgorithm.equals("DESede2Key")) {
366 this.cipher =new DESCoreEde2KeyBlockCipher(key.getEncoded());
367
368 } else if (this.cipherAlgorithm.equals("DESede3Key")) {
369 this.cipher =new DESCoreEde3KeyBlockCipher(key.getEncoded());
370 }
371
372 } catch (IllegalBlockSizeException cannothappen) {
373 throw new Error("Can not happen.", cannothappen);
374 }
375
376 //OperationMode
377 if (this.modeAlgorithm.equals("ECB")) {
378 this.mode = new OperationModeECB(this.cipher);
379
380 } else if (this.modeAlgorithm.equals("CBC")) {
381 if (params == null) {
382 if (this.opmode == Cipher.ENCRYPT_MODE ||
383 this.opmode == Cipher.WRAP_MODE) {
384
385 this.mode = new OperationModeCBC(this.cipher);
386
387 try{
388 this.mode.setIv(generateIv(random));
389 } catch (IllegalBlockSizeException cannothappen) {
390 throw new Error("Can not happen.", cannothappen);
391 }
392
393 } else if (this.opmode == Cipher.DECRYPT_MODE ||
394 this.opmode == Cipher.UNWRAP_MODE) {
395
396 throw new InvalidAlgorithmParameterException("No algorithm "
397 + "paramter spec given.");
398 }
399
400 } else if (params instanceof DESOperationModeInitializationVectorSpec){
401
402 this.mode = new OperationModeCBC(this.cipher);
403
404 try{
405 this.mode.setIv(
406 ((DESOperationModeInitializationVectorSpec) params).getIv());
407 } catch (IllegalBlockSizeException cannothappen) {
408 throw new Error("Can not happen.", cannothappen);
409 }
410
411 } else {
412
413 throw new InvalidAlgorithmParameterException("Wrong Type: "
414 + "de.cscc.crypto.spec.DESOperationModeInitialization"
415 + "VectorSpec expected.");
416 }
417 }
418
419 //Padding
420 if (this.paddingAlgorithm.equals("ISO10126OctetPadding")) {
421 this.padding = new PaddingISO10126OctetPadding(this.mode);
422
423 } else if (this.paddingAlgorithm.equals("NoPadding")) {
424 this.padding = new PaddingNoPadding(this.mode);
425
426 }
427 }
428
429 /**
430 * Continues a multiple-part encryption or decryption operation
431 * (depending on how this cipher was initialized), processing another data
432 * part.
433 * @param input the input buffer.
434 * @param inputOffset the offset in input where the input starts.
435 * @param inputLen the input length.
436 * @return the new buffer with the result, or null if the
437 * underlying cipher is a block cipher and the input
438 * data is too short to result in a new block.
439 */
440 byte[] update(byte[] input, int inputOffset, int inputLen) {
441 if (this.opmode == Cipher.ENCRYPT_MODE) {
442 return this.padding.updateEncryption(input, inputOffset, inputLen);
443 }
444 if (this.opmode == Cipher.DECRYPT_MODE) {
445 return this.padding.updateDecryption(input, inputOffset, inputLen);
446 }
447
448 //If the cipher initialized for WRAP_MODE or UNWRAP_MODE do nothing.
449 return new byte[0];
450 }
451
452 /**
453 * Continues a multiple-part encryption or decryption operation
454 * (depending on how this cipher was initialized), processing another data
455 * part.
456 * @param input the input buffer.
457 * @param inputOffset the offset in input where the input starts.
458 * @param inputLen the input length.
459 * @param output the buffer for the result.
460 * @param outputOffset the offset in output where the result is stored.
461 * @throws ShortBufferException if the given output buffer is too small to
462 * hold the result.
463 * @return the number of bytes stored in output
464 */
465 int update(byte[] input, int inputOffset, int inputLen,
466 byte[] output, int outputOffset) throws ShortBufferException {
467 if (this.opmode == Cipher.ENCRYPT_MODE) {
468 return this.padding.updateEncryption(input, inputOffset, inputLen,
469 output, outputOffset);
470 }
471 if (this.opmode == Cipher.DECRYPT_MODE) {
472 return this.padding.updateDecryption(input, inputOffset, inputLen,
473 output, outputOffset);
474 }
475
476 //If the cipher initialized for WRAP_MODE or UNWRAP_MODE do nothing.
477 return 0;
478 }
479
480
481 /** Encrypts or decrypts data in a single-part operation, or finishes a
482 * multiple-part operation.
483 * @param input the input buffer.
484 * @param inputOffset the offset in input where the input starts.
485 * @param inputLen the input length.
486 * @throws IllegalBlockSizeException if this cipher is a block cipher, no padding
487 * has been requested (only in encryption mode),
488 * and the total input length of the data processed
489 * by this cipher is not a multiple of block size.
490 * @throws BadPaddingException if this cipher is in decryption mode,
491 * and (un)padding has been requested,
492 * but the decrypted data is not bounded
493 * by the appropriate padding bytes.
494 * @return the new buffer with the finally result.
495 */
496 byte[] doFinal(byte[] input, int inputOffset, int inputLen)
497 throws IllegalBlockSizeException, BadPaddingException {
498 if (this.opmode == Cipher.ENCRYPT_MODE) {
499 return this.padding.doFinalEncryption(input, inputOffset, inputLen);
500 }
501 if (this.opmode == Cipher.DECRYPT_MODE) {
502 return this.padding.doFinalDecryption(input, inputOffset, inputLen);
503 }
504
505 //If the cipher initialized for WRAP_MODE or UNWRAP_MODE do nothing.
506 return new byte[0];
507 }
508
509
510 /**
511 * Encrypts or decrypts data in a single-part operation, or finishes a
512 * multiple-part operation.
513 * @param input the input buffer.
514 * @param inputOffset the offset in input where the input starts.
515 * @param inputLen the input length.
516 * @param output the buffer for the finally result.
517 * @param outputOffset the offset in output where the result is stored.
518 * @throws ShortBufferException if the given output buffer is too small to
519 * hold the result.
520 * @throws IllegalBlockSizeException if this cipher is a block cipher, no padding
521 * has been requested (only in encryption mode),
522 * and the total input length of the data processed
523 * by this cipher is not a multiple of block size.
524 * @throws BadPaddingException if this cipher is in decryption mode,
525 * and (un)padding has been requested,
526 * but the decrypted data is not bounded
527 * by the appropriate padding bytes.
528 * @return the number of bytes stored in output.
529 */
530 int doFinal(byte[] input, int inputOffset, int inputLen,
531 byte[] output, int outputOffset)
532 throws ShortBufferException, IllegalBlockSizeException,
533 BadPaddingException {
534 if (this.opmode == Cipher.ENCRYPT_MODE) {
535 return this.padding.doFinalEncryption(input, inputOffset, inputLen,
536 output, outputOffset);
537 }
538 if (this.opmode == Cipher.DECRYPT_MODE) {
539 return this.padding.doFinalDecryption(input, inputOffset, inputLen,
540 output, outputOffset);
541 }
542
543 //If the cipher initialized for WRAP_MODE or UNWRAP_MODE do nothing.
544 return 0;
545 }
546
547 /**
548 * Returns the length in bytes that an output buffer would need to be in
549 * order to hold the result of the next update() or doFinal() operation, given
550 * the input length inputLen (in bytes).
551 * @param inputLen the input length in bytes.
552 * @return the reqired output buffer size in bytes.
553 */
554 int getOutputSize(int inputLen) {
555 if (this.opmode == Cipher.ENCRYPT_MODE) {
556 return this.padding.getDoFinalEncryptionOutputSize(inputLen);
557 }
558 if (this.opmode == Cipher.DECRYPT_MODE) {
559 return this.padding.getDoFinalDecryptionOutputSize(inputLen);
560 }
561 if (this.opmode == Cipher.WRAP_MODE) {
562 return 0;
563 }
564 if (this.opmode == Cipher.UNWRAP_MODE) {
565 return 0;
566 }
567
568 //This case will never be true, because the JCE catches this case.
569 return 0;
570 }
571
572 /**
573 * Returns the parameters used with this cipher.
574 * @return the parameters used with this cipher,
575 * or null if this cipher does not use
576 * any parameters.
577 */
578 AlgorithmParameters getParameters() {
579 return null;
580 }
581
582 /**
583 * Returns the initialization vector (IV) in a new buffer.
584 * @return the initialization vector in a new buffer,
585 * or null if the underlying algorithm does not
586 * use an IV, or if the IV has not yet been set.
587 */
588 byte[] getIV() {
589 return this.mode.getIv();
590 }
591
592 /**
593 * Returns the block size (in bytes).
594 * @return the block size (in bytes), or 0 if the
595 * underlying algorithm is not a block cipher
596 */
597 int getBlockSize() {
598 return this.cipher.getBlockSize();
599 }
600
601
602 /**
603 * Returns the key size of the given key object.
604 * @param key the key object.
605 * @throws InvalidKeyException if key is invalid.
606 * @return the key size of the given key object.
607 */
608 int getKeySize(Key key) throws InvalidKeyException {
609 checkKey(key);
610
611 return this.cipher.getKeyBitSize();
612 }
613
614 /**
615 * Unwrap a previously wrapped key.
616 * @param wrappedKey the wrapped key to unwrap.
617 * @param wrappedKeyAlgorithm the algorithm associated with the key wrapped key.
618 * @param wrappedKeyType the type of the wrapped key. This is one of
619 * javax.crypto.Cipher.SECRET_KEY,
620 * javax.crypto.Cipher.PRIVATE_KEY,
621 * javax.crypto.Cipher.PUBLIC_KEY.
622 * @throws InvalidKeyException if wrappedKey does not represent a wrapped key,
623 * or if the algorithm associated with the wrapped
624 * key is different from wrappedKeyAlgorithm and/or
625 * its key type is different from wrappedKeyType.
626 * @throws NoSuchAlgorithmException if no installed providers can create
627 * keys for the wrappedKeyAlgorithm.
628 * @return the unwrapped key.
629 */
630 Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
631 int wrappedKeyType)
632 throws InvalidKeyException, NoSuchAlgorithmException {
633 throw new UnsupportedOperationException("Don't support key unwrapping.");
634 }
635
636 /**
637 * Wrap a key.
638 * @param key the key to be wrapped.
639 * @throws IllegalBlockSizeException if this cipher is a block cipher,
640 * no padding has been requested, and the
641 * length of the encoding of the key to be
642 * wrapped is not a multiple of the block size.
643 * @throws InvalidKeyException if it is impossible or unsafe to wrap the
644 * key with this cipher (e.g., a hardware
645 * public key is being passed to a
646 * software-only cipher).
647 * @return the wrapped key.
648 */
649 byte[] wrap(Key key)
650 throws IllegalBlockSizeException, InvalidKeyException {
651 throw new UnsupportedOperationException("Don't support key wrapping.");
652 }
653 }
654
|
DESBaseCipherImpl |
|