blob: 23cc79b4960290efff694e5263db0965abbfcd76 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.crypto.provider;
27
28import java.util.Locale;
29
30import java.security.*;
31import java.security.spec.*;
32import javax.crypto.*;
33import javax.crypto.spec.*;
34import javax.crypto.BadPaddingException;
35
36/**
37 * This class represents the symmetric algorithms in its various modes
38 * (<code>ECB</code>, <code>CFB</code>, <code>OFB</code>, <code>CBC</code>,
39 * <code>PCBC</code>, <code>CTR</code>, and <code>CTS</code>) and
40 * padding schemes (<code>PKCS5Padding</code>, <code>NoPadding</code>,
41 * <code>ISO10126Padding</code>).
42 *
43 * @author Gigi Ankeny
44 * @author Jan Luehe
45 * @see ElectronicCodeBook
46 * @see CipherFeedback
47 * @see OutputFeedback
48 * @see CipherBlockChaining
49 * @see PCBC
50 * @see CounterMode
51 * @see CipherTextStealing
52 */
53
54final class CipherCore {
55
56 /*
57 * internal buffer
58 */
59 private byte[] buffer = null;
60
61 /*
62 * internal buffer
63 */
64 private int blockSize = 0;
65
66 /*
67 * unit size (number of input bytes that can be processed at a time)
68 */
69 private int unitBytes = 0;
70
71 /*
72 * index of the content size left in the buffer
73 */
74 private int buffered = 0;
75
76 /*
77 * minimum number of bytes in the buffer required for
78 * FeedbackCipher.encryptFinal()/decryptFinal() call.
79 * update() must buffer this many bytes before before starting
80 * to encrypt/decrypt data.
81 * currently, only CTS mode has a non-zero value due to its special
82 * handling on the last two blocks (the last one may be incomplete).
83 */
84 private int minBytes = 0;
85
86 /*
87 * number of bytes needed to make the total input length a multiple
88 * of the blocksize (this is used in feedback mode, when the number of
89 * input bytes that are processed at a time is different from the block
90 * size)
91 */
92 private int diffBlocksize = 0;
93
94 /*
95 * padding class
96 */
97 private Padding padding = null;
98
99 /*
100 * internal cipher engine
101 */
102 private FeedbackCipher cipher = null;
103
104 /*
105 * the cipher mode
106 */
107 private int cipherMode = ECB_MODE;
108
109 /*
110 * are we encrypting or decrypting?
111 */
112 private boolean decrypting = false;
113
114 /*
115 * Block Mode constants
116 */
117 private static final int ECB_MODE = 0;
118 private static final int CBC_MODE = 1;
119 private static final int CFB_MODE = 2;
120 private static final int OFB_MODE = 3;
121 private static final int PCBC_MODE = 4;
122 private static final int CTR_MODE = 5;
123 private static final int CTS_MODE = 6;
124
125 /**
126 * Creates an instance of CipherCore with default ECB mode and
127 * PKCS5Padding.
128 */
129 CipherCore(SymmetricCipher impl, int blkSize) {
130 blockSize = blkSize;
131 unitBytes = blkSize;
132 diffBlocksize = blkSize;
133
134 /*
135 * The buffer should be usable for all cipher mode and padding
136 * schemes. Thus, it has to be at least (blockSize+1) for CTS.
137 * In decryption mode, it also hold the possible padding block.
138 */
139 buffer = new byte[blockSize*2];
140
141 // set mode and padding
142 cipher = new ElectronicCodeBook(impl);
143 padding = new PKCS5Padding(blockSize);
144 }
145
146 /**
147 * Sets the mode of this cipher.
148 *
149 * @param mode the cipher mode
150 *
151 * @exception NoSuchAlgorithmException if the requested cipher mode does
152 * not exist
153 */
154 void setMode(String mode) throws NoSuchAlgorithmException {
155 if (mode == null)
156 throw new NoSuchAlgorithmException("null mode");
157
158 String modeUpperCase = mode.toUpperCase(Locale.ENGLISH);
159
160 if (modeUpperCase.equals("ECB")) {
161 return;
162 }
163
164 SymmetricCipher rawImpl = cipher.getEmbeddedCipher();
165 if (modeUpperCase.equals("CBC")) {
166 cipherMode = CBC_MODE;
167 cipher = new CipherBlockChaining(rawImpl);
168 }
169 else if (modeUpperCase.equals("CTS")) {
170 cipherMode = CTS_MODE;
171 cipher = new CipherTextStealing(rawImpl);
172 minBytes = blockSize+1;
173 padding = null;
174 }
175 else if (modeUpperCase.equals("CTR")) {
176 cipherMode = CTR_MODE;
177 cipher = new CounterMode(rawImpl);
178 unitBytes = 1;
179 padding = null;
180 }
181 else if (modeUpperCase.startsWith("CFB")) {
182 cipherMode = CFB_MODE;
183 unitBytes = getNumOfUnit(mode, "CFB".length(), blockSize);
184 cipher = new CipherFeedback(rawImpl, unitBytes);
185 }
186 else if (modeUpperCase.startsWith("OFB")) {
187 cipherMode = OFB_MODE;
188 unitBytes = getNumOfUnit(mode, "OFB".length(), blockSize);
189 cipher = new OutputFeedback(rawImpl, unitBytes);
190 }
191 else if (modeUpperCase.equals("PCBC")) {
192 cipherMode = PCBC_MODE;
193 cipher = new PCBC(rawImpl);
194 }
195 else {
196 throw new NoSuchAlgorithmException("Cipher mode: " + mode
197 + " not found");
198 }
199 }
200
201 private static int getNumOfUnit(String mode, int offset, int blockSize)
202 throws NoSuchAlgorithmException {
203 int result = blockSize; // use blockSize as default value
204 if (mode.length() > offset) {
205 int numInt;
206 try {
207 Integer num = Integer.valueOf(mode.substring(offset));
208 numInt = num.intValue();
209 result = numInt >> 3;
210 } catch (NumberFormatException e) {
211 throw new NoSuchAlgorithmException
212 ("Algorithm mode: " + mode + " not implemented");
213 }
214 if ((numInt % 8 != 0) || (result > blockSize)) {
215 throw new NoSuchAlgorithmException
216 ("Invalid algorithm mode: " + mode);
217 }
218 }
219 return result;
220 }
221
222 /**
223 * Sets the padding mechanism of this cipher.
224 *
225 * @param padding the padding mechanism
226 *
227 * @exception NoSuchPaddingException if the requested padding mechanism
228 * does not exist
229 */
230 void setPadding(String paddingScheme)
231 throws NoSuchPaddingException
232 {
233 if (paddingScheme == null) {
234 throw new NoSuchPaddingException("null padding");
235 }
236 if (paddingScheme.equalsIgnoreCase("NoPadding")) {
237 padding = null;
238 } else if (paddingScheme.equalsIgnoreCase("ISO10126Padding")) {
239 padding = new ISO10126Padding(blockSize);
240 } else if (!paddingScheme.equalsIgnoreCase("PKCS5Padding")) {
241 throw new NoSuchPaddingException("Padding: " + paddingScheme
242 + " not implemented");
243 }
244 if ((padding != null) &&
245 ((cipherMode == CTR_MODE) || (cipherMode == CTS_MODE))) {
246 padding = null;
247 throw new NoSuchPaddingException
248 ((cipherMode == CTR_MODE? "CTR":"CTS") +
249 " mode must be used with NoPadding");
250 }
251 }
252
253 /**
254 * Returns the length in bytes that an output buffer would need to be in
255 * order to hold the result of the next <code>update</code> or
256 * <code>doFinal</code> operation, given the input length
257 * <code>inputLen</code> (in bytes).
258 *
259 * <p>This call takes into account any unprocessed (buffered) data from a
260 * previous <code>update</code> call, and padding.
261 *
262 * <p>The actual output length of the next <code>update</code> or
263 * <code>doFinal</code> call may be smaller than the length returned by
264 * this method.
265 *
266 * @param inputLen the input length (in bytes)
267 *
268 * @return the required output buffer size (in bytes)
269 */
270 int getOutputSize(int inputLen) {
271 int totalLen = buffered + inputLen;
272
273 if (padding == null)
274 return totalLen;
275
276 if (decrypting)
277 return totalLen;
278
279 if (unitBytes != blockSize) {
280 if (totalLen < diffBlocksize)
281 return diffBlocksize;
282 else
283 return (totalLen + blockSize -
284 ((totalLen - diffBlocksize) % blockSize));
285 } else {
286 return totalLen + padding.padLength(totalLen);
287 }
288 }
289
290 /**
291 * Returns the initialization vector (IV) in a new buffer.
292 *
293 * <p>This is useful in the case where a random IV has been created
294 * (see <a href = "#init">init</a>),
295 * or in the context of password-based encryption or
296 * decryption, where the IV is derived from a user-provided password.
297 *
298 * @return the initialization vector in a new buffer, or null if the
299 * underlying algorithm does not use an IV, or if the IV has not yet
300 * been set.
301 */
302 byte[] getIV() {
303 byte[] iv = cipher.getIV();
304 return (iv == null) ? null : (byte[])iv.clone();
305 }
306
307 /**
308 * Returns the parameters used with this cipher.
309 *
310 * <p>The returned parameters may be the same that were used to initialize
311 * this cipher, or may contain the default set of parameters or a set of
312 * randomly generated parameters used by the underlying cipher
313 * implementation (provided that the underlying cipher implementation
314 * uses a default set of parameters or creates new parameters if it needs
315 * parameters but was not initialized with any).
316 *
317 * @return the parameters used with this cipher, or null if this cipher
318 * does not use any parameters.
319 */
320 AlgorithmParameters getParameters(String algName) {
321 AlgorithmParameters params = null;
322 if (cipherMode == ECB_MODE) return null;
323 byte[] iv = getIV();
324 if (iv != null) {
325 AlgorithmParameterSpec ivSpec;
326 if (algName.equals("RC2")) {
327 RC2Crypt rawImpl = (RC2Crypt) cipher.getEmbeddedCipher();
328 ivSpec = new RC2ParameterSpec(rawImpl.getEffectiveKeyBits(),
329 iv);
330 } else {
331 ivSpec = new IvParameterSpec(iv);
332 }
333 try {
334 params = AlgorithmParameters.getInstance(algName, "SunJCE");
335 } catch (NoSuchAlgorithmException nsae) {
336 // should never happen
337 throw new RuntimeException("Cannot find " + algName +
338 " AlgorithmParameters implementation in SunJCE provider");
339 } catch (NoSuchProviderException nspe) {
340 // should never happen
341 throw new RuntimeException("Cannot find SunJCE provider");
342 }
343 try {
344 params.init(ivSpec);
345 } catch (InvalidParameterSpecException ipse) {
346 // should never happen
347 throw new RuntimeException("IvParameterSpec not supported");
348 }
349 }
350 return params;
351 }
352
353 /**
354 * Initializes this cipher with a key and a source of randomness.
355 *
356 * <p>The cipher is initialized for one of the following four operations:
357 * encryption, decryption, key wrapping or key unwrapping, depending on
358 * the value of <code>opmode</code>.
359 *
360 * <p>If this cipher requires an initialization vector (IV), it will get
361 * it from <code>random</code>.
362 * This behaviour should only be used in encryption or key wrapping
363 * mode, however.
364 * When initializing a cipher that requires an IV for decryption or
365 * key unwrapping, the IV
366 * (same IV that was used for encryption or key wrapping) must be provided
367 * explicitly as a
368 * parameter, in order to get the correct result.
369 *
370 * <p>This method also cleans existing buffer and other related state
371 * information.
372 *
373 * @param opmode the operation mode of this cipher (this is one of
374 * the following:
375 * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
376 * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
377 * @param key the secret key
378 * @param random the source of randomness
379 *
380 * @exception InvalidKeyException if the given key is inappropriate for
381 * initializing this cipher
382 */
383 void init(int opmode, Key key, SecureRandom random)
384 throws InvalidKeyException {
385 try {
386 init(opmode, key, (AlgorithmParameterSpec)null, random);
387 } catch (InvalidAlgorithmParameterException e) {
388 throw new InvalidKeyException(e.getMessage());
389 }
390 }
391
392 /**
393 * Initializes this cipher with a key, a set of
394 * algorithm parameters, and a source of randomness.
395 *
396 * <p>The cipher is initialized for one of the following four operations:
397 * encryption, decryption, key wrapping or key unwrapping, depending on
398 * the value of <code>opmode</code>.
399 *
400 * <p>If this cipher (including its underlying feedback or padding scheme)
401 * requires any random bytes, it will get them from <code>random</code>.
402 *
403 * @param opmode the operation mode of this cipher (this is one of
404 * the following:
405 * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
406 * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
407 * @param key the encryption key
408 * @param params the algorithm parameters
409 * @param random the source of randomness
410 *
411 * @exception InvalidKeyException if the given key is inappropriate for
412 * initializing this cipher
413 * @exception InvalidAlgorithmParameterException if the given algorithm
414 * parameters are inappropriate for this cipher
415 */
416 void init(int opmode, Key key, AlgorithmParameterSpec params,
417 SecureRandom random)
418 throws InvalidKeyException, InvalidAlgorithmParameterException {
419 decrypting = (opmode == Cipher.DECRYPT_MODE)
420 || (opmode == Cipher.UNWRAP_MODE);
421
422 byte[] keyBytes = getKeyBytes(key);
423
424 byte[] ivBytes;
425 if (params == null) {
426 ivBytes = null;
427 } else if (params instanceof IvParameterSpec) {
428 ivBytes = ((IvParameterSpec)params).getIV();
429 if ((ivBytes == null) || (ivBytes.length != blockSize)) {
430 throw new InvalidAlgorithmParameterException
431 ("Wrong IV length: must be " + blockSize +
432 " bytes long");
433 }
434 } else if (params instanceof RC2ParameterSpec) {
435 ivBytes = ((RC2ParameterSpec)params).getIV();
436 if ((ivBytes != null) && (ivBytes.length != blockSize)) {
437 throw new InvalidAlgorithmParameterException
438 ("Wrong IV length: must be " + blockSize +
439 " bytes long");
440 }
441 } else {
442 throw new InvalidAlgorithmParameterException("Wrong parameter "
443 + "type: IV "
444 + "expected");
445 }
446
447 if (cipherMode == ECB_MODE) {
448 if (ivBytes != null) {
449 throw new InvalidAlgorithmParameterException
450 ("ECB mode cannot use IV");
451 }
452 } else if (ivBytes == null) {
453 if (decrypting) {
454 throw new InvalidAlgorithmParameterException("Parameters "
455 + "missing");
456 }
457 if (random == null) {
458 random = SunJCE.RANDOM;
459 }
460 ivBytes = new byte[blockSize];
461 random.nextBytes(ivBytes);
462 }
463
464 buffered = 0;
465 diffBlocksize = blockSize;
466
467 String algorithm = key.getAlgorithm();
468
469 cipher.init(decrypting, algorithm, keyBytes, ivBytes);
470 }
471
472 void init(int opmode, Key key, AlgorithmParameters params,
473 SecureRandom random)
474 throws InvalidKeyException, InvalidAlgorithmParameterException {
475 IvParameterSpec ivSpec = null;
476 if (params != null) {
477 try {
478 ivSpec = (IvParameterSpec)params.getParameterSpec
479 (IvParameterSpec.class);
480 } catch (InvalidParameterSpecException ipse) {
481 throw new InvalidAlgorithmParameterException("Wrong parameter "
482 + "type: IV "
483 + "expected");
484 }
485 }
486 init(opmode, key, ivSpec, random);
487 }
488
489 /**
490 * Return the key bytes of the specified key. Throw an InvalidKeyException
491 * if the key is not usable.
492 */
493 static byte[] getKeyBytes(Key key) throws InvalidKeyException {
494 if (key == null) {
495 throw new InvalidKeyException("No key given");
496 }
497 // note: key.getFormat() may return null
498 if (!"RAW".equalsIgnoreCase(key.getFormat())) {
499 throw new InvalidKeyException("Wrong format: RAW bytes needed");
500 }
501 byte[] keyBytes = key.getEncoded();
502 if (keyBytes == null) {
503 throw new InvalidKeyException("RAW key bytes missing");
504 }
505 return keyBytes;
506 }
507
508 /**
509 * Continues a multiple-part encryption or decryption operation
510 * (depending on how this cipher was initialized), processing another data
511 * part.
512 *
513 * <p>The first <code>inputLen</code> bytes in the <code>input</code>
514 * buffer, starting at <code>inputOffset</code>, are processed, and the
515 * result is stored in a new buffer.
516 *
517 * @param input the input buffer
518 * @param inputOffset the offset in <code>input</code> where the input
519 * starts
520 * @param inputLen the input length
521 *
522 * @return the new buffer with the result
523 *
524 * @exception IllegalStateException if this cipher is in a wrong state
525 * (e.g., has not been initialized)
526 */
527 byte[] update(byte[] input, int inputOffset, int inputLen) {
528 byte[] output = null;
529 byte[] out = null;
530 try {
531 output = new byte[getOutputSize(inputLen)];
532 int len = update(input, inputOffset, inputLen, output,
533 0);
534 if (len == output.length) {
535 out = output;
536 } else {
537 out = new byte[len];
538 System.arraycopy(output, 0, out, 0, len);
539 }
540 } catch (ShortBufferException e) {
541 // never thrown
542 }
543 return out;
544 }
545
546 /**
547 * Continues a multiple-part encryption or decryption operation
548 * (depending on how this cipher was initialized), processing another data
549 * part.
550 *
551 * <p>The first <code>inputLen</code> bytes in the <code>input</code>
552 * buffer, starting at <code>inputOffset</code>, are processed, and the
553 * result is stored in the <code>output</code> buffer, starting at
554 * <code>outputOffset</code>.
555 *
556 * @param input the input buffer
557 * @param inputOffset the offset in <code>input</code> where the input
558 * starts
559 * @param inputLen the input length
560 * @param output the buffer for the result
561 * @param outputOffset the offset in <code>output</code> where the result
562 * is stored
563 *
564 * @return the number of bytes stored in <code>output</code>
565 *
566 * @exception ShortBufferException if the given output buffer is too small
567 * to hold the result
568 */
569 int update(byte[] input, int inputOffset, int inputLen, byte[] output,
570 int outputOffset) throws ShortBufferException {
571 // figure out how much can be sent to crypto function
572 int len = buffered + inputLen - minBytes;
573 if (padding != null && decrypting) {
574 // do not include the padding bytes when decrypting
575 len -= blockSize;
576 }
577 // do not count the trailing bytes which do not make up a unit
578 len = (len > 0 ? (len - (len%unitBytes)) : 0);
579
580 // check output buffer capacity
581 if ((output == null) || ((output.length - outputOffset) < len)) {
582 throw new ShortBufferException("Output buffer must be "
583 + "(at least) " + len
584 + " bytes long");
585 }
586 if (len != 0) {
587 // there is some work to do
588 byte[] in = new byte[len];
589
590 int inputConsumed = len - buffered;
591 int bufferedConsumed = buffered;
592 if (inputConsumed < 0) {
593 inputConsumed = 0;
594 bufferedConsumed = len;
595 }
596
597 if (buffered != 0) {
598 System.arraycopy(buffer, 0, in, 0, bufferedConsumed);
599 }
600 if (inputConsumed > 0) {
601 System.arraycopy(input, inputOffset, in,
602 bufferedConsumed, inputConsumed);
603 }
604
605 if (decrypting) {
606 cipher.decrypt(in, 0, len, output, outputOffset);
607 } else {
608 cipher.encrypt(in, 0, len, output, outputOffset);
609 }
610
611 // Let's keep track of how many bytes are needed to make
612 // the total input length a multiple of blocksize when
613 // padding is applied
614 if (unitBytes != blockSize) {
615 if (len < diffBlocksize)
616 diffBlocksize -= len;
617 else
618 diffBlocksize = blockSize -
619 ((len - diffBlocksize) % blockSize);
620 }
621
622 inputLen -= inputConsumed;
623 inputOffset += inputConsumed;
624 outputOffset += len;
625 buffered -= bufferedConsumed;
626 if (buffered > 0) {
627 System.arraycopy(buffer, bufferedConsumed, buffer, 0,
628 buffered);
629 }
630 }
631 // left over again
632 if (inputLen > 0) {
633 System.arraycopy(input, inputOffset, buffer, buffered,
634 inputLen);
635 }
636 buffered += inputLen;
637 return len;
638 }
639
640 /**
641 * Encrypts or decrypts data in a single-part operation,
642 * or finishes a multiple-part operation.
643 * The data is encrypted or decrypted, depending on how this cipher was
644 * initialized.
645 *
646 * <p>The first <code>inputLen</code> bytes in the <code>input</code>
647 * buffer, starting at <code>inputOffset</code>, and any input bytes that
648 * may have been buffered during a previous <code>update</code> operation,
649 * are processed, with padding (if requested) being applied.
650 * The result is stored in a new buffer.
651 *
652 * <p>The cipher is reset to its initial state (uninitialized) after this
653 * call.
654 *
655 * @param input the input buffer
656 * @param inputOffset the offset in <code>input</code> where the input
657 * starts
658 * @param inputLen the input length
659 *
660 * @return the new buffer with the result
661 *
662 * @exception IllegalBlockSizeException if this cipher is a block cipher,
663 * no padding has been requested (only in encryption mode), and the total
664 * input length of the data processed by this cipher is not a multiple of
665 * block size
666 * @exception BadPaddingException if this cipher is in decryption mode,
667 * and (un)padding has been requested, but the decrypted data is not
668 * bounded by the appropriate padding bytes
669 */
670 byte[] doFinal(byte[] input, int inputOffset, int inputLen)
671 throws IllegalBlockSizeException, BadPaddingException {
672 byte[] output = null;
673 byte[] out = null;
674 try {
675 output = new byte[getOutputSize(inputLen)];
676 int len = doFinal(input, inputOffset, inputLen, output, 0);
677 if (len < output.length) {
678 out = new byte[len];
679 if (len != 0)
680 System.arraycopy(output, 0, out, 0, len);
681 } else {
682 out = output;
683 }
684 } catch (ShortBufferException e) {
685 // never thrown
686 }
687 return out;
688 }
689
690 /**
691 * Encrypts or decrypts data in a single-part operation,
692 * or finishes a multiple-part operation.
693 * The data is encrypted or decrypted, depending on how this cipher was
694 * initialized.
695 *
696 * <p>The first <code>inputLen</code> bytes in the <code>input</code>
697 * buffer, starting at <code>inputOffset</code>, and any input bytes that
698 * may have been buffered during a previous <code>update</code> operation,
699 * are processed, with padding (if requested) being applied.
700 * The result is stored in the <code>output</code> buffer, starting at
701 * <code>outputOffset</code>.
702 *
703 * <p>The cipher is reset to its initial state (uninitialized) after this
704 * call.
705 *
706 * @param input the input buffer
707 * @param inputOffset the offset in <code>input</code> where the input
708 * starts
709 * @param inputLen the input length
710 * @param output the buffer for the result
711 * @param outputOffset the offset in <code>output</code> where the result
712 * is stored
713 *
714 * @return the number of bytes stored in <code>output</code>
715 *
716 * @exception IllegalBlockSizeException if this cipher is a block cipher,
717 * no padding has been requested (only in encryption mode), and the total
718 * input length of the data processed by this cipher is not a multiple of
719 * block size
720 * @exception ShortBufferException if the given output buffer is too small
721 * to hold the result
722 * @exception BadPaddingException if this cipher is in decryption mode,
723 * and (un)padding has been requested, but the decrypted data is not
724 * bounded by the appropriate padding bytes
725 */
726 int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
727 int outputOffset)
728 throws IllegalBlockSizeException, ShortBufferException,
729 BadPaddingException {
730
731 // calculate the total input length
732 int totalLen = buffered + inputLen;
733 int paddedLen = totalLen;
734 int paddingLen = 0;
735
736 // will the total input length be a multiple of blockSize?
737 if (unitBytes != blockSize) {
738 if (totalLen < diffBlocksize) {
739 paddingLen = diffBlocksize - totalLen;
740 } else {
741 paddingLen = blockSize -
742 ((totalLen - diffBlocksize) % blockSize);
743 }
744 } else if (padding != null) {
745 paddingLen = padding.padLength(totalLen);
746 }
747
748 if ((paddingLen > 0) && (paddingLen != blockSize) &&
749 (padding != null) && decrypting) {
750 throw new IllegalBlockSizeException
751 ("Input length must be multiple of " + blockSize +
752 " when decrypting with padded cipher");
753 }
754
755 // if encrypting and padding not null, add padding
756 if (!decrypting && padding != null)
757 paddedLen += paddingLen;
758
759 // check output buffer capacity.
760 // if we are decrypting with padding applied, we can perform this
761 // check only after we have determined how many padding bytes there
762 // are.
763 if (output == null) {
764 throw new ShortBufferException("Output buffer is null");
765 }
766 int outputCapacity = output.length - outputOffset;
767 if (((!decrypting) || (padding == null)) &&
768 (outputCapacity < paddedLen) ||
769 (decrypting && (outputCapacity < (paddedLen - blockSize)))) {
770 throw new ShortBufferException("Output buffer too short: "
771 + outputCapacity + " bytes given, "
772 + paddedLen + " bytes needed");
773 }
774
775 // prepare the final input avoiding copying if possible
776 byte[] finalBuf = input;
777 int finalOffset = inputOffset;
778 if ((buffered != 0) || (!decrypting && padding != null)) {
779 finalOffset = 0;
780 finalBuf = new byte[paddedLen];
781 if (buffered != 0) {
782 System.arraycopy(buffer, 0, finalBuf, 0, buffered);
783 }
784 if (inputLen != 0) {
785 System.arraycopy(input, inputOffset, finalBuf,
786 buffered, inputLen);
787 }
788 if (!decrypting && padding != null) {
789 padding.padWithLen(finalBuf, totalLen, paddingLen);
790 }
791 }
792
793 if (decrypting) {
794 // if the size of specified output buffer is less than
795 // the length of the cipher text, then the current
796 // content of cipher has to be preserved in order for
797 // users to retry the call with a larger buffer in the
798 // case of ShortBufferException.
799 if (outputCapacity < paddedLen) {
800 cipher.save();
801 }
802 // create temporary output buffer so that only "real"
803 // data bytes are passed to user's output buffer.
804 byte[] outWithPadding = new byte[totalLen];
805 totalLen = finalNoPadding(finalBuf, finalOffset, outWithPadding,
806 0, totalLen);
807
808 if (padding != null) {
809 int padStart = padding.unpad(outWithPadding, 0, totalLen);
810 if (padStart < 0) {
811 throw new BadPaddingException("Given final block not "
812 + "properly padded");
813 }
814 totalLen = padStart;
815 }
816 if ((output.length - outputOffset) < totalLen) {
817 // restore so users can retry with a larger buffer
818 cipher.restore();
819 throw new ShortBufferException("Output buffer too short: "
820 + (output.length-outputOffset)
821 + " bytes given, " + totalLen
822 + " bytes needed");
823 }
824 for (int i = 0; i < totalLen; i++) {
825 output[outputOffset + i] = outWithPadding[i];
826 }
827 } else { // encrypting
828 totalLen = finalNoPadding(finalBuf, finalOffset, output,
829 outputOffset, paddedLen);
830 }
831
832 buffered = 0;
833 diffBlocksize = blockSize;
834 if (cipherMode != ECB_MODE) {
835 ((FeedbackCipher)cipher).reset();
836 }
837 return totalLen;
838 }
839
840 private int finalNoPadding(byte[] in, int inOff, byte[] out, int outOff,
841 int len)
842 throws IllegalBlockSizeException
843 {
844 if (in == null || len == 0)
845 return 0;
846
847 if ((cipherMode != CFB_MODE) && (cipherMode != OFB_MODE)
848 && ((len % unitBytes) != 0) && (cipherMode != CTS_MODE)) {
849 if (padding != null) {
850 throw new IllegalBlockSizeException
851 ("Input length (with padding) not multiple of " +
852 unitBytes + " bytes");
853 } else {
854 throw new IllegalBlockSizeException
855 ("Input length not multiple of " + unitBytes
856 + " bytes");
857 }
858 }
859
860 if (decrypting) {
861 cipher.decryptFinal(in, inOff, len, out, outOff);
862 } else {
863 cipher.encryptFinal(in, inOff, len, out, outOff);
864 }
865
866 return len;
867 }
868
869 // Note: Wrap() and Unwrap() are the same in
870 // each of SunJCE CipherSpi implementation classes.
871 // They are duplicated due to export control requirements:
872 // All CipherSpi implementation must be final.
873 /**
874 * Wrap a key.
875 *
876 * @param key the key to be wrapped.
877 *
878 * @return the wrapped key.
879 *
880 * @exception IllegalBlockSizeException if this cipher is a block
881 * cipher, no padding has been requested, and the length of the
882 * encoding of the key to be wrapped is not a
883 * multiple of the block size.
884 *
885 * @exception InvalidKeyException if it is impossible or unsafe to
886 * wrap the key with this cipher (e.g., a hardware protected key is
887 * being passed to a software only cipher).
888 */
889 byte[] wrap(Key key)
890 throws IllegalBlockSizeException, InvalidKeyException {
891 byte[] result = null;
892
893 try {
894 byte[] encodedKey = key.getEncoded();
895 if ((encodedKey == null) || (encodedKey.length == 0)) {
896 throw new InvalidKeyException("Cannot get an encoding of " +
897 "the key to be wrapped");
898 }
899 result = doFinal(encodedKey, 0, encodedKey.length);
900 } catch (BadPaddingException e) {
901 // Should never happen
902 }
903 return result;
904 }
905
906 /**
907 * Unwrap a previously wrapped key.
908 *
909 * @param wrappedKey the key to be unwrapped.
910 *
911 * @param wrappedKeyAlgorithm the algorithm the wrapped key is for.
912 *
913 * @param wrappedKeyType the type of the wrapped key.
914 * This is one of <code>Cipher.SECRET_KEY</code>,
915 * <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>.
916 *
917 * @return the unwrapped key.
918 *
919 * @exception NoSuchAlgorithmException if no installed providers
920 * can create keys of type <code>wrappedKeyType</code> for the
921 * <code>wrappedKeyAlgorithm</code>.
922 *
923 * @exception InvalidKeyException if <code>wrappedKey</code> does not
924 * represent a wrapped key of type <code>wrappedKeyType</code> for
925 * the <code>wrappedKeyAlgorithm</code>.
926 */
927 Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
928 int wrappedKeyType)
929 throws InvalidKeyException, NoSuchAlgorithmException {
930 byte[] encodedKey;
931 try {
932 encodedKey = doFinal(wrappedKey, 0, wrappedKey.length);
933 } catch (BadPaddingException ePadding) {
934 throw new InvalidKeyException("The wrapped key is not padded " +
935 "correctly");
936 } catch (IllegalBlockSizeException eBlockSize) {
937 throw new InvalidKeyException("The wrapped key does not have " +
938 "the correct length");
939 }
940 return ConstructKeys.constructKey(encodedKey, wrappedKeyAlgorithm,
941 wrappedKeyType);
942 }
943}