|
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 |
|