Save This Page
Home » geronimo-2.2-source-release » org.apache.geronimo.crypto.crypto.modes » [javadoc | source]
    1   /**
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   
   18   package org.apache.geronimo.crypto.crypto.modes;
   19   
   20   import org.apache.geronimo.crypto.crypto.BlockCipher;
   21   import org.apache.geronimo.crypto.crypto.CipherParameters;
   22   import org.apache.geronimo.crypto.crypto.DataLengthException;
   23   import org.apache.geronimo.crypto.crypto.params.ParametersWithIV;
   24   
   25   /**
   26    * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
   27    */
   28   public class CBCBlockCipher
   29       implements BlockCipher
   30   {
   31       private byte[]          IV;
   32       private byte[]          cbcV;
   33       private byte[]          cbcNextV;
   34   
   35       private int             blockSize;
   36       private BlockCipher     cipher = null;
   37       private boolean         encrypting;
   38   
   39       /**
   40        * Basic constructor.
   41        *
   42        * @param cipher the block cipher to be used as the basis of chaining.
   43        */
   44       public CBCBlockCipher(
   45           BlockCipher cipher)
   46       {
   47           this.cipher = cipher;
   48           this.blockSize = cipher.getBlockSize();
   49   
   50           this.IV = new byte[blockSize];
   51           this.cbcV = new byte[blockSize];
   52           this.cbcNextV = new byte[blockSize];
   53       }
   54   
   55       /**
   56        * return the underlying block cipher that we are wrapping.
   57        *
   58        * @return the underlying block cipher that we are wrapping.
   59        */
   60       public BlockCipher getUnderlyingCipher()
   61       {
   62           return cipher;
   63       }
   64   
   65       /**
   66        * Initialise the cipher and, possibly, the initialisation vector (IV).
   67        * If an IV isn't passed as part of the parameter, the IV will be all zeros.
   68        *
   69        * @param encrypting if true the cipher is initialised for
   70        *  encryption, if false for decryption.
   71        * @param params the key and other data required by the cipher.
   72        * @exception IllegalArgumentException if the params argument is
   73        * inappropriate.
   74        */
   75       public void init(
   76           boolean             encrypting,
   77           CipherParameters    params)
   78           throws IllegalArgumentException
   79       {
   80           this.encrypting = encrypting;
   81           
   82           if (params instanceof ParametersWithIV)
   83           {
   84                   ParametersWithIV ivParam = (ParametersWithIV)params;
   85                   byte[]      iv = ivParam.getIV();
   86   
   87                   if (iv.length != blockSize)
   88                   {
   89                       throw new IllegalArgumentException("initialisation vector must be the same length as block size");
   90                   }
   91   
   92                   System.arraycopy(iv, 0, IV, 0, iv.length);
   93   
   94                   reset();
   95   
   96                   cipher.init(encrypting, ivParam.getParameters());
   97           }
   98           else
   99           {
  100                   reset();
  101   
  102                   cipher.init(encrypting, params);
  103           }
  104       }
  105   
  106       /**
  107        * return the algorithm name and mode.
  108        *
  109        * @return the name of the underlying algorithm followed by "/CBC".
  110        */
  111       public String getAlgorithmName()
  112       {
  113           return cipher.getAlgorithmName() + "/CBC";
  114       }
  115   
  116       /**
  117        * return the block size of the underlying cipher.
  118        *
  119        * @return the block size of the underlying cipher.
  120        */
  121       public int getBlockSize()
  122       {
  123           return cipher.getBlockSize();
  124       }
  125   
  126       /**
  127        * Process one block of input from the array in and write it to
  128        * the out array.
  129        *
  130        * @param in the array containing the input data.
  131        * @param inOff offset into the in array the data starts at.
  132        * @param out the array the output data will be copied into.
  133        * @param outOff the offset into the out array the output will start at.
  134        * @exception DataLengthException if there isn't enough data in in, or
  135        * space in out.
  136        * @exception IllegalStateException if the cipher isn't initialised.
  137        * @return the number of bytes processed and produced.
  138        */
  139       public int processBlock(
  140           byte[]      in,
  141           int         inOff,
  142           byte[]      out,
  143           int         outOff)
  144           throws DataLengthException, IllegalStateException
  145       {
  146           return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
  147       }
  148   
  149       /**
  150        * reset the chaining vector back to the IV and reset the underlying
  151        * cipher.
  152        */
  153       public void reset()
  154       {
  155           System.arraycopy(IV, 0, cbcV, 0, IV.length);
  156   
  157           cipher.reset();
  158       }
  159   
  160       /**
  161        * Do the appropriate chaining step for CBC mode encryption.
  162        *
  163        * @param in the array containing the data to be encrypted.
  164        * @param inOff offset into the in array the data starts at.
  165        * @param out the array the encrypted data will be copied into.
  166        * @param outOff the offset into the out array the output will start at.
  167        * @exception DataLengthException if there isn't enough data in in, or
  168        * space in out.
  169        * @exception IllegalStateException if the cipher isn't initialised.
  170        * @return the number of bytes processed and produced.
  171        */
  172       private int encryptBlock(
  173           byte[]      in,
  174           int         inOff,
  175           byte[]      out,
  176           int         outOff)
  177           throws DataLengthException, IllegalStateException
  178       {
  179           if ((inOff + blockSize) > in.length)
  180           {
  181               throw new DataLengthException("input buffer too short");
  182           }
  183   
  184           /*
  185            * XOR the cbcV and the input,
  186            * then encrypt the cbcV
  187            */
  188           for (int i = 0; i < blockSize; i++)
  189           {
  190               cbcV[i] ^= in[inOff + i];
  191           }
  192   
  193           int length = cipher.processBlock(cbcV, 0, out, outOff);
  194   
  195           /*
  196            * copy ciphertext to cbcV
  197            */
  198           System.arraycopy(out, outOff, cbcV, 0, cbcV.length);
  199   
  200           return length;
  201       }
  202   
  203       /**
  204        * Do the appropriate chaining step for CBC mode decryption.
  205        *
  206        * @param in the array containing the data to be decrypted.
  207        * @param inOff offset into the in array the data starts at.
  208        * @param out the array the decrypted data will be copied into.
  209        * @param outOff the offset into the out array the output will start at.
  210        * @exception DataLengthException if there isn't enough data in in, or
  211        * space in out.
  212        * @exception IllegalStateException if the cipher isn't initialised.
  213        * @return the number of bytes processed and produced.
  214        */
  215       private int decryptBlock(
  216           byte[]      in,
  217           int         inOff,
  218           byte[]      out,
  219           int         outOff)
  220           throws DataLengthException, IllegalStateException
  221       {
  222           if ((inOff + blockSize) > in.length)
  223           {
  224               throw new DataLengthException("input buffer too short");
  225           }
  226   
  227           System.arraycopy(in, inOff, cbcNextV, 0, blockSize);
  228   
  229           int length = cipher.processBlock(in, inOff, out, outOff);
  230   
  231           /*
  232            * XOR the cbcV and the output
  233            */
  234           for (int i = 0; i < blockSize; i++)
  235           {
  236               out[outOff + i] ^= cbcV[i];
  237           }
  238   
  239           /*
  240            * swap the back up buffer into next position
  241            */
  242           byte[]  tmp;
  243   
  244           tmp = cbcV;
  245           cbcV = cbcNextV;
  246           cbcNextV = tmp;
  247   
  248           return length;
  249       }
  250   }

Save This Page
Home » geronimo-2.2-source-release » org.apache.geronimo.crypto.crypto.modes » [javadoc | source]