Save This Page
Home » openjdk-7 » com.sun.crypto » provider » [javadoc | source]
    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   }

Save This Page
Home » openjdk-7 » com.sun.crypto » provider » [javadoc | source]