|
PaddingISO10126OctetPadding |
|
1 /* $RCSfile: PaddingISO10126OctetPadding.java,v $ 2 * $Revision: 1.11 $ 3 * $Date: 2002/11/23 11:09:56 $ 4 * $Author: uwe_guenther $ 5 * $State: Exp $ 6 * 7 * Created on August 19, 2001 4:29 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 javax.crypto.BadPaddingException; 35 import javax.crypto.IllegalBlockSizeException; 36 import javax.crypto.ShortBufferException; 37 38 /** 39 * PaddingISO10126OctetPadding Class. 40 * 41 * @author <a href=mailto:uwe@cscc.de>Uwe Günther</a> 42 * @version $Revision: 1.11 $ 43 */ 44 class PaddingISO10126OctetPadding extends Padding { 45 46 /** 47 * The operation mode object (such as ECB, or CBC), that 48 * will be wrapped from this padding object. 49 */ 50 private OperationMode mode; 51 52 /** 53 * A single buffer to store unprocessed plaintext, 54 * while processing a block cipher. 55 */ 56 private PaddingSingleBuffer unprocessedPlainTextBuffer; 57 58 /** 59 * A double buffer to store unprocessed ciphertext, 60 * while processing a block cipher. 61 */ 62 private PaddingDoubleBuffer unprocessedCipherTextBuffer; 63 64 /** 65 * Temporary buffer that will be used from al en- and decrypt methods 66 * to prvent exceive byt[] allocation in these methods. 67 */ 68 private byte[] tempBuffer; 69 70 /** 71 * Don't create an PaddingISO10126OctetPadding Object 72 * with the default constructor. 73 */ 74 private PaddingISO10126OctetPadding() {} 75 76 /** 77 * Constructs a new padding Object, that wraps a operation mode 78 * object. 79 * 80 * @param mode the operation mode algorithm object that we wrap. 81 */ 82 public PaddingISO10126OctetPadding(OperationMode mode) { 83 this.mode = mode; 84 this.unprocessedPlainTextBuffer = 85 new PaddingSingleBuffer(getBlockSize()); 86 this.unprocessedCipherTextBuffer = 87 new PaddingDoubleBuffer(getBlockSize()); 88 89 this.tempBuffer = new byte[getBlockSize()]; 90 } 91 92 /** 93 * Returns a string representation of the object. 94 * 95 * @return a string representation of the object. 96 */ 97 public String toString() { 98 99 String returnValue = ""; 100 101 returnValue += "[mode: " + this.mode + "] "; 102 returnValue += "[unprocessedPlainTextBuffer: " 103 + this.unprocessedPlainTextBuffer + "] "; 104 returnValue += "[unprocessedCipherTextBuffer: " 105 + this.unprocessedCipherTextBuffer + "] "; 106 return returnValue; 107 } 108 109 /** 110 * Get the block size of the underlying mode object. 111 * 112 * @return the block size of the underlying mode object. 113 */ 114 public int getBlockSize() { 115 return mode.getBlockSize(); 116 } 117 118 /** 119 * Calculates the output size for to returned byted array, or 120 * the size for the output array that will 121 * be passed through updateEncryption(.....). 122 * 123 * @param inputLength the input length, that will be base for the 124 * calculation. 125 * @return the size for to returned byte array, or 126 * the size for the output array that will 127 * be passed through updateEncryption(.....). 128 */ 129 public int getUpdateEncryptionOutputSize(int inputLength) { 130 //Skip the rest if we divide with getBlockSize() 131 return ( 132 ( 133 this.unprocessedPlainTextBuffer.hasBytes() + inputLength 134 ) / getBlockSize() 135 ) * getBlockSize(); 136 } 137 138 /** 139 * Continues a multipart encryption operation, processing 140 * another data part. 141 * 142 * @param input plainText that should be encrypted. 143 * @param inputOffset the offset in input where the input starts. 144 * @param inputLength the input length. 145 * @throws IllegalArgumentException if <tt>input == null</tt>, 146 * <tt>inputOffset < 0</tt>, <tt>inputLength < 0</tt> or 147 * <tt>input.length < inputOffset+inputLength</tt>. 148 * @return the encrypted data, if there enough (at least one block size), 149 * or byte[8] otherwise. We aren't allowed to return null, like javadoc 150 * for CipherSpi this says, because the JCE 151 * (byte[] Cipher#update(byte[], int, int)) will throw a 152 * NullPointerException. 153 */ 154 public byte[] updateEncryption(byte[] input, int inputOffset, 155 int inputLength) { 156 //The next three if's are hte same as the JCE does check, 157 //but these checks are not documented, so we do check again. 158 if (input == null) { 159 throw new IllegalArgumentException("Bad Arguments."); 160 } 161 162 if (inputOffset < 0 || 163 inputLength < 0 || 164 input.length < (inputOffset+inputLength) ){ 165 166 throw new IllegalArgumentException("Bad Arguments."); 167 } 168 169 ////if (inputLength == 0){ 170 //// return null; 171 ////} 172 173 174 byte[] output = null; 175 int outputOffset = 0; 176 177 //Will be there some result, get space for the result output byte array. 178 ////if(getUpdateEncryptionOutputSize(inputLength) > 0){ 179 output = new byte[getUpdateEncryptionOutputSize(inputLength)]; 180 ////} 181 182 //Process the whole input. 183 for (int i = inputOffset; i < inputOffset+inputLength; i++) { 184 185 //Add every single byte to our unprocessedPlainTextBuffer. 186 this.unprocessedPlainTextBuffer.add(input[i]); 187 188 //If our unprocessedPlainTextBuffer is full process it and put 189 //the result into output. 190 if (this.unprocessedPlainTextBuffer.isFull()) { 191 192 //Process the unprocessedPlainTextBuffer and switch the 193 //outputOffset one block further. 194 try { 195 this.unprocessedPlainTextBuffer.fetch(this.tempBuffer, 0); 196 outputOffset += 197 this.mode.encrypt(this.tempBuffer, 0, output, outputOffset); 198 } catch (IllegalBlockSizeException cannothappen) { 199 throw new Error("Can not happen.", cannothappen); 200 } catch (ShortBufferException cannothappen){ 201 throw new Error("Can not happen.", cannothappen); 202 } 203 } 204 } 205 206 //Return the result as byte array, or byte[0] if there no result. 207 return output; 208 } 209 210 /** 211 * Continues a multipart encryption operation, processing 212 * another data part. 213 * 214 * @param input plainText that should be encrypted. 215 * @param inputOffset the offset in input where the input starts. 216 * @param inputLength the input length. 217 * @param output the buffer for the encrypted result. 218 * @param outputOffset the offset in output where the result is stored. 219 * @throws ShortBufferException if the usable range in the output buffer is 220 * to less. This means that the usable range must at least 221 * getUpdateEncryptionOutputSize(inputLength) bytes large. 222 * @throws IllegalArgumentException if <tt>input == null</tt>, 223 * <tt>inputOffset < 0</tt>, <tt>inputLength < 0</tt>, 224 * <tt>outputOffset < 0</tt> or <tt>input.length < 225 * inputOffset+inputLength</tt>. 226 * @return the number of bytes stored in output. 227 */ 228 public int updateEncryption(byte[] input, int inputOffset, int inputLength, 229 byte[] output, int outputOffset) throws ShortBufferException { 230 //The next three if's are the same as the JCE does check, 231 //but these checks are not documented, so we do check again. 232 if (input == null) { 233 throw new IllegalArgumentException("Bad Arguments."); 234 } 235 236 if (inputOffset < 0 || 237 inputLength < 0 || 238 outputOffset < 0 || 239 input.length < (inputOffset+inputLength)) { 240 241 throw new IllegalArgumentException("Bad Arguments."); 242 } 243 244 if (inputLength == 0) { 245 return 0; 246 } 247 248 249 //Check output for null. 250 if (output == null) { 251 throw new ShortBufferException( 252 "Output buffer should be (at least) " + 253 getUpdateEncryptionOutputSize(inputLength) + 254 " bytes or larger, but not null."); 255 } 256 257 //Check, if output is large enough. 258 if (getUpdateEncryptionOutputSize(inputLength) > output.length-outputOffset){ 259 throw new ShortBufferException( 260 "Usable byte range in output buffer is " + 261 (output.length-outputOffset) + " bytes large, but it should be " + 262 getUpdateEncryptionOutputSize(inputLength) + " bytes or larger."); 263 } 264 265 266 //Save outputOffset, to calc number of bytes stored in output. 267 int saveOutputOffset = outputOffset; 268 269 //Process the whole input. 270 for (int i = inputOffset; i < inputOffset+inputLength; i++) { 271 272 //Add every single byte to our unprocessedPlainTextBuffer. 273 this.unprocessedPlainTextBuffer.add(input[i]); 274 275 //If our unprocessedPlainTextBuffer is full process it and put the 276 //result into output. 277 if (this.unprocessedPlainTextBuffer.isFull()) { 278 279 //If one of the Exception, declared in the catch clause, was 280 //thrown, the cause is orginated here, so we catch it here. 281 try { 282 this.unprocessedPlainTextBuffer.fetch(this.tempBuffer, 0); 283 284 //Process our unprocessedPlainTextBuffer and add the number 285 //of new output bytes to outputOffset. 286 outputOffset += 287 this.mode.encrypt(this.tempBuffer, 0, output, outputOffset); 288 289 } catch (IllegalBlockSizeException cannothappen){ 290 throw new Error("Can not happen.", cannothappen); 291 } catch (ShortBufferException cannothappen){ 292 throw new Error("Can not happen.", cannothappen); 293 } 294 } 295 } 296 297 //Return the number of bytes stored in output. 298 return outputOffset - saveOutputOffset; 299 } 300 301 /** 302 * Calculates the output size for to returned byte array, or 303 * the size for the output array that will 304 * be passed through doFinalEncryption(.....). 305 * 306 * @param inputLength the input length, that will be base for the 307 * calculation. 308 * @return the size for to returned byte array, or 309 * the size for the output array that will 310 * be passed through doFinalEncryption(.....). 311 */ 312 public int getDoFinalEncryptionOutputSize(int inputLength) { 313 //getUpdateSize() + one block for the padding bytes. 314 return getUpdateEncryptionOutputSize(inputLength) + getBlockSize(); 315 } 316 317 /** 318 * Encrypts data in a single part operation, or finishes 319 * a multipart encryption. 320 * 321 * @return the padded and encrypted data. 322 * @param input plainText that should be encrypted. 323 * @param inputOffset the offset in input where the input starts. 324 * @param inputLength the input length. 325 * @throws IllegalArgumentException if <tt>input == null</tt>, 326 * <tt>inputOffset < 0</tt>, <tt>inputLength < 0</tt>, 327 * or <tt>input.length < inputOffset+inputLength</tt>. 328 */ 329 public byte[] doFinalEncryption(byte[] input, int inputOffset, 330 int inputLength) { 331 //The next three if's are hte same as the JCE does check, 332 //but these checks are not documented, so we do check again. 333 if (input == null && inputOffset == 0 && inputLength == 0) { 334 //At these point the JCE byte[] doFinal() was invoked. 335 } else { 336 337 if (input == null) { 338 throw new IllegalArgumentException("Bad Arguments."); 339 } 340 341 if (inputOffset < 0 || 342 inputLength < 0 || 343 input.length < (inputOffset+inputLength)) { 344 345 throw new IllegalArgumentException("Bad Arguments."); 346 } 347 } 348 349 350 //Get space for the result output byte array. 351 byte[] output = new byte[getDoFinalEncryptionOutputSize(inputLength)];; 352 int outputOffset =0; 353 354 //Process the whole input. 355 for (int i = inputOffset; i < inputOffset+inputLength; i++){ 356 357 //Add every single byte to our unprocessedPlainTextBuffer. 358 this.unprocessedPlainTextBuffer.add(input[i]); 359 360 //If our unprocessedPlainTextBuffer is full process it and put 361 //the result into output. 362 if (this.unprocessedPlainTextBuffer.isFull()) { 363 364 //If one of the Exception, declared in the catch clause, was 365 //thrown, the cause is orginated here, so we catch it here. 366 try { 367 this.unprocessedPlainTextBuffer.fetch(this.tempBuffer, 0); 368 369 //Process our unprocessedPlainTextBuffer and add the number 370 //of new output bytes to outputOffset. 371 outputOffset += 372 this.mode.encrypt(this.tempBuffer, 0, output, outputOffset); 373 } catch (IllegalBlockSizeException cannothappen) { 374 throw new Error("Can not happen.", cannothappen); 375 } catch (ShortBufferException cannothappen) { 376 throw new Error("Can not happen.", cannothappen); 377 } 378 } 379 } 380 381 //Fill free space in our unprocessedPlainTextBuffer with arbitrary 382 //content and put the number of filled bytes in the last byte of our 383 //unprocessedPlainTextBuffer. 384 this.unprocessedPlainTextBuffer.doISO10126OctetPadding(); 385 386 //If one of the Exception, declared in the catch clause, was 387 //thrown, the cause is orginated here, so we catch it here. 388 try { 389 this.unprocessedPlainTextBuffer.fetch(this.tempBuffer, 0); 390 391 //Process our unprocessedPlainTextBuffer and add the number of 392 //new output bytes to outputOffset. 393 outputOffset += 394 this.mode.encrypt(this.tempBuffer, 0, output, outputOffset); 395 } catch (IllegalBlockSizeException cannothappen) { 396 throw new Error("Can not happen.", cannothappen); 397 } catch (ShortBufferException cannothappen) { 398 throw new Error("Can not happen.", cannothappen); 399 } 400 401 //Now all things are done, so we can reset the mode object to reuse it. 402 this.mode.resetToIv(); 403 404 //Return the result as byte array, or null if there no result. 405 return output; 406 } 407 408 /** 409 * Encrypts data in a single part operation, or finishes 410 * a multipart encryption. 411 * 412 * @return the number of bytes stored in output. 413 * @param input plainText that should be encrypted. 414 * @param inputOffset the offset in input where the input starts. 415 * @param inputLength the input length. 416 * @param output the buffer for the padded and encrypted result. 417 * @param outputOffset the offset in output where the result is stored. 418 * @throws ShortBufferException if the usable range in the output buffer is 419 * to less. 420 * @throws IllegalArgumentException if <tt>input == null</tt>, 421 * <tt>inputOffset < 0</tt>, <tt>inputLength < 0</tt>, 422 * <tt>outputOffset < 0</tt> or <tt>input.length < 423 * inputOffset+inputLength</tt>. 424 * This means that the usable range must at least 425 * getDoFinalEncryptionOutputSize(inputLength) bytes large. */ 426 public int doFinalEncryption(byte[] input, int inputOffset, int inputLength, 427 byte[] output, int outputOffset) throws ShortBufferException { 428 //The next three if's are hte same as the JCE does check, 429 //but these checks are not documented, so we do check again. 430 if (input == null && inputOffset == 0 && inputLength == 0) { 431 //At these point the JCE 432 //byte[] doFinal(byte[] output, int outputOffset) was invoked. 433 } else { 434 435 if (input == null){ 436 throw new IllegalArgumentException("Bad Arguments."); 437 } 438 439 if (inputOffset < 0 || 440 inputLength < 0 || 441 outputOffset < 0 || 442 input.length < (inputOffset+inputLength)) { 443 444 throw new IllegalArgumentException("Bad Arguments."); 445 } 446 } 447 448 449 //Check output for null. 450 if (output == null) { 451 throw new ShortBufferException( 452 "Output buffer should be (at least) " + 453 getDoFinalEncryptionOutputSize(inputLength) + 454 " bytes or larger, but not null."); 455 } 456 457 //Check, if output is large enough. 458 if (getUpdateEncryptionOutputSize(inputLength) > output.length-outputOffset) { 459 throw new ShortBufferException( 460 "Usable byte range in output buffer is " + 461 (output.length-outputOffset) + " bytes large, but it should be " + 462 getDoFinalEncryptionOutputSize(inputLength) + " bytes or larger."); 463 } 464 465 466 //Save outputOffset, to calc number of bytes stored in output. 467 int saveOutputOffset = outputOffset; 468 469 //Process the whole input. 470 for (int i = inputOffset; i < inputOffset+inputLength; i++) { 471 472 //Add every single byte to our unprocessedPlainTextBuffer. 473 this.unprocessedPlainTextBuffer.add(input[i]); 474 475 //If our unprocessedPlainTextBuffer is full process it and put the 476 //result into output. 477 if (this.unprocessedPlainTextBuffer.isFull()) { 478 479 //If one of the Exception, declared in the catch clause, was 480 //thrown, the cause is orginated here, so we catch it here. 481 try { 482 this.unprocessedPlainTextBuffer.fetch(this.tempBuffer, 0); 483 484 //Process our unprocessedPlainTextBuffer and add the number 485 //of new output bytes to outputOffset. 486 outputOffset += 487 this.mode.encrypt(this.tempBuffer, 0, output, outputOffset); 488 } catch (IllegalBlockSizeException cannothappen) { 489 throw new Error("Can not happen.", cannothappen); 490 } 491 } 492 } 493 494 //Fill free space in our unprocessedPlainTextBuffer with arbitrary 495 //content and put the number of filled bytes in the last byte of our 496 //unprocessedPlainTextBuffer. 497 this.unprocessedPlainTextBuffer.doISO10126OctetPadding(); 498 499 //If one of the Exception, declared in the catch clause, was 500 //thrown, the cause is orginated here, so we catch it here. 501 try { 502 this.unprocessedPlainTextBuffer.fetch(this.tempBuffer, 0); 503 504 //Process our unprocessedPlainTextBuffer and add the number of 505 //new output bytes to outputOffset. 506 outputOffset += 507 this.mode.encrypt(this.tempBuffer, 0, output, outputOffset); 508 } catch (IllegalBlockSizeException cannothappen) { 509 throw new Error("Can not happen.", cannothappen); 510 } 511 512 //Now all things are done, so we can reset the mode object to reuse it. 513 this.mode.resetToIv(); 514 515 //Return the number of bytes stored in output. 516 return outputOffset - saveOutputOffset; 517 } 518 519 /** 520 * Calculates the output size for to returned byte array, or 521 * the size for the output array that will 522 * be passed through updateDecryption(.....). 523 * 524 * @param inputLength the input length, that will be base for the 525 * calculation. 526 * @return the size for to returned byte array, or 527 * the size for the output array that will 528 * be passed through updateDecryption(.....). 529 */ 530 public int getUpdateDecryptionOutputSize(int inputLength) { 531 //Skip the rest if we divide with getBlockSize() 532 //We do at least one byte in the unprocessedCipherTextBuffer. 533 //So we need the this.unprocessedCipherTextBuffer.hasBytes()-1 534 return ( 535 ( 536 this.unprocessedCipherTextBuffer.hasBytes()-1 + inputLength 537 ) / getBlockSize() 538 ) * getBlockSize(); 539 } 540 541 542 /** 543 * Continues a multipart decryption operation, processing 544 * another data part. 545 * @param input padded cipherText that should be decrypted. 546 * @param inputOffset the offset in input where the input starts. 547 * @param inputLength the input length. 548 * @throws IllegalArgumentException if <tt>input == null</tt>, 549 * <tt>inputOffset < 0</tt>, <tt>inputLength < 0</tt>, 550 * or <tt>input.length < inputOffset+inputLength</tt>. 551 * @return the decrypted data, if there enough (at least one block size + 552 * one byte), or byte[0] otherwise. We aren't allowed to return null, 553 * like javadoc for CipherSpi this says, because the JCE 554 * (byte[] Cipher#update(byte[], int, int)) will throw a 555 * NullPointerException. 556 */ 557 public byte[] updateDecryption(byte[] input, int inputOffset, 558 int inputLength) { 559 //The next three if's are the same as the JCE does check, 560 //but these checks are not documented, so we do check again. 561 if (input == null) { 562 throw new IllegalArgumentException("Bad Arguments."); 563 } 564 565 if (inputOffset < 0 || 566 inputLength < 0 || 567 input.length < (inputOffset+inputLength)) { 568 569 throw new IllegalArgumentException("Bad Arguments."); 570 } 571 572 ////if (inputLength == 0){ 573 //// return null; 574 ////} 575 576 577 byte[] output =null; 578 int outputOffset =0; 579 580 //Will be there some result, get space for the result output byte array. 581 ////if(getUpdateDecryptionOutputSize(inputLength) > 0){ 582 output = new byte[getUpdateDecryptionOutputSize(inputLength)]; 583 ////} 584 585 //Process the whole input. 586 for (int i = inputOffset; i < inputOffset+inputLength; i++) { 587 588 //Add every single byte to our unprocessedCipherTextBuffer. 589 this.unprocessedCipherTextBuffer.add(input[i]); 590 591 //If our unprocessedCipherTextBuffer has enough bytes, process it 592 //and put the result into output. 593 if (this.unprocessedCipherTextBuffer.hasEnoughBytes()) { 594 595 //If one of the Exception, declared in the catch clause, was 596 //thrown, the cause is orginated here, so we catch it here. 597 try { 598 this.unprocessedCipherTextBuffer.fetch(this.tempBuffer, 0); 599 600 //Process our unprocessedCipherTextBuffer and add the number 601 //of new output bytes to outputOffset. 602 outputOffset += 603 this.mode.decrypt(this.tempBuffer, 0, output, outputOffset); 604 } catch (IllegalBlockSizeException cannothappen){ 605 throw new Error("Can not happen.", cannothappen); 606 } catch (ShortBufferException cannothappen){ 607 throw new Error("Can not happen.", cannothappen); 608 } 609 } 610 } 611 612 //Return the result as byte array, or byte[0] if there no result. 613 return output; 614 } 615 616 /** 617 * Continues a multipart decryption operation, processing 618 * another data part. 619 * 620 * @param input padded cipherText that should be decrypted. 621 * @param inputOffset the offset in input where the input starts. 622 * @param inputLength the input length. 623 * @param output the buffer for the decrypted result. 624 * @param outputOffset the offset in output where the result is stored. 625 * @throws ShortBufferException if the usable range in the output buffer is 626 * to less. This means that the usable range must at least 627 * getUpdateDecryptionOutputSize(inputLength) bytes large. 628 * @throws IllegalArgumentException if <tt>input == null</tt>, 629 * <tt>inputOffset < 0</tt>, <tt>inputLength < 0</tt>, 630 * <tt>outputOffset < 0</tt> or <tt>input.length < 631 * inputOffset+inputLength</tt>. 632 * @return the number of bytes stored in output. 633 */ 634 public int updateDecryption(byte[] input, int inputOffset, int inputLength, 635 byte[] output, int outputOffset) throws ShortBufferException { 636 //The next three if's are hte same as the JCE does check, 637 //but these checks are not documented, so we do check again. 638 if (input == null) { 639 throw new IllegalArgumentException("Bad Arguments."); 640 } 641 642 if (inputOffset < 0 || 643 inputLength < 0 || 644 outputOffset < 0 || 645 input.length < (inputOffset+inputLength)) { 646 647 throw new IllegalArgumentException("Bad Arguments."); 648 } 649 650 if (inputLength == 0) { 651 return 0; 652 } 653 654 655 //Check output for null. 656 if (output == null) { 657 throw new ShortBufferException( 658 "Output buffer should be (at least) " + 659 getUpdateDecryptionOutputSize(inputLength) + 660 " bytes or larger, but not null."); 661 } 662 663 //Check, if output is large enough. 664 if (getUpdateDecryptionOutputSize(inputLength) > output.length-outputOffset) { 665 throw new ShortBufferException( 666 "Usable byte range in output buffer is " + 667 (output.length-outputOffset) + " bytes large, but it should be " + 668 getUpdateDecryptionOutputSize(inputLength) + " bytes or larger."); 669 } 670 671 672 //Save outputOffset, to calc number of bytes stored in output. 673 int saveOutputOffset = outputOffset; 674 675 //Process the whole input. 676 for (int i = inputOffset; i < inputOffset+inputLength; i++) { 677 678 //Add every single byte to our unprocessedCipherTextBuffer. 679 this.unprocessedCipherTextBuffer.add(input[i]); 680 681 //If our unprocessedCipherTextBuffer has enough bytes, process it 682 //and put the result into output. 683 if (this.unprocessedCipherTextBuffer.hasEnoughBytes()) { 684 685 //If one of the Exception, declared in the catch clause, was 686 //thrown, the cause is orginated here, so we catch it here. 687 try { 688 this.unprocessedCipherTextBuffer.fetch(this.tempBuffer, 0); 689 //Process our unprocessedCipherTextBuffer and add the number 690 //of new output bytes to outputOffset. 691 outputOffset += 692 this.mode.decrypt(this.tempBuffer, 0, output, outputOffset); 693 } catch (IllegalBlockSizeException cannothappen){ 694 throw new Error("Can not happen.", cannothappen); 695 } catch (ShortBufferException cannothappen){ 696 throw new Error("Can not happen.", cannothappen); 697 } 698 } 699 } 700 701 //Return the number of bytes stored in output. 702 return outputOffset - saveOutputOffset; 703 } 704 705 /** 706 * Calculates the output size for to returned byte array, or 707 * the size for the output array that will 708 * be passed through doFinalDecryption(.....). 709 * 710 * @param inputLength the input length, that will be base for the 711 * calculation. 712 * @return the size for to returned byte array, or 713 * the size for the output array that will 714 * be passed through doFinalDecryption(.....). 715 */ 716 public int getDoFinalDecryptionOutputSize(int inputLength) { 717 //Skip the rest if we divide with getBlockSize() 718 return ( 719 ( 720 this.unprocessedCipherTextBuffer.hasBytes() + inputLength 721 ) / getBlockSize() 722 ) * getBlockSize(); 723 } 724 725 /** 726 * Checks if the result from buffer bytes and 727 * a given inputLength is a multiple of the 728 * block size of the underlying mode object. 729 * 730 * @param inputLength the input length, that will be base for the 731 * verification. 732 * @return true if the result from buffer bytes and 733 * a given inputLength is a multiple of the 734 * block size of the underlying mode object, 735 * false otherwise. 736 */ 737 private boolean isBufferAndInputLengthMultipleOfBlockSize(int inputLength) { 738 return ( 739 this.unprocessedCipherTextBuffer.hasBytes() + inputLength 740 ) % getBlockSize() == 0; 741 } 742 743 /** 744 * Checks if a given padCount is valid or not. 745 * 746 * @param padCount the padCount that will be verifyed. 747 * @return true if the paddCount is valid, false otherwise. 748 */ 749 private boolean isPadCountValid(int padCount) { 750 return 1 <= padCount && padCount <= getBlockSize(); 751 } 752 753 /** 754 * Decrypts data in a single part operation, or finishes 755 * a multipart decryption. 756 * 757 * @param input padded cipherText that should be decrypted. 758 * @param inputOffset the offset in input where the input starts. 759 * @param inputLength the input length. 760 * @throws IllegalBlockSizeException if the final size of processed bytes 761 * not a multiple of block size. 762 * @throws BadPaddingException if the decrypted padCount not in the range 763 * between 1 and block size. 764 * @throws IllegalArgumentException if <tt>input == null</tt>, 765 * <tt>inputOffset < 0</tt>, <tt>inputLength < 0</tt>, 766 * or <tt>input.length < inputOffset+inputLength</tt>. 767 * @return the unpadded and decrypted data. 768 */ 769 public byte[] doFinalDecryption(byte[] input, int inputOffset, 770 int inputLength) 771 throws IllegalBlockSizeException, BadPaddingException { 772 //The next three if's are the same as the JCE does check, 773 //but these checks are not documented, so we do check again. 774 if (input == null && inputOffset == 0 && inputLength == 0) { 775 //At these point the JCE byte[] doFinal() was invoked. 776 } else { 777 778 if (input == null) { 779 throw new IllegalArgumentException("Bad Arguments."); 780 } 781 782 if (inputOffset < 0 || 783 inputLength < 0 || 784 input.length < (inputOffset+inputLength)) { 785 786 throw new IllegalArgumentException("Bad Arguments."); 787 } 788 } 789 790 if (isBufferAndInputLengthMultipleOfBlockSize(inputLength) == false) { 791 throw new IllegalBlockSizeException("Input length not multiple of " 792 + getBlockSize() + " bytes."); 793 } 794 795 byte[] output; 796 int outputOffset; 797 if (getDoFinalDecryptionOutputSize(inputLength) > 0){ 798 799 //Get space for the result output byte array. 800 output = new byte[getDoFinalDecryptionOutputSize(inputLength)]; 801 outputOffset = 0; 802 803 } else { 804 805 //There were no date to decrypt, there will never be data to decrypt, 806 //so we can stop here and return byte[0]. Sun does the same in its 807 //provider. This is only for doFinalDecryption(null, 0, 0), wich 808 //will be called by the JCE-API, if someone calls doFinal(). 809 return new byte[0]; 810 } 811 812 //Process the whole input. 813 for (int i = inputOffset; i < inputOffset+inputLength; i++){ 814 815 //Add every single byte to our unprocessedCipherTextBuffer. 816 this.unprocessedCipherTextBuffer.add(input[i]); 817 818 //If our unprocessedCipherTextBuffer has enough bytes, process it 819 //and put the result into output. 820 if (this.unprocessedCipherTextBuffer.hasEnoughBytes()){ 821 822 //If one of the Exception, declared in the catch clause, was 823 //thrown, the cause is orginated here, so we catch it here. 824 try{ 825 this.unprocessedCipherTextBuffer.fetch(this.tempBuffer, 0); 826 827 //Process our unprocessedCipherTextBuffer and add the number 828 //of new output bytes to outputOffset. 829 outputOffset += 830 this.mode.decrypt(this.tempBuffer, 0, output, outputOffset); 831 } catch (ShortBufferException cannothappen){ 832 throw new Error("Can not happen.", cannothappen); 833 } 834 } 835 } 836 837 //If one of the Exception, declared in the catch clause, was 838 //thrown, the cause is orginated here, so we catch it here. 839 try { 840 this.unprocessedCipherTextBuffer.finalFetch(this.tempBuffer, 0); 841 842 //Process our unprocessedCipherTextBuffer and add the number 843 //of new output bytes to outputOffset a final one. 844 outputOffset += 845 this.mode.decrypt(this.tempBuffer, 0, output, outputOffset); 846 } catch (ShortBufferException cannothappen){ 847 throw new Error("Can not happen.", cannothappen); 848 } 849 850 //At these point we reset the mode Iv, to leave the Object in a valid 851 //state (for further use), even if a BadPaddingException will be thrown. 852 this.mode.resetToIv(); 853 854 //Read the padCount from last byte of decrypted data. 855 int padCount = output[outputOffset-1] & 0x000000ff; 856 857 //Check if the padCount is valid. 858 if (isPadCountValid(padCount) == false) { 859 throw new BadPaddingException( 860 "Given final block not properly padded."); 861 } 862 863 //Calculate the new length of the result byte array 864 //(without padding bytes). 865 int returnValueLength = outputOffset-padCount; 866 867 //Get an appropriate byte array (right length). 868 byte[] returnValue = new byte[returnValueLength]; 869 870 //Copy the decrypted data (without padding bytes), in the new 871 //appropriate bytearray. 872 System.arraycopy(output, 0, returnValue, 0, returnValueLength); 873 874 //Return the result as byte array, or as byte[0] if na date available. 875 //For API consistence it would be better to return null, if 876 //returnValueLength == 0. But the Sun provider return byte[0], 877 //so we do this also. 878 return returnValue; 879 } 880 881 /** 882 * Decrypts data in a single part operation, or finishes 883 * a multipart decryption. 884 * 885 * @param input padded cipherText that should be decrypted. 886 * @param inputOffset the offset in input where the input starts. 887 * @param inputLength the input length. 888 * @param output the buffer for the unpadded and decrypted result. 889 * @param outputOffset the offset in output where the result is stored. 890 * @throws IllegalBlockSizeException if the final size of processed bytes 891 * not a multiple of block size. 892 * @throws BadPaddingException if the decrypted padCount not in the range 893 * between 1 and block size. 894 * @throws ShortBufferException if the usable range in the output buffer is 895 * to less. This means that the usable range must at least 896 * getDoFinalDecryptionOutputSize(inputLength) bytes large. 897 * @throws IllegalArgumentException if <tt>input == null</tt>, 898 * <tt>inputOffset < 0</tt>, <tt>inputLength < 0</tt>, 899 * <tt>outputOffset < 0</tt> or <tt>input.length < 900 * inputOffset+inputLength</tt>. 901 * @return the number of bytes stored in output. 902 */ 903 public int doFinalDecryption(byte[] input, int inputOffset, int inputLength, 904 byte[] output, int outputOffset) 905 throws IllegalBlockSizeException, BadPaddingException, 906 ShortBufferException { 907 //The next three if's are the same as the JCE does check, 908 //but these checks are not documented, so we do check again. 909 if (input == null && inputOffset == 0 && inputLength == 0) { 910 //At these point the JCE byte[] doFinal() was invoked. 911 } else { 912 913 if (input == null){ 914 throw new IllegalArgumentException("Bad Arguments."); 915 } 916 917 if (inputOffset < 0 || 918 inputLength < 0 || 919 input.length < (inputOffset+inputLength) ){ 920 921 throw new IllegalArgumentException("Bad Arguments."); 922 } 923 } 924 925 if (isBufferAndInputLengthMultipleOfBlockSize(inputLength) == false) { 926 throw new IllegalBlockSizeException("Input length not multiple of " 927 + getBlockSize() + " bytes."); 928 } 929 930 if (getDoFinalDecryptionOutputSize(inputLength) < 1) { 931 //There were no date to decrypt, there will never be data to decrypt, 932 //so we can stop here and return 0. Sun does the same in its 933 //provider. This is only for doFinalDecryption(null, 0, 0), wich 934 //will be called by the JCE-API, if someone calls doFinal(byte[0],0). 935 return 0; 936 } 937 938 int saveOutputOffset = outputOffset; 939 940 //Process the whole input. 941 for (int i = inputOffset; i < inputOffset+inputLength; i++) { 942 943 //Add every single byte to our unprocessedCipherTextBuffer. 944 this.unprocessedCipherTextBuffer.add(input[i]); 945 946 //If our unprocessedCipherTextBuffer has enough bytes, process it 947 //and put the result into output. 948 if (this.unprocessedCipherTextBuffer.hasEnoughBytes()) { 949 950 this.unprocessedCipherTextBuffer.fetch(this.tempBuffer, 0); 951 952 //Process our unprocessedCipherTextBuffer and add the number 953 //of new output bytes to outputOffset. 954 outputOffset += 955 this.mode.decrypt(this.tempBuffer, 0, output, outputOffset); 956 } 957 } 958 959 this.unprocessedCipherTextBuffer.finalFetch(this.tempBuffer, 0); 960 961 //Process our unprocessedCipherTextBuffer and add the number 962 //of new output bytes to outputOffset a final one. 963 outputOffset += 964 this.mode.decrypt(this.tempBuffer, 0, output, outputOffset); 965 966 //At these point we reset the mode Iv, to leave the Object in a valid 967 //state (for further use), even if a BadPaddingException will be thrown. 968 this.mode.resetToIv(); 969 970 //Read the padCount from last byte of decrypted data. 971 int padCount = output[outputOffset-1] & 0x000000ff; 972 973 //Check if the padCount is valid. 974 if (isPadCountValid(padCount) == false){ 975 throw new BadPaddingException( 976 "Given final block not properly padded."); 977 } 978 979 //Return the effectiv number of bytes stored in output. 980 return outputOffset-saveOutputOffset - padCount; 981 } 982 } 983
|
PaddingISO10126OctetPadding |
|