jdk/src/java.base/share/classes/javax/crypto/Mac.java
changeset 25859 3317bb8137f4
parent 10336 0bb1999251f8
child 26736 5a93000b26cd
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 1998, 2011, 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 javax.crypto;
       
    27 
       
    28 import java.util.*;
       
    29 
       
    30 import java.security.*;
       
    31 import java.security.Provider.Service;
       
    32 import java.security.spec.AlgorithmParameterSpec;
       
    33 
       
    34 import java.nio.ByteBuffer;
       
    35 
       
    36 import sun.security.util.Debug;
       
    37 import sun.security.jca.*;
       
    38 import sun.security.jca.GetInstance.Instance;
       
    39 
       
    40 /**
       
    41  * This class provides the functionality of a "Message Authentication Code"
       
    42  * (MAC) algorithm.
       
    43  *
       
    44  * <p> A MAC provides a way to check
       
    45  * the integrity of information transmitted over or stored in an unreliable
       
    46  * medium, based on a secret key. Typically, message
       
    47  * authentication codes are used between two parties that share a secret
       
    48  * key in order to validate information transmitted between these
       
    49  * parties.
       
    50  *
       
    51  * <p> A MAC mechanism that is based on cryptographic hash functions is
       
    52  * referred to as HMAC. HMAC can be used with any cryptographic hash function,
       
    53  * e.g., MD5 or SHA-1, in combination with a secret shared key. HMAC is
       
    54  * specified in RFC 2104.
       
    55  *
       
    56  * <p> Every implementation of the Java platform is required to support
       
    57  * the following standard <code>Mac</code> algorithms:
       
    58  * <ul>
       
    59  * <li><tt>HmacMD5</tt></li>
       
    60  * <li><tt>HmacSHA1</tt></li>
       
    61  * <li><tt>HmacSHA256</tt></li>
       
    62  * </ul>
       
    63  * These algorithms are described in the
       
    64  * <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
       
    65  * Mac section</a> of the
       
    66  * Java Cryptography Architecture Standard Algorithm Name Documentation.
       
    67  * Consult the release documentation for your implementation to see if any
       
    68  * other algorithms are supported.
       
    69  *
       
    70  * @author Jan Luehe
       
    71  *
       
    72  * @since 1.4
       
    73  */
       
    74 
       
    75 public class Mac implements Cloneable {
       
    76 
       
    77     private static final Debug debug =
       
    78                         Debug.getInstance("jca", "Mac");
       
    79 
       
    80     // The provider
       
    81     private Provider provider;
       
    82 
       
    83     // The provider implementation (delegate)
       
    84     private MacSpi spi;
       
    85 
       
    86     // The name of the MAC algorithm.
       
    87     private final String algorithm;
       
    88 
       
    89     // Has this object been initialized?
       
    90     private boolean initialized = false;
       
    91 
       
    92     // next service to try in provider selection
       
    93     // null once provider is selected
       
    94     private Service firstService;
       
    95 
       
    96     // remaining services to try in provider selection
       
    97     // null once provider is selected
       
    98     private Iterator<Service> serviceIterator;
       
    99 
       
   100     private final Object lock;
       
   101 
       
   102     /**
       
   103      * Creates a MAC object.
       
   104      *
       
   105      * @param macSpi the delegate
       
   106      * @param provider the provider
       
   107      * @param algorithm the algorithm
       
   108      */
       
   109     protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
       
   110         this.spi = macSpi;
       
   111         this.provider = provider;
       
   112         this.algorithm = algorithm;
       
   113         serviceIterator = null;
       
   114         lock = null;
       
   115     }
       
   116 
       
   117     private Mac(Service s, Iterator<Service> t, String algorithm) {
       
   118         firstService = s;
       
   119         serviceIterator = t;
       
   120         this.algorithm = algorithm;
       
   121         lock = new Object();
       
   122     }
       
   123 
       
   124     /**
       
   125      * Returns the algorithm name of this <code>Mac</code> object.
       
   126      *
       
   127      * <p>This is the same name that was specified in one of the
       
   128      * <code>getInstance</code> calls that created this
       
   129      * <code>Mac</code> object.
       
   130      *
       
   131      * @return the algorithm name of this <code>Mac</code> object.
       
   132      */
       
   133     public final String getAlgorithm() {
       
   134         return this.algorithm;
       
   135     }
       
   136 
       
   137     /**
       
   138      * Returns a <code>Mac</code> object that implements the
       
   139      * specified MAC algorithm.
       
   140      *
       
   141      * <p> This method traverses the list of registered security Providers,
       
   142      * starting with the most preferred Provider.
       
   143      * A new Mac object encapsulating the
       
   144      * MacSpi implementation from the first
       
   145      * Provider that supports the specified algorithm is returned.
       
   146      *
       
   147      * <p> Note that the list of registered providers may be retrieved via
       
   148      * the {@link Security#getProviders() Security.getProviders()} method.
       
   149      *
       
   150      * @param algorithm the standard name of the requested MAC algorithm.
       
   151      * See the Mac section in the <a href=
       
   152      *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
       
   153      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
       
   154      * for information about standard algorithm names.
       
   155      *
       
   156      * @return the new <code>Mac</code> object.
       
   157      *
       
   158      * @exception NoSuchAlgorithmException if no Provider supports a
       
   159      *          MacSpi implementation for the
       
   160      *          specified algorithm.
       
   161      *
       
   162      * @see java.security.Provider
       
   163      */
       
   164     public static final Mac getInstance(String algorithm)
       
   165             throws NoSuchAlgorithmException {
       
   166         List<Service> services = GetInstance.getServices("Mac", algorithm);
       
   167         // make sure there is at least one service from a signed provider
       
   168         Iterator<Service> t = services.iterator();
       
   169         while (t.hasNext()) {
       
   170             Service s = t.next();
       
   171             if (JceSecurity.canUseProvider(s.getProvider()) == false) {
       
   172                 continue;
       
   173             }
       
   174             return new Mac(s, t, algorithm);
       
   175         }
       
   176         throw new NoSuchAlgorithmException
       
   177                                 ("Algorithm " + algorithm + " not available");
       
   178     }
       
   179 
       
   180     /**
       
   181      * Returns a <code>Mac</code> object that implements the
       
   182      * specified MAC algorithm.
       
   183      *
       
   184      * <p> A new Mac object encapsulating the
       
   185      * MacSpi implementation from the specified provider
       
   186      * is returned.  The specified provider must be registered
       
   187      * in the security provider list.
       
   188      *
       
   189      * <p> Note that the list of registered providers may be retrieved via
       
   190      * the {@link Security#getProviders() Security.getProviders()} method.
       
   191      *
       
   192      * @param algorithm the standard name of the requested MAC algorithm.
       
   193      * See the Mac section in the <a href=
       
   194      *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
       
   195      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
       
   196      * for information about standard algorithm names.
       
   197      *
       
   198      * @param provider the name of the provider.
       
   199      *
       
   200      * @return the new <code>Mac</code> object.
       
   201      *
       
   202      * @exception NoSuchAlgorithmException if a MacSpi
       
   203      *          implementation for the specified algorithm is not
       
   204      *          available from the specified provider.
       
   205      *
       
   206      * @exception NoSuchProviderException if the specified provider is not
       
   207      *          registered in the security provider list.
       
   208      *
       
   209      * @exception IllegalArgumentException if the <code>provider</code>
       
   210      *          is null or empty.
       
   211      *
       
   212      * @see java.security.Provider
       
   213      */
       
   214     public static final Mac getInstance(String algorithm, String provider)
       
   215             throws NoSuchAlgorithmException, NoSuchProviderException {
       
   216         Instance instance = JceSecurity.getInstance
       
   217                 ("Mac", MacSpi.class, algorithm, provider);
       
   218         return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
       
   219     }
       
   220 
       
   221     /**
       
   222      * Returns a <code>Mac</code> object that implements the
       
   223      * specified MAC algorithm.
       
   224      *
       
   225      * <p> A new Mac object encapsulating the
       
   226      * MacSpi implementation from the specified Provider
       
   227      * object is returned.  Note that the specified Provider object
       
   228      * does not have to be registered in the provider list.
       
   229      *
       
   230      * @param algorithm the standard name of the requested MAC algorithm.
       
   231      * See the Mac section in the <a href=
       
   232      *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
       
   233      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
       
   234      * for information about standard algorithm names.
       
   235      *
       
   236      * @param provider the provider.
       
   237      *
       
   238      * @return the new <code>Mac</code> object.
       
   239      *
       
   240      * @exception NoSuchAlgorithmException if a MacSpi
       
   241      *          implementation for the specified algorithm is not available
       
   242      *          from the specified Provider object.
       
   243      *
       
   244      * @exception IllegalArgumentException if the <code>provider</code>
       
   245      *          is null.
       
   246      *
       
   247      * @see java.security.Provider
       
   248      */
       
   249     public static final Mac getInstance(String algorithm, Provider provider)
       
   250             throws NoSuchAlgorithmException {
       
   251         Instance instance = JceSecurity.getInstance
       
   252                 ("Mac", MacSpi.class, algorithm, provider);
       
   253         return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
       
   254     }
       
   255 
       
   256     // max number of debug warnings to print from chooseFirstProvider()
       
   257     private static int warnCount = 10;
       
   258 
       
   259     /**
       
   260      * Choose the Spi from the first provider available. Used if
       
   261      * delayed provider selection is not possible because init()
       
   262      * is not the first method called.
       
   263      */
       
   264     void chooseFirstProvider() {
       
   265         if ((spi != null) || (serviceIterator == null)) {
       
   266             return;
       
   267         }
       
   268         synchronized (lock) {
       
   269             if (spi != null) {
       
   270                 return;
       
   271             }
       
   272             if (debug != null) {
       
   273                 int w = --warnCount;
       
   274                 if (w >= 0) {
       
   275                     debug.println("Mac.init() not first method "
       
   276                         + "called, disabling delayed provider selection");
       
   277                     if (w == 0) {
       
   278                         debug.println("Further warnings of this type will "
       
   279                             + "be suppressed");
       
   280                     }
       
   281                     new Exception("Call trace").printStackTrace();
       
   282                 }
       
   283             }
       
   284             Exception lastException = null;
       
   285             while ((firstService != null) || serviceIterator.hasNext()) {
       
   286                 Service s;
       
   287                 if (firstService != null) {
       
   288                     s = firstService;
       
   289                     firstService = null;
       
   290                 } else {
       
   291                     s = serviceIterator.next();
       
   292                 }
       
   293                 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
       
   294                     continue;
       
   295                 }
       
   296                 try {
       
   297                     Object obj = s.newInstance(null);
       
   298                     if (obj instanceof MacSpi == false) {
       
   299                         continue;
       
   300                     }
       
   301                     spi = (MacSpi)obj;
       
   302                     provider = s.getProvider();
       
   303                     // not needed any more
       
   304                     firstService = null;
       
   305                     serviceIterator = null;
       
   306                     return;
       
   307                 } catch (NoSuchAlgorithmException e) {
       
   308                     lastException = e;
       
   309                 }
       
   310             }
       
   311             ProviderException e = new ProviderException
       
   312                     ("Could not construct MacSpi instance");
       
   313             if (lastException != null) {
       
   314                 e.initCause(lastException);
       
   315             }
       
   316             throw e;
       
   317         }
       
   318     }
       
   319 
       
   320     private void chooseProvider(Key key, AlgorithmParameterSpec params)
       
   321             throws InvalidKeyException, InvalidAlgorithmParameterException {
       
   322         synchronized (lock) {
       
   323             if (spi != null) {
       
   324                 spi.engineInit(key, params);
       
   325                 return;
       
   326             }
       
   327             Exception lastException = null;
       
   328             while ((firstService != null) || serviceIterator.hasNext()) {
       
   329                 Service s;
       
   330                 if (firstService != null) {
       
   331                     s = firstService;
       
   332                     firstService = null;
       
   333                 } else {
       
   334                     s = serviceIterator.next();
       
   335                 }
       
   336                 // if provider says it does not support this key, ignore it
       
   337                 if (s.supportsParameter(key) == false) {
       
   338                     continue;
       
   339                 }
       
   340                 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
       
   341                     continue;
       
   342                 }
       
   343                 try {
       
   344                     MacSpi spi = (MacSpi)s.newInstance(null);
       
   345                     spi.engineInit(key, params);
       
   346                     provider = s.getProvider();
       
   347                     this.spi = spi;
       
   348                     firstService = null;
       
   349                     serviceIterator = null;
       
   350                     return;
       
   351                 } catch (Exception e) {
       
   352                     // NoSuchAlgorithmException from newInstance()
       
   353                     // InvalidKeyException from init()
       
   354                     // RuntimeException (ProviderException) from init()
       
   355                     if (lastException == null) {
       
   356                         lastException = e;
       
   357                     }
       
   358                 }
       
   359             }
       
   360             // no working provider found, fail
       
   361             if (lastException instanceof InvalidKeyException) {
       
   362                 throw (InvalidKeyException)lastException;
       
   363             }
       
   364             if (lastException instanceof InvalidAlgorithmParameterException) {
       
   365                 throw (InvalidAlgorithmParameterException)lastException;
       
   366             }
       
   367             if (lastException instanceof RuntimeException) {
       
   368                 throw (RuntimeException)lastException;
       
   369             }
       
   370             String kName = (key != null) ? key.getClass().getName() : "(null)";
       
   371             throw new InvalidKeyException
       
   372                 ("No installed provider supports this key: "
       
   373                 + kName, lastException);
       
   374         }
       
   375     }
       
   376 
       
   377     /**
       
   378      * Returns the provider of this <code>Mac</code> object.
       
   379      *
       
   380      * @return the provider of this <code>Mac</code> object.
       
   381      */
       
   382     public final Provider getProvider() {
       
   383         chooseFirstProvider();
       
   384         return this.provider;
       
   385     }
       
   386 
       
   387     /**
       
   388      * Returns the length of the MAC in bytes.
       
   389      *
       
   390      * @return the MAC length in bytes.
       
   391      */
       
   392     public final int getMacLength() {
       
   393         chooseFirstProvider();
       
   394         return spi.engineGetMacLength();
       
   395     }
       
   396 
       
   397     /**
       
   398      * Initializes this <code>Mac</code> object with the given key.
       
   399      *
       
   400      * @param key the key.
       
   401      *
       
   402      * @exception InvalidKeyException if the given key is inappropriate for
       
   403      * initializing this MAC.
       
   404      */
       
   405     public final void init(Key key) throws InvalidKeyException {
       
   406         try {
       
   407             if (spi != null) {
       
   408                 spi.engineInit(key, null);
       
   409             } else {
       
   410                 chooseProvider(key, null);
       
   411             }
       
   412         } catch (InvalidAlgorithmParameterException e) {
       
   413             throw new InvalidKeyException("init() failed", e);
       
   414         }
       
   415         initialized = true;
       
   416     }
       
   417 
       
   418     /**
       
   419      * Initializes this <code>Mac</code> object with the given key and
       
   420      * algorithm parameters.
       
   421      *
       
   422      * @param key the key.
       
   423      * @param params the algorithm parameters.
       
   424      *
       
   425      * @exception InvalidKeyException if the given key is inappropriate for
       
   426      * initializing this MAC.
       
   427      * @exception InvalidAlgorithmParameterException if the given algorithm
       
   428      * parameters are inappropriate for this MAC.
       
   429      */
       
   430     public final void init(Key key, AlgorithmParameterSpec params)
       
   431             throws InvalidKeyException, InvalidAlgorithmParameterException {
       
   432         if (spi != null) {
       
   433             spi.engineInit(key, params);
       
   434         } else {
       
   435             chooseProvider(key, params);
       
   436         }
       
   437         initialized = true;
       
   438     }
       
   439 
       
   440     /**
       
   441      * Processes the given byte.
       
   442      *
       
   443      * @param input the input byte to be processed.
       
   444      *
       
   445      * @exception IllegalStateException if this <code>Mac</code> has not been
       
   446      * initialized.
       
   447      */
       
   448     public final void update(byte input) throws IllegalStateException {
       
   449         chooseFirstProvider();
       
   450         if (initialized == false) {
       
   451             throw new IllegalStateException("MAC not initialized");
       
   452         }
       
   453         spi.engineUpdate(input);
       
   454     }
       
   455 
       
   456     /**
       
   457      * Processes the given array of bytes.
       
   458      *
       
   459      * @param input the array of bytes to be processed.
       
   460      *
       
   461      * @exception IllegalStateException if this <code>Mac</code> has not been
       
   462      * initialized.
       
   463      */
       
   464     public final void update(byte[] input) throws IllegalStateException {
       
   465         chooseFirstProvider();
       
   466         if (initialized == false) {
       
   467             throw new IllegalStateException("MAC not initialized");
       
   468         }
       
   469         if (input != null) {
       
   470             spi.engineUpdate(input, 0, input.length);
       
   471         }
       
   472     }
       
   473 
       
   474     /**
       
   475      * Processes the first <code>len</code> bytes in <code>input</code>,
       
   476      * starting at <code>offset</code> inclusive.
       
   477      *
       
   478      * @param input the input buffer.
       
   479      * @param offset the offset in <code>input</code> where the input starts.
       
   480      * @param len the number of bytes to process.
       
   481      *
       
   482      * @exception IllegalStateException if this <code>Mac</code> has not been
       
   483      * initialized.
       
   484      */
       
   485     public final void update(byte[] input, int offset, int len)
       
   486             throws IllegalStateException {
       
   487         chooseFirstProvider();
       
   488         if (initialized == false) {
       
   489             throw new IllegalStateException("MAC not initialized");
       
   490         }
       
   491 
       
   492         if (input != null) {
       
   493             if ((offset < 0) || (len > (input.length - offset)) || (len < 0))
       
   494                 throw new IllegalArgumentException("Bad arguments");
       
   495             spi.engineUpdate(input, offset, len);
       
   496         }
       
   497     }
       
   498 
       
   499     /**
       
   500      * Processes <code>input.remaining()</code> bytes in the ByteBuffer
       
   501      * <code>input</code>, starting at <code>input.position()</code>.
       
   502      * Upon return, the buffer's position will be equal to its limit;
       
   503      * its limit will not have changed.
       
   504      *
       
   505      * @param input the ByteBuffer
       
   506      *
       
   507      * @exception IllegalStateException if this <code>Mac</code> has not been
       
   508      * initialized.
       
   509      * @since 1.5
       
   510      */
       
   511     public final void update(ByteBuffer input) {
       
   512         chooseFirstProvider();
       
   513         if (initialized == false) {
       
   514             throw new IllegalStateException("MAC not initialized");
       
   515         }
       
   516         if (input == null) {
       
   517             throw new IllegalArgumentException("Buffer must not be null");
       
   518         }
       
   519         spi.engineUpdate(input);
       
   520     }
       
   521 
       
   522     /**
       
   523      * Finishes the MAC operation.
       
   524      *
       
   525      * <p>A call to this method resets this <code>Mac</code> object to the
       
   526      * state it was in when previously initialized via a call to
       
   527      * <code>init(Key)</code> or
       
   528      * <code>init(Key, AlgorithmParameterSpec)</code>.
       
   529      * That is, the object is reset and available to generate another MAC from
       
   530      * the same key, if desired, via new calls to <code>update</code> and
       
   531      * <code>doFinal</code>.
       
   532      * (In order to reuse this <code>Mac</code> object with a different key,
       
   533      * it must be reinitialized via a call to <code>init(Key)</code> or
       
   534      * <code>init(Key, AlgorithmParameterSpec)</code>.
       
   535      *
       
   536      * @return the MAC result.
       
   537      *
       
   538      * @exception IllegalStateException if this <code>Mac</code> has not been
       
   539      * initialized.
       
   540      */
       
   541     public final byte[] doFinal() throws IllegalStateException {
       
   542         chooseFirstProvider();
       
   543         if (initialized == false) {
       
   544             throw new IllegalStateException("MAC not initialized");
       
   545         }
       
   546         byte[] mac = spi.engineDoFinal();
       
   547         spi.engineReset();
       
   548         return mac;
       
   549     }
       
   550 
       
   551     /**
       
   552      * Finishes the MAC operation.
       
   553      *
       
   554      * <p>A call to this method resets this <code>Mac</code> object to the
       
   555      * state it was in when previously initialized via a call to
       
   556      * <code>init(Key)</code> or
       
   557      * <code>init(Key, AlgorithmParameterSpec)</code>.
       
   558      * That is, the object is reset and available to generate another MAC from
       
   559      * the same key, if desired, via new calls to <code>update</code> and
       
   560      * <code>doFinal</code>.
       
   561      * (In order to reuse this <code>Mac</code> object with a different key,
       
   562      * it must be reinitialized via a call to <code>init(Key)</code> or
       
   563      * <code>init(Key, AlgorithmParameterSpec)</code>.
       
   564      *
       
   565      * <p>The MAC result is stored in <code>output</code>, starting at
       
   566      * <code>outOffset</code> inclusive.
       
   567      *
       
   568      * @param output the buffer where the MAC result is stored
       
   569      * @param outOffset the offset in <code>output</code> where the MAC is
       
   570      * stored
       
   571      *
       
   572      * @exception ShortBufferException if the given output buffer is too small
       
   573      * to hold the result
       
   574      * @exception IllegalStateException if this <code>Mac</code> has not been
       
   575      * initialized.
       
   576      */
       
   577     public final void doFinal(byte[] output, int outOffset)
       
   578         throws ShortBufferException, IllegalStateException
       
   579     {
       
   580         chooseFirstProvider();
       
   581         if (initialized == false) {
       
   582             throw new IllegalStateException("MAC not initialized");
       
   583         }
       
   584         int macLen = getMacLength();
       
   585         if (output == null || output.length-outOffset < macLen) {
       
   586             throw new ShortBufferException
       
   587                 ("Cannot store MAC in output buffer");
       
   588         }
       
   589         byte[] mac = doFinal();
       
   590         System.arraycopy(mac, 0, output, outOffset, macLen);
       
   591         return;
       
   592     }
       
   593 
       
   594     /**
       
   595      * Processes the given array of bytes and finishes the MAC operation.
       
   596      *
       
   597      * <p>A call to this method resets this <code>Mac</code> object to the
       
   598      * state it was in when previously initialized via a call to
       
   599      * <code>init(Key)</code> or
       
   600      * <code>init(Key, AlgorithmParameterSpec)</code>.
       
   601      * That is, the object is reset and available to generate another MAC from
       
   602      * the same key, if desired, via new calls to <code>update</code> and
       
   603      * <code>doFinal</code>.
       
   604      * (In order to reuse this <code>Mac</code> object with a different key,
       
   605      * it must be reinitialized via a call to <code>init(Key)</code> or
       
   606      * <code>init(Key, AlgorithmParameterSpec)</code>.
       
   607      *
       
   608      * @param input data in bytes
       
   609      * @return the MAC result.
       
   610      *
       
   611      * @exception IllegalStateException if this <code>Mac</code> has not been
       
   612      * initialized.
       
   613      */
       
   614     public final byte[] doFinal(byte[] input) throws IllegalStateException
       
   615     {
       
   616         chooseFirstProvider();
       
   617         if (initialized == false) {
       
   618             throw new IllegalStateException("MAC not initialized");
       
   619         }
       
   620         update(input);
       
   621         return doFinal();
       
   622     }
       
   623 
       
   624     /**
       
   625      * Resets this <code>Mac</code> object.
       
   626      *
       
   627      * <p>A call to this method resets this <code>Mac</code> object to the
       
   628      * state it was in when previously initialized via a call to
       
   629      * <code>init(Key)</code> or
       
   630      * <code>init(Key, AlgorithmParameterSpec)</code>.
       
   631      * That is, the object is reset and available to generate another MAC from
       
   632      * the same key, if desired, via new calls to <code>update</code> and
       
   633      * <code>doFinal</code>.
       
   634      * (In order to reuse this <code>Mac</code> object with a different key,
       
   635      * it must be reinitialized via a call to <code>init(Key)</code> or
       
   636      * <code>init(Key, AlgorithmParameterSpec)</code>.
       
   637      */
       
   638     public final void reset() {
       
   639         chooseFirstProvider();
       
   640         spi.engineReset();
       
   641     }
       
   642 
       
   643     /**
       
   644      * Returns a clone if the provider implementation is cloneable.
       
   645      *
       
   646      * @return a clone if the provider implementation is cloneable.
       
   647      *
       
   648      * @exception CloneNotSupportedException if this is called on a
       
   649      * delegate that does not support <code>Cloneable</code>.
       
   650      */
       
   651     public final Object clone() throws CloneNotSupportedException {
       
   652         chooseFirstProvider();
       
   653         Mac that = (Mac)super.clone();
       
   654         that.spi = (MacSpi)this.spi.clone();
       
   655         return that;
       
   656     }
       
   657 }