History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/crypto/provider/CipherCore.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/crypto/provider/CipherCore.java+943−0
@@ -0,0 +1,943 @@
1+/*
2+ * Copyright (c) 2002, 2007, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package com.sun.crypto.provider;
27+
28+import java.util.Locale;
29+
30+import java.security.*;
31+import java.security.spec.*;
32+import javax.crypto.*;
33+import javax.crypto.spec.*;
34+import 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+
54+final 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+}