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