Source for javax.crypto.CipherSpi

   1: /* CipherSpi.java -- The cipher service provider interface.
   2:    Copyright (C) 2004, 2006  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.crypto;
  40: 
  41: import java.nio.ByteBuffer;
  42: 
  43: import java.security.AlgorithmParameters;
  44: import java.security.InvalidAlgorithmParameterException;
  45: import java.security.InvalidKeyException;
  46: import java.security.Key;
  47: import java.security.NoSuchAlgorithmException;
  48: import java.security.SecureRandom;
  49: import java.security.spec.AlgorithmParameterSpec;
  50: 
  51: /**
  52:  * <p>This class represents the <i>Service Provider Interface</i>
  53:  * (<b>SPI</b>) for cryptographic ciphers.</p>
  54:  *
  55:  * <p>Providers of cryptographic ciphers must subclass this for every
  56:  * cipher they implement, implementing the abstract methods as
  57:  * appropriate, then provide an entry that points to the subclass in
  58:  * their implementation of {@link java.security.Provider}.</p>
  59:  *
  60:  * <p>CipherSpi objects are instantiated along with {@link Cipher}s when
  61:  * the {@link Cipher#getInstance(java.lang.String)} methods are invoked.
  62:  * Particular ciphers are referenced by a <i>transformation</i>, which
  63:  * is a String consisting of the cipher's name or the ciper's name
  64:  * followed by a mode and a padding. Transformations all follow the
  65:  * general form:</p>
  66:  *
  67:  * <ul>
  68:  * <li><i>algorithm</i>, or</li>
  69:  * <li><i>algorithm</i>/<i>mode</i>/<i>padding</i>
  70:  * </ul>
  71:  *
  72:  * <p>Cipher names in the master {@link java.security.Provider} class
  73:  * may be:</p>
  74:  *
  75:  * <ol>
  76:  * <li>The algorithm's name, which uses a pluggable mode and padding:
  77:  * <code>Cipher.<i>algorithm</i></code></li>
  78:  * <li>The algorithm's name and the mode, which uses pluggable padding:
  79:  * <code>Cipher.<i>algorithm</i>/<i>mode</i></code></li>
  80:  * <li>The algorithm's name and the padding, which uses a pluggable
  81:  * mode: <code>Cipher.<i>algorithm</i>//<i>padding</i></code></li>
  82:  * <li>The algorihtm's name, the mode, and the padding:
  83:  * <code>Cipher.<i>algorithm</i>/<i>mode</i>/<i>padding</i></code></li>
  84:  * </ol>
  85:  *
  86:  * <p>When any {@link Cipher#getInstance(java.lang.String)} method is
  87:  * invoked, the following happens if the transformation is simply
  88:  * <i>algorithm</i>:</p>
  89:  *
  90:  * <ol>
  91:  * <li>If the provider defines a <code>CipherSpi</code> implementation
  92:  * for "<i>algorithm</i>", return it. Otherwise throw a {@link
  93:  * java.security.NoSuchAlgorithmException}.</li>
  94:  * </ol>
  95:  *
  96:  * <p>If the transformation is of the form
  97:  * <i>algorithm</i>/<i>mode</i>/<i>padding</i>:</p>
  98:  *
  99:  * <ol>
 100:  * <li>If the provider defines a <code>CipherSpi</code> subclass for
 101:  * "<i>algorithm</i>/<i>mode</i>/<i>padding</i>", return it. Otherwise
 102:  * go to step 2.</li>
 103:  *
 104:  * <li>If the provider defines a <code>CipherSpi</code> subclass for
 105:  * "<i>algorithm</i>/<i>mode</i>", instatiate it, call {@link
 106:  * #engineSetPadding(java.lang.String)} for the padding name, and return
 107:  * it. Otherwise go to step 3.</li>
 108:  *
 109:  * <li>If the provider defines a <code>CipherSpi</code> subclass for
 110:  * "<i>algorithm</i>//<i>padding</i>", instatiate it, call {@link
 111:  * #engineSetMode(java.lang.String)} for the mode name, and return
 112:  * it. Otherwise go to step 4.</li>
 113:  *
 114:  * <li>If the provider defines a <code>CipherSpi</code> subclass for
 115:  * "<i>algorithm</i>", instatiate it, call {@link
 116:  * #engineSetMode(java.lang.String)} for the mode name, call {@link
 117:  * #engineSetPadding(java.lang.String)} for the padding name, and return
 118:  * it. Otherwise throw a {@link java.security.NoSuchAlgorithmException}.</li>
 119:  * </ol>
 120:  *
 121:  * @author Casey Marshall (csm@gnu.org)
 122:  * @since 1.4
 123:  */
 124: public abstract class CipherSpi
 125: {
 126: 
 127:   // Constructors.
 128:   // ------------------------------------------------------------------------
 129: 
 130:   /**
 131:    * Create a new CipherSpi.
 132:    */
 133:   public CipherSpi()
 134:   {
 135:   }
 136: 
 137:   // Abstract methods to be implemented by providers.
 138:   // ------------------------------------------------------------------------
 139: 
 140:   /**
 141:    * Finishes a multi-part transformation or transforms a portion of a
 142:    * byte array, and returns the transformed bytes.
 143:    *
 144:    * @param input       The input bytes.
 145:    * @param inputOffset The index in the input at which to start.
 146:    * @param inputLength The number of bytes to transform.
 147:    * @return The transformed bytes in a new array.
 148:    * @throws javax.crypto.IllegalBlockSizeException If this instance has
 149:    *         no padding and the input size is not a multiple of the
 150:    *         block size.
 151:    * @throws javax.crypto.BadPaddingException If this instance is being
 152:    *         used for decryption and the padding is not appropriate for
 153:    *         this instance's padding scheme.
 154:    */
 155:   protected abstract byte[]
 156:   engineDoFinal(byte[] input, int inputOffset, int inputLength)
 157:   throws IllegalBlockSizeException, BadPaddingException;
 158: 
 159:   /**
 160:    * Finishes a multi-part transformation or transforms a portion of a
 161:    * byte array, and stores the transformed bytes in the supplied array.
 162:    *
 163:    * @param input        The input bytes.
 164:    * @param inputOffset  The index in the input at which to start.
 165:    * @param inputLength  The number of bytes to transform.
 166:    * @param output       The output byte array.
 167:    * @param outputOffset The index in the output array at which to start.
 168:    * @return The number of transformed bytes stored in the output array.
 169:    * @throws javax.crypto.IllegalBlockSizeException If this instance has
 170:    *         no padding and the input size is not a multiple of the
 171:    *         block size.
 172:    * @throws javax.crypto.BadPaddingException If this instance is being
 173:    *         used for decryption and the padding is not appropriate for
 174:    *         this instance's padding scheme.
 175:    * @throws javax.crypto.ShortBufferException If there is not enough
 176:    *         space in the output array for the transformed bytes.
 177:    */
 178:   protected abstract int
 179:   engineDoFinal(byte[] input, int inputOffset, int inputLength,
 180:                 byte[] output, int outputOffset)
 181:   throws IllegalBlockSizeException, BadPaddingException, ShortBufferException;
 182: 
 183:   /**
 184:    * @since 1.5
 185:    */
 186:   protected int engineDoFinal (ByteBuffer input, ByteBuffer output)
 187:     throws BadPaddingException, IllegalBlockSizeException,
 188:            ShortBufferException
 189:   {
 190:     int total = 0;
 191:     byte[] inbuf = new byte[256];
 192:     while (input.hasRemaining ())
 193:       {
 194:         int in = Math.min (inbuf.length, input.remaining ());
 195:         input.get (inbuf, 0, in);
 196:         byte[] outbuf = new byte[engineGetOutputSize (in)];
 197:         int out = 0;
 198:         if (input.hasRemaining ()) // i.e., we have more 'update' calls
 199:           out = engineUpdate (inbuf, 0, in, outbuf, 0);
 200:         else
 201:           out = engineDoFinal (inbuf, 0, in, outbuf, 0);
 202:         output.put (outbuf, 0, out);
 203:         total += out;
 204:       }
 205:     return total;
 206:   }
 207: 
 208:   /**
 209:    * Returns the block size of the underlying cipher.
 210:    *
 211:    * @return The block size.
 212:    */
 213:   protected abstract int engineGetBlockSize();
 214: 
 215:   /**
 216:    * Returns the initializaiton vector this cipher was initialized with,
 217:    * if any.
 218:    *
 219:    * @return The IV, or null if this cipher uses no IV or if this
 220:    *         instance has not been initialized yet.
 221:    */
 222:   protected abstract byte[] engineGetIV();
 223: 
 224:   /**
 225:    * <p>Return the length of the given key in bits.</p>
 226:    *
 227:    * <p>For compatibility this method is not declared
 228:    * <code>abstract</code>, and the default implementation will throw an
 229:    * {@link java.lang.UnsupportedOperationException}. Concrete
 230:    * subclasses should override this method to return the correct
 231:    * value.</p>
 232:    *
 233:    * @param key The key to get the size for.
 234:    * @return The size of the key, in bits.
 235:    * @throws java.security.InvalidKeyException If the key's length
 236:    *         cannot be determined by this implementation.
 237:    */
 238:   protected int engineGetKeySize(Key key) throws InvalidKeyException
 239:   {
 240:     throw new UnsupportedOperationException();
 241:   }
 242: 
 243:   /**
 244:    * <p>Returns the size, in bytes, an output buffer must be for a call
 245:    * to {@link #engineUpdate(byte[],int,int,byte[],int)} or {@link
 246:    * #engineDoFinal(byte[],int,int,byte[],int)} to succeed.</p>
 247:    *
 248:    * <p>The actual output length may be smaller than the value returned
 249:    * by this method, as it considers the padding length as well. The
 250:    * length considered is the argument plus the length of any buffered,
 251:    * unprocessed bytes.</p>
 252:    *
 253:    * @param inputLength The input length, in bytes.
 254:    * @return The size an output buffer must be.
 255:    */
 256:   protected abstract int engineGetOutputSize(int inputLength);
 257: 
 258:   /**
 259:    * Returns the parameters that this cipher is using. This may be the
 260:    * parameters used to initialize this cipher, or it may be parameters
 261:    * that have been initialized with random values.
 262:    *
 263:    * @return This cipher's parameters, or <code>null</code> if this
 264:    *         cipher does not use parameters.
 265:    */
 266:   protected abstract AlgorithmParameters engineGetParameters();
 267: 
 268:   /**
 269:    * Initializes this cipher with an operation mode, key, and source of
 270:    * randomness. If this cipher requires any other initializing data,
 271:    * for example an initialization vector, then it should generate it
 272:    * from the provided source of randomness.
 273:    *
 274:    * @param opmode The operation mode, one of {@link
 275:    *        Cipher#DECRYPT_MODE}, {@link Cipher#ENCRYPT_MODE}, {@link
 276:    *        Cipher#UNWRAP_MODE}, or {@link Cipher#WRAP_MODE}.
 277:    * @param key    The key to initialize this cipher with.
 278:    * @param random The source of random bytes to use.
 279:    * @throws java.security.InvalidKeyException If the given key is not
 280:    *         acceptable for this implementation.
 281:    */
 282:   protected abstract void engineInit(int opmode, Key key, SecureRandom random)
 283:   throws InvalidKeyException;
 284: 
 285:   /**
 286:    * Initializes this cipher with an operation mode, key, parameters,
 287:    * and source of randomness. If this cipher requires any other
 288:    * initializing data, for example an initialization vector, then it should
 289:    * generate it from the provided source of randomness.
 290:    *
 291:    * @param opmode The operation mode, one of {@link
 292:    *        Cipher#DECRYPT_MODE}, {@link Cipher#ENCRYPT_MODE}, {@link
 293:    *        Cipher#UNWRAP_MODE}, or {@link Cipher#WRAP_MODE}.
 294:    * @param key    The key to initialize this cipher with.
 295:    * @param params The algorithm parameters to initialize with.
 296:    * @param random The source of random bytes to use.
 297:    * @throws java.security.InvalidAlgorithmParameterException If the
 298:    *         given parameters are not appropriate for this
 299:    *         implementation.
 300:    * @throws java.security.InvalidKeyException If the given key is not
 301:    *         acceptable for this implementation.
 302:    */
 303:   protected abstract void
 304:   engineInit(int opmode, Key key, AlgorithmParameters params,
 305:              SecureRandom random)
 306:   throws InvalidAlgorithmParameterException, InvalidKeyException;
 307: 
 308:   /**
 309:    * Initializes this cipher with an operation mode, key, parameters,
 310:    * and source of randomness. If this cipher requires any other
 311:    * initializing data, for example an initialization vector, then it should
 312:    * generate it from the provided source of randomness.
 313:    *
 314:    * @param opmode The operation mode, one of {@link
 315:    *        Cipher#DECRYPT_MODE}, {@link Cipher#ENCRYPT_MODE}, {@link
 316:    *        Cipher#UNWRAP_MODE}, or {@link Cipher#WRAP_MODE}.
 317:    * @param key    The key to initialize this cipher with.
 318:    * @param params The algorithm parameters to initialize with.
 319:    * @param random The source of random bytes to use.
 320:    * @throws java.security.InvalidAlgorithmParameterException If the
 321:    *         given parameters are not appropriate for this
 322:    *         implementation.
 323:    * @throws java.security.InvalidKeyException If the given key is not
 324:    *         acceptable for this implementation.
 325:    */
 326:   protected abstract void
 327:   engineInit(int opmode, Key key, AlgorithmParameterSpec params,
 328:              SecureRandom random)
 329:   throws InvalidAlgorithmParameterException, InvalidKeyException;
 330: 
 331:   /**
 332:    * Set the mode in which this cipher is to run.
 333:    *
 334:    * @param mode The name of the mode to use.
 335:    * @throws java.security.NoSuchAlgorithmException If the mode is
 336:    *         not supported by this cipher's provider.
 337:    */
 338:   protected abstract void engineSetMode(String mode)
 339:   throws NoSuchAlgorithmException;
 340: 
 341:   /**
 342:    * Set the method with which the input is to be padded.
 343:    *
 344:    * @param padding The name of the padding to use.
 345:    * @throws javax.crypto.NoSuchPaddingException If the padding is not
 346:    *         supported by this cipher's provider.
 347:    */
 348:   protected abstract void engineSetPadding(String padding)
 349:   throws NoSuchPaddingException;
 350: 
 351:   /**
 352:    * <p>Unwraps a previously-wrapped key.</p>
 353:    *
 354:    * <p>For compatibility this method is not declared
 355:    * <code>abstract</code>, and the default implementation will throw an
 356:    * {@link java.lang.UnsupportedOperationException}.</p>
 357:    *
 358:    * @param wrappedKey          The wrapped key.
 359:    * @param wrappedKeyAlgorithm The name of the algorithm used to wrap
 360:    *                            this key.
 361:    * @param wrappedKeyType      The type of wrapped key; one of
 362:    *                            {@link Cipher#PRIVATE_KEY},
 363:    *                            {@link Cipher#PUBLIC_KEY}, or
 364:    *                            {@link Cipher#SECRET_KEY}.
 365:    * @return The unwrapped key.
 366:    * @throws java.security.InvalidKeyException If the key cannot be
 367:    *         unwrapped, or if <code>wrappedKeyType</code> is an
 368:    *         inappropriate type for the unwrapped key.
 369:    * @throws java.security.NoSuchAlgorithmException If the
 370:    *         <code>wrappedKeyAlgorithm</code> is unknown.
 371:    */
 372:   protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
 373:                              int wrappedKeyType)
 374:   throws InvalidKeyException, NoSuchAlgorithmException
 375:   {
 376:     throw new UnsupportedOperationException();
 377:   }
 378: 
 379:   /**
 380:    * Continue with a multi-part transformation, returning a new array of
 381:    * the transformed bytes.
 382:    *
 383:    * @param input       The next input bytes.
 384:    * @param inputOffset The index in the input array from which to start.
 385:    * @param inputLength The number of bytes to input.
 386:    * @return The transformed bytes.
 387:    */
 388:   protected abstract byte[]
 389:   engineUpdate(byte[] input, int inputOffset, int inputLength);
 390: 
 391:   /**
 392:    * Continue with a multi-part transformation, storing the transformed
 393:    * bytes into the specified array.
 394:    *
 395:    * @param input        The next input bytes.
 396:    * @param inputOffset  The index in the input from which to start.
 397:    * @param inputLength  The number of bytes to input.
 398:    * @param output       The output buffer.
 399:    * @param outputOffset The index in the output array from which to start.
 400:    * @return The transformed bytes.
 401:    * @throws javax.crypto.ShortBufferException If there is not enough
 402:    *         space in the output array to store the transformed bytes.
 403:    */
 404:   protected abstract int
 405:   engineUpdate(byte[] input, int inputOffset, int inputLength,
 406:                byte[] output, int outputOffset)
 407:   throws ShortBufferException;
 408: 
 409:   /**
 410:    * @since 1.5
 411:    */
 412:   protected int engineUpdate (ByteBuffer input, ByteBuffer output)
 413:     throws ShortBufferException
 414:   {
 415:     int total = 0;
 416:     byte[] inbuf = new byte[256];
 417:     while (input.hasRemaining ())
 418:       {
 419:         int in = Math.min (inbuf.length, input.remaining ());
 420:         input.get (inbuf, 0, in);
 421:         byte[] outbuf = new byte[engineGetOutputSize (in)];
 422:         int out = engineUpdate (inbuf, 0, in, outbuf, 0);
 423:         output.put (outbuf, 0, out);
 424:         total += out;
 425:       }
 426:     return total;
 427:   }
 428: 
 429:   /**
 430:    * <p>Wrap a key.</p>
 431:    *
 432:    * <p>For compatibility this method is not declared
 433:    * <code>abstract</code>, and the default implementation will throw an
 434:    * {@link java.lang.UnsupportedOperationException}.</p>
 435:    *
 436:    * @param key The key to wrap.
 437:    * @return The wrapped key.
 438:    * @throws java.security.InvalidKeyException If the key cannot be
 439:    *         wrapped.
 440:    */
 441:   protected byte[] engineWrap(Key key) throws InvalidKeyException, IllegalBlockSizeException
 442:   {
 443:     throw new UnsupportedOperationException();
 444:   }
 445: }