Source for javax.crypto.Mac

   1: /* Mac.java -- The message authentication code interface.
   2:    Copyright (C) 2004  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 gnu.java.security.Engine;
  42: 
  43: import java.lang.reflect.InvocationTargetException;
  44: import java.security.InvalidAlgorithmParameterException;
  45: import java.security.InvalidKeyException;
  46: import java.security.Key;
  47: import java.security.NoSuchAlgorithmException;
  48: import java.security.NoSuchProviderException;
  49: import java.security.Provider;
  50: import java.security.Security;
  51: import java.security.spec.AlgorithmParameterSpec;
  52: 
  53: /**
  54:  * This class implements a "message authentication code" (MAC), a method
  55:  * to ensure the integrity of data transmitted between two parties who
  56:  * share a common secret key.
  57:  *
  58:  * <p>The best way to describe a MAC is as a <i>keyed one-way hash
  59:  * function</i>, which looks like:
  60:  *
  61:  * <blockquote><p><code>D = MAC(K, M)</code></blockquote>
  62:  *
  63:  * <p>where <code>K</code> is the key, <code>M</code> is the message,
  64:  * and <code>D</code> is the resulting digest. One party will usually
  65:  * send the concatenation <code>M || D</code> to the other party, who
  66:  * will then verify <code>D</code> by computing <code>D'</code> in a
  67:  * similar fashion. If <code>D == D'</code>, then the message is assumed
  68:  * to be authentic.
  69:  *
  70:  * @author Casey Marshall (csm@gnu.org)
  71:  */
  72: public class Mac implements Cloneable
  73: {
  74: 
  75:   // Fields.
  76:   // ------------------------------------------------------------------------
  77: 
  78:   private static final String SERVICE = "Mac";
  79: 
  80:   /** The underlying MAC implementation. */
  81:   private MacSpi macSpi;
  82: 
  83:   /** The provider we got our implementation from. */
  84:   private Provider provider;
  85: 
  86:   /** The name of the algorithm. */
  87:   private String algorithm;
  88: 
  89:   /** Whether or not we've been initialized. */
  90:   private boolean virgin;
  91: 
  92:   // Constructor.
  93:   // ------------------------------------------------------------------------
  94: 
  95:   /**
  96:    * Creates a new Mac instance.
  97:    *
  98:    * @param macSpi    The underlying MAC implementation.
  99:    * @param provider  The provider of this implementation.
 100:    * @param algorithm The name of this MAC algorithm.
 101:    */
 102:   protected Mac(MacSpi macSpi, Provider provider, String algorithm)
 103:   {
 104:     this.macSpi = macSpi;
 105:     this.provider = provider;
 106:     this.algorithm = algorithm;
 107:     virgin = true;
 108:   }
 109: 
 110:   // Class methods.
 111:   // ------------------------------------------------------------------------
 112: 
 113:   /**
 114:    * Get an instance of the named algorithm from the first provider with
 115:    * an appropriate implementation.
 116:    *
 117:    * @param algorithm The name of the algorithm.
 118:    * @return An appropriate Mac instance, if the specified algorithm
 119:    *         is implemented by a provider.
 120:    * @throws java.security.NoSuchAlgorithmException If no implementation
 121:    *         of the named algorithm is installed.
 122:    */
 123:   public static final Mac getInstance(String algorithm)
 124:     throws NoSuchAlgorithmException
 125:   {
 126:     Provider[] provs = Security.getProviders();
 127:     String msg = "";
 128:     for (int i = 0; i < provs.length; i++)
 129:       {
 130:         try
 131:           {
 132:             return getInstance(algorithm, provs[i]);
 133:           }
 134:         catch (NoSuchAlgorithmException nsae)
 135:           {
 136:             msg = nsae.getMessage();
 137:           }
 138:       }
 139:     throw new NoSuchAlgorithmException(msg);
 140:   }
 141: 
 142:   /**
 143:    * Get an instance of the named algorithm from the named provider.
 144:    *
 145:    * @param algorithm The name of the algorithm.
 146:    * @param provider  The name of the provider.
 147:    * @return An appropriate Mac instance, if the specified algorithm is
 148:    *         implemented by the named provider.
 149:    * @throws java.security.NoSuchAlgorithmException If the named provider
 150:    *         has no implementation of the algorithm.
 151:    * @throws java.security.NoSuchProviderException If the named provider
 152:    *         does not exist.
 153:    */
 154:   public static final Mac getInstance(String algorithm, String provider)
 155:     throws NoSuchAlgorithmException, NoSuchProviderException
 156:   {
 157:     Provider p = Security.getProvider(provider);
 158:     if (p == null)
 159:       {
 160:         throw new NoSuchProviderException(provider);
 161:       }
 162:     return getInstance(algorithm, p);
 163:   }
 164: 
 165:   /**
 166:    * Get an instance of the named algorithm from a provider.
 167:    *
 168:    * @param algorithm The name of the algorithm.
 169:    * @param provider  The provider.
 170:    * @return An appropriate Mac instance, if the specified algorithm is
 171:    *         implemented by the provider.
 172:    * @throws java.security.NoSuchAlgorithmException If the provider
 173:    *         has no implementation of the algorithm.
 174:    */
 175:   public static final Mac getInstance(String algorithm, Provider provider)
 176:     throws NoSuchAlgorithmException
 177:   {
 178:     try
 179:       {
 180:         return new Mac((MacSpi) Engine.getInstance(SERVICE, algorithm, provider),
 181:                        provider, algorithm);
 182:       }
 183:     catch (InvocationTargetException ite)
 184:       {
 185:         if (ite.getCause() == null)
 186:           throw new NoSuchAlgorithmException(algorithm);
 187:         if (ite.getCause() instanceof NoSuchAlgorithmException)
 188:           throw (NoSuchAlgorithmException) ite.getCause();
 189:         throw new NoSuchAlgorithmException(algorithm);
 190:       }
 191:     catch (ClassCastException cce)
 192:       {
 193:         throw new NoSuchAlgorithmException(algorithm);
 194:       }
 195:   }
 196: 
 197:   // Instance methods.
 198:   // ------------------------------------------------------------------------
 199: 
 200:   /**
 201:    * Finishes the computation of a MAC and returns the digest.
 202:    *
 203:    * <p>After this method succeeds, it may be used again as just after a
 204:    * call to <code>init</code>, and can compute another MAC using the
 205:    * same key and parameters.
 206:    *
 207:    * @return The message authentication code.
 208:    * @throws java.lang.IllegalStateException If this instnace has not
 209:    *         been initialized.
 210:    */
 211:   public final byte[] doFinal() throws IllegalStateException
 212:   {
 213:     if (virgin)
 214:       {
 215:         throw new IllegalStateException("not initialized");
 216:       }
 217:     byte[] digest = macSpi.engineDoFinal();
 218:     reset();
 219:     return digest;
 220:   }
 221: 
 222:   /**
 223:    * Finishes the computation of a MAC with a final byte array (or
 224:    * computes a MAC over those bytes only) and returns the digest.
 225:    *
 226:    * <p>After this method succeeds, it may be used again as just after a
 227:    * call to <code>init</code>, and can compute another MAC using the
 228:    * same key and parameters.
 229:    *
 230:    * @param input The bytes to add.
 231:    * @return The message authentication code.
 232:    * @throws java.lang.IllegalStateException If this instnace has not
 233:    *         been initialized.
 234:    */
 235:   public final byte[] doFinal(byte[] input) throws IllegalStateException
 236:   {
 237:     update(input);
 238:     byte[] digest = macSpi.engineDoFinal();
 239:     reset();
 240:     return digest;
 241:   }
 242: 
 243:   /**
 244:    * Finishes the computation of a MAC and places the result into the
 245:    * given array.
 246:    *
 247:    * <p>After this method succeeds, it may be used again as just after a
 248:    * call to <code>init</code>, and can compute another MAC using the
 249:    * same key and parameters.
 250:    *
 251:    * @param output    The destination for the result.
 252:    * @param outOffset The index in the output array to start.
 253:    * @return The message authentication code.
 254:    * @throws java.lang.IllegalStateException If this instnace has not
 255:    *         been initialized.
 256:    * @throws javax.crypto.ShortBufferException If <code>output</code> is
 257:    *         not large enough to hold the result.
 258:    */
 259:   public final void doFinal(byte[] output, int outOffset)
 260:   throws IllegalStateException, ShortBufferException
 261:   {
 262:     if (virgin)
 263:       {
 264:         throw new IllegalStateException("not initialized");
 265:       }
 266:     if (output.length - outOffset < getMacLength())
 267:       {
 268:         throw new ShortBufferException();
 269:       }
 270:     byte[] mac = macSpi.engineDoFinal();
 271:     System.arraycopy(mac, 0, output, outOffset, getMacLength());
 272:     reset();
 273:   }
 274: 
 275:   /**
 276:    * Returns the name of this MAC algorithm.
 277:    *
 278:    * @return The MAC name.
 279:    */
 280:   public final String getAlgorithm()
 281:   {
 282:     return algorithm;
 283:   }
 284: 
 285:   /**
 286:    * Get the size of the MAC. This is the size of the array returned by
 287:    * {@link #doFinal()} and {@link #doFinal(byte[])}, and the minimum
 288:    * number of bytes that must be available in the byte array passed to
 289:    * {@link #doFinal(byte[],int)}.
 290:    *
 291:    * @return The MAC length.
 292:    */
 293:   public final int getMacLength()
 294:   {
 295:     return macSpi.engineGetMacLength();
 296:   }
 297: 
 298:   /**
 299:    * Get the provider of the underlying implementation.
 300:    *
 301:    * @return The provider.
 302:    */
 303:   public final Provider getProvider()
 304:   {
 305:     return provider;
 306:   }
 307: 
 308:   /**
 309:    * Initialize this MAC with a key and no parameters.
 310:    *
 311:    * @param key The key to initialize this instance with.
 312:    * @throws java.security.InvalidKeyException If the key is
 313:    *         unacceptable.
 314:    */
 315:   public final void init(Key key) throws InvalidKeyException
 316:   {
 317:     try
 318:       {
 319:         init(key, null);
 320:       }
 321:     catch (InvalidAlgorithmParameterException iape)
 322:       {
 323:         throw new IllegalArgumentException(algorithm + " needs parameters");
 324:       }
 325:   }
 326: 
 327:   /**
 328:    * Initialize this MAC with a key and parameters.
 329:    *
 330:    * @param key    The key to initialize this instance with.
 331:    * @param params The algorithm-specific parameters.
 332:    * @throws java.security.InvalidAlgorithmParameterException If the
 333:    *         algorithm parameters are unacceptable.
 334:    * @throws java.security.InvalidKeyException If the key is
 335:    *         unacceptable.
 336:    */
 337:   public final void init(Key key, AlgorithmParameterSpec params)
 338:     throws InvalidAlgorithmParameterException, InvalidKeyException
 339:   {
 340:     macSpi.engineInit(key, params);
 341:     virgin = false;                      // w00t!
 342:   }
 343: 
 344:   /**
 345:    * Reset this instance. A call to this method returns this instance
 346:    * back to the state it was in just after it was initialized.
 347:    */
 348:   public final void reset()
 349:   {
 350:     macSpi.engineReset();
 351:   }
 352: 
 353:   /**
 354:    * Update the computation with a single byte.
 355:    *
 356:    * @param input The next byte.
 357:    * @throws java.lang.IllegalStateException If this instance has not
 358:    *         been initialized.
 359:    */
 360:   public final void update(byte input) throws IllegalStateException
 361:   {
 362:     if (virgin)
 363:       {
 364:         throw new IllegalStateException("not initialized");
 365:       }
 366:     macSpi.engineUpdate(input);
 367:   }
 368: 
 369:   /**
 370:    * Update the computation with a byte array.
 371:    *
 372:    * @param input The next bytes.
 373:    * @throws java.lang.IllegalStateException If this instance has not
 374:    *         been initialized.
 375:    */
 376:   public final void update(byte[] input) throws IllegalStateException
 377:   {
 378:     update(input, 0, input.length);
 379:   }
 380: 
 381:   /**
 382:    * Update the computation with a portion of a byte array.
 383:    *
 384:    * @param input  The next bytes.
 385:    * @param offset The index in <code>input</code> to start.
 386:    * @param length The number of bytes to update.
 387:    * @throws java.lang.IllegalStateException If this instance has not
 388:    *         been initialized.
 389:    */
 390:   public final void update(byte[] input, int offset, int length)
 391:     throws IllegalStateException
 392:   {
 393:     if (virgin)
 394:       {
 395:         throw new IllegalStateException("not initialized");
 396:       }
 397:     macSpi.engineUpdate(input, offset, length);
 398:   }
 399: 
 400:   /**
 401:    * Clone this instance, if the underlying implementation supports it.
 402:    *
 403:    * @return A clone of this instance.
 404:    * @throws java.lang.CloneNotSupportedException If the underlying
 405:    *         implementation is not cloneable.
 406:    */
 407:   public final Object clone() throws CloneNotSupportedException
 408:   {
 409:     Mac result = new Mac((MacSpi) macSpi.clone(), provider, algorithm);
 410:     result.virgin = virgin;
 411:     return result;
 412:   }
 413: }