• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package javax.crypto;
28 
29 import java.util.*;
30 
31 import java.security.*;
32 import java.security.Provider.Service;
33 import java.security.spec.AlgorithmParameterSpec;
34 
35 import java.nio.ByteBuffer;
36 
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> Android provides the following <code>Mac</code> algorithms:
57  * <table>
58  *   <thead>
59  *     <tr>
60  *       <th>Algorithm</th>
61  *       <th>Supported API Levels</th>
62  *     </tr>
63  *   </thead>
64  *   <tbody>
65  *     <tr class="deprecated">
66  *       <td>DESMAC</td>
67  *       <td>1-8</td>
68  *     </tr>
69  *     <tr class="deprecated">
70  *       <td>DESMAC/CFB8</td>
71  *       <td>1-8</td>
72  *     </tr>
73  *     <tr class="deprecated">
74  *       <td>DESedeMAC</td>
75  *       <td>1-8</td>
76  *     </tr>
77  *     <tr class="deprecated">
78  *       <td>DESedeMAC/CFB8</td>
79  *       <td>1-8</td>
80  *     </tr>
81  *     <tr class="deprecated">
82  *       <td>DESedeMAC64</td>
83  *       <td>1-8</td>
84  *     </tr>
85  *     <tr class="deprecated">
86  *       <td>DESwithISO9797</td>
87  *       <td>1-8</td>
88  *     </tr>
89  *     <tr>
90  *       <td>HmacMD5</td>
91  *       <td>1+</td>
92  *     </tr>
93  *     <tr>
94  *       <td>HmacSHA1</td>
95  *       <td>1+</td>
96  *     </tr>
97  *     <tr>
98  *       <td>HmacSHA224</td>
99  *       <td>1-8,22+</td>
100  *     </tr>
101  *     <tr>
102  *       <td>HmacSHA256</td>
103  *       <td>1+</td>
104  *     </tr>
105  *     <tr>
106  *       <td>HmacSHA384</td>
107  *       <td>1+</td>
108  *     </tr>
109  *     <tr>
110  *       <td>HmacSHA512</td>
111  *       <td>1+</td>
112  *     </tr>
113  *     <tr class="deprecated">
114  *       <td>ISO9797ALG3MAC</td>
115  *       <td>1-8</td>
116  *     </tr>
117  *     <tr>
118  *       <td>PBEwithHmacSHA</td>
119  *       <td>1+</td>
120  *     </tr>
121  *     <tr>
122  *       <td>PBEwithHmacSHA1</td>
123  *       <td>1+</td>
124  *     </tr>
125  *     <tr>
126  *       <td>PBEwithHmacSHA224</td>
127  *       <td>26+</td>
128  *     </tr>
129  *     <tr>
130  *       <td>PBEwithHmacSHA256</td>
131  *       <td>26+</td>
132  *     </tr>
133  *     <tr>
134  *       <td>PBEwithHmacSHA384</td>
135  *       <td>26+</td>
136  *     </tr>
137  *     <tr>
138  *       <td>PBEwithHmacSHA512</td>
139  *       <td>26+</td>
140  *     </tr>
141  *   </tbody>
142  * </table>
143  *
144  * These algorithms are described in the
145  * <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
146  * Mac section</a> of the
147  * Java Cryptography Architecture Standard Algorithm Name Documentation.
148  *
149  * @author Jan Luehe
150  *
151  * @since 1.4
152  */
153 
154 public class Mac implements Cloneable {
155 
156     // Android-removed: this debugging mechanism is not used in Android.
157     /*
158     private static final Debug debug =
159                         Debug.getInstance("jca", "Mac");
160 
161     private static final Debug pdebug =
162                         Debug.getInstance("provider", "Provider");
163     private static final boolean skipDebug =
164         Debug.isOn("engine=") && !Debug.isOn("mac");
165     */
166 
167     // The provider
168     private Provider provider;
169 
170     // The provider implementation (delegate)
171     private MacSpi spi;
172 
173     // The name of the MAC algorithm.
174     private final String algorithm;
175 
176     // Has this object been initialized?
177     private boolean initialized = false;
178 
179     // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider.
180     // When only the algorithm is specified, we want to allow the Mac provider for that
181     // algorithm to change if multiple providers exist and they support different subsets of
182     // keys.  To that end, we don't hold an iterator and exhaust it when we need to choose
183     // a provider like the upstream implementation, we reestablish the list of providers
184     // each time.
185     /*
186     // next service to try in provider selection
187     // null once provider is selected
188     private Service firstService;
189 
190     // remaining services to try in provider selection
191     // null once provider is selected
192     private Iterator<Service> serviceIterator;
193     */
194     // END Android-removed: Redo the provider selection logic to allow reselecting provider.
195 
196     private final Object lock;
197 
198     /**
199      * Creates a MAC object.
200      *
201      * @param macSpi the delegate
202      * @param provider the provider
203      * @param algorithm the algorithm
204      */
Mac(MacSpi macSpi, Provider provider, String algorithm)205     protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
206         this.spi = macSpi;
207         this.provider = provider;
208         this.algorithm = algorithm;
209         lock = null;
210     }
211 
212     // Android-changed: Remove Service and Iterator from constructor args.
Mac(String algorithm)213     private Mac(String algorithm) {
214         this.algorithm = algorithm;
215         lock = new Object();
216     }
217 
218     /**
219      * Returns the algorithm name of this <code>Mac</code> object.
220      *
221      * <p>This is the same name that was specified in one of the
222      * <code>getInstance</code> calls that created this
223      * <code>Mac</code> object.
224      *
225      * @return the algorithm name of this <code>Mac</code> object.
226      */
getAlgorithm()227     public final String getAlgorithm() {
228         return this.algorithm;
229     }
230 
231     /**
232      * Returns a <code>Mac</code> object that implements the
233      * specified MAC algorithm.
234      *
235      * <p> This method traverses the list of registered security Providers,
236      * starting with the most preferred Provider.
237      * A new Mac object encapsulating the
238      * MacSpi implementation from the first
239      * Provider that supports the specified algorithm is returned.
240      *
241      * <p> Note that the list of registered providers may be retrieved via
242      * the {@link Security#getProviders() Security.getProviders()} method.
243      *
244      * @param algorithm the standard name of the requested MAC algorithm.
245      * See the Mac section in the <a href=
246      *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
247      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
248      * for information about standard algorithm names.
249      *
250      * @return the new <code>Mac</code> object.
251      *
252      * @exception NoSuchAlgorithmException if no Provider supports a
253      *          MacSpi implementation for the
254      *          specified algorithm.
255      *
256      * @see java.security.Provider
257      */
getInstance(String algorithm)258     public static final Mac getInstance(String algorithm)
259             throws NoSuchAlgorithmException {
260         List<Service> services = GetInstance.getServices("Mac", algorithm);
261         // make sure there is at least one service from a signed provider
262         Iterator<Service> t = services.iterator();
263         while (t.hasNext()) {
264             Service s = t.next();
265             if (JceSecurity.canUseProvider(s.getProvider()) == false) {
266                 continue;
267             }
268             // Android-changed: Remove Service and Iterator from constructor args.
269             // return new Mac(s, t, algorithm);
270             return new Mac(algorithm);
271         }
272         throw new NoSuchAlgorithmException
273                                 ("Algorithm " + algorithm + " not available");
274     }
275 
276     /**
277      * Returns a <code>Mac</code> object that implements the
278      * specified MAC algorithm.
279      *
280      * <p> A new Mac object encapsulating the
281      * MacSpi implementation from the specified provider
282      * is returned.  The specified provider must be registered
283      * in the security provider list.
284      *
285      * <p> Note that the list of registered providers may be retrieved via
286      * the {@link Security#getProviders() Security.getProviders()} method.
287      *
288      * @param algorithm the standard name of the requested MAC algorithm.
289      * See the Mac section in the <a href=
290      *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
291      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
292      * for information about standard algorithm names.
293      *
294      * @param provider the name of the provider.
295      *
296      * @return the new <code>Mac</code> object.
297      *
298      * @exception NoSuchAlgorithmException if a MacSpi
299      *          implementation for the specified algorithm is not
300      *          available from the specified provider.
301      *
302      * @exception NoSuchProviderException if the specified provider is not
303      *          registered in the security provider list.
304      *
305      * @exception IllegalArgumentException if the <code>provider</code>
306      *          is null or empty.
307      *
308      * @see java.security.Provider
309      */
getInstance(String algorithm, String provider)310     public static final Mac getInstance(String algorithm, String provider)
311             throws NoSuchAlgorithmException, NoSuchProviderException {
312         // Android-added: Check for Bouncy Castle deprecation
313         Providers.checkBouncyCastleDeprecation(provider, "Mac", algorithm);
314         Instance instance = JceSecurity.getInstance
315                 ("Mac", MacSpi.class, algorithm, provider);
316         return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
317     }
318 
319     /**
320      * Returns a <code>Mac</code> object that implements the
321      * specified MAC algorithm.
322      *
323      * <p> A new Mac object encapsulating the
324      * MacSpi implementation from the specified Provider
325      * object is returned.  Note that the specified Provider object
326      * does not have to be registered in the provider list.
327      *
328      * @param algorithm the standard name of the requested MAC algorithm.
329      * See the Mac section in the <a href=
330      *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
331      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
332      * for information about standard algorithm names.
333      *
334      * @param provider the provider.
335      *
336      * @return the new <code>Mac</code> object.
337      *
338      * @exception NoSuchAlgorithmException if a MacSpi
339      *          implementation for the specified algorithm is not available
340      *          from the specified Provider object.
341      *
342      * @exception IllegalArgumentException if the <code>provider</code>
343      *          is null.
344      *
345      * @see java.security.Provider
346      */
getInstance(String algorithm, Provider provider)347     public static final Mac getInstance(String algorithm, Provider provider)
348             throws NoSuchAlgorithmException {
349         // Android-added: Check for Bouncy Castle deprecation
350         Providers.checkBouncyCastleDeprecation(provider, "Mac", algorithm);
351         Instance instance = JceSecurity.getInstance
352                 ("Mac", MacSpi.class, algorithm, provider);
353         return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
354     }
355 
356     // max number of debug warnings to print from chooseFirstProvider()
357     private static int warnCount = 10;
358 
359     /**
360      * Choose the Spi from the first provider available. Used if
361      * delayed provider selection is not possible because init()
362      * is not the first method called.
363      */
chooseFirstProvider()364     void chooseFirstProvider() {
365         // Android-changed: Check if lock is null rather than removed serviceIterator field.
366         // if ((spi != null) || (serviceIterator == null)) {
367         if (spi != null || lock == null) {
368             return;
369         }
370         synchronized (lock) {
371             if (spi != null) {
372                 return;
373             }
374             // Android-removed: this debugging mechanism is not used in Android.
375             /*
376             if (debug != null) {
377                 int w = --warnCount;
378                 if (w >= 0) {
379                     debug.println("Mac.init() not first method "
380                         + "called, disabling delayed provider selection");
381                     if (w == 0) {
382                         debug.println("Further warnings of this type will "
383                             + "be suppressed");
384                     }
385                     new Exception("Call trace").printStackTrace();
386                 }
387             }
388             */
389             Exception lastException = null;
390             // Android-changed: Provider selection; loop over a new list each time.
391             for (Service s : GetInstance.getServices("Mac", algorithm)) {
392                 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
393                     continue;
394                 }
395                 try {
396                     Object obj = s.newInstance(null);
397                     if (obj instanceof MacSpi == false) {
398                         continue;
399                     }
400                     spi = (MacSpi)obj;
401                     provider = s.getProvider();
402                     // Android-removed: Provider selection; loop over a new list each time.
403                     /*
404                     // not needed any more
405                     firstService = null;
406                     serviceIterator = null;
407                     */
408                     return;
409                 } catch (NoSuchAlgorithmException e) {
410                     lastException = e;
411                 }
412             }
413             ProviderException e = new ProviderException
414                     ("Could not construct MacSpi instance");
415             if (lastException != null) {
416                 e.initCause(lastException);
417             }
418             throw e;
419         }
420     }
421 
chooseProvider(Key key, AlgorithmParameterSpec params)422     private void chooseProvider(Key key, AlgorithmParameterSpec params)
423             throws InvalidKeyException, InvalidAlgorithmParameterException {
424         synchronized (lock) {
425             // Android-changed: Use the currently-selected provider only if no key was provided.
426             // if (spi != null) {
427             if (spi != null && (key == null || lock == null)) {
428                 spi.engineInit(key, params);
429                 return;
430             }
431             Exception lastException = null;
432             // Android-changed: Provider selection; loop over a new list each time.
433             for (Service s : GetInstance.getServices("Mac", algorithm)) {
434                 // if provider says it does not support this key, ignore it
435                 if (s.supportsParameter(key) == false) {
436                     continue;
437                 }
438                 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
439                     continue;
440                 }
441                 try {
442                     MacSpi spi = (MacSpi)s.newInstance(null);
443                     spi.engineInit(key, params);
444                     provider = s.getProvider();
445                     this.spi = spi;
446                     // Android-removed: Provider selection; loop over a new list each time.
447                     /*
448                     firstService = null;
449                     serviceIterator = null;
450                     */
451                     return;
452                 } catch (Exception e) {
453                     // NoSuchAlgorithmException from newInstance()
454                     // InvalidKeyException from init()
455                     // RuntimeException (ProviderException) from init()
456                     if (lastException == null) {
457                         lastException = e;
458                     }
459                 }
460             }
461             // no working provider found, fail
462             if (lastException instanceof InvalidKeyException) {
463                 throw (InvalidKeyException)lastException;
464             }
465             if (lastException instanceof InvalidAlgorithmParameterException) {
466                 throw (InvalidAlgorithmParameterException)lastException;
467             }
468             if (lastException instanceof RuntimeException) {
469                 throw (RuntimeException)lastException;
470             }
471             String kName = (key != null) ? key.getClass().getName() : "(null)";
472             throw new InvalidKeyException
473                 ("No installed provider supports this key: "
474                 + kName, lastException);
475         }
476     }
477 
478     /**
479      * Returns the provider of this <code>Mac</code> object.
480      *
481      * @return the provider of this <code>Mac</code> object.
482      */
getProvider()483     public final Provider getProvider() {
484         chooseFirstProvider();
485         return this.provider;
486     }
487 
488     /**
489      * Returns the length of the MAC in bytes.
490      *
491      * @return the MAC length in bytes.
492      */
getMacLength()493     public final int getMacLength() {
494         chooseFirstProvider();
495         return spi.engineGetMacLength();
496     }
497 
498     /**
499      * Initializes this <code>Mac</code> object with the given key.
500      *
501      * @param key the key.
502      *
503      * @exception InvalidKeyException if the given key is inappropriate for
504      * initializing this MAC.
505      */
init(Key key)506     public final void init(Key key) throws InvalidKeyException {
507         try {
508             // Android-changed: Use the currently-selected provider only if no key was provided.
509             // if (spi != null) {
510             if (spi != null && (key == null || lock == null)) {
511                 spi.engineInit(key, null);
512             } else {
513                 chooseProvider(key, null);
514             }
515         } catch (InvalidAlgorithmParameterException e) {
516             throw new InvalidKeyException("init() failed", e);
517         }
518         initialized = true;
519 
520         // Android-removed: this debugging mechanism is not used in Android.
521         /*
522         if (!skipDebug && pdebug != null) {
523             pdebug.println("Mac." + algorithm + " algorithm from: " +
524                 this.provider.getName());
525         }
526         */
527     }
528 
529     /**
530      * Initializes this <code>Mac</code> object with the given key and
531      * algorithm parameters.
532      *
533      * @param key the key.
534      * @param params the algorithm parameters.
535      *
536      * @exception InvalidKeyException if the given key is inappropriate for
537      * initializing this MAC.
538      * @exception InvalidAlgorithmParameterException if the given algorithm
539      * parameters are inappropriate for this MAC.
540      */
init(Key key, AlgorithmParameterSpec params)541     public final void init(Key key, AlgorithmParameterSpec params)
542             throws InvalidKeyException, InvalidAlgorithmParameterException {
543         // Android-changed: Use the currently-selected provider only if no key was provided.
544         // if (spi != null) {
545         if (spi != null && (key == null || lock == null)) {
546             spi.engineInit(key, params);
547         } else {
548             chooseProvider(key, params);
549         }
550         initialized = true;
551 
552         // Android-removed: this debugging mechanism is not used in Android.
553         /*
554         if (!skipDebug && pdebug != null) {
555             pdebug.println("Mac." + algorithm + " algorithm from: " +
556                 this.provider.getName());
557         }
558         */
559     }
560 
561     /**
562      * Processes the given byte.
563      *
564      * @param input the input byte to be processed.
565      *
566      * @exception IllegalStateException if this <code>Mac</code> has not been
567      * initialized.
568      */
update(byte input)569     public final void update(byte input) throws IllegalStateException {
570         chooseFirstProvider();
571         if (initialized == false) {
572             throw new IllegalStateException("MAC not initialized");
573         }
574         spi.engineUpdate(input);
575     }
576 
577     /**
578      * Processes the given array of bytes.
579      *
580      * @param input the array of bytes to be processed.
581      *
582      * @exception IllegalStateException if this <code>Mac</code> has not been
583      * initialized.
584      */
update(byte[] input)585     public final void update(byte[] input) throws IllegalStateException {
586         chooseFirstProvider();
587         if (initialized == false) {
588             throw new IllegalStateException("MAC not initialized");
589         }
590         if (input != null) {
591             spi.engineUpdate(input, 0, input.length);
592         }
593     }
594 
595     /**
596      * Processes the first <code>len</code> bytes in <code>input</code>,
597      * starting at <code>offset</code> inclusive.
598      *
599      * @param input the input buffer.
600      * @param offset the offset in <code>input</code> where the input starts.
601      * @param len the number of bytes to process.
602      *
603      * @exception IllegalStateException if this <code>Mac</code> has not been
604      * initialized.
605      */
update(byte[] input, int offset, int len)606     public final void update(byte[] input, int offset, int len)
607             throws IllegalStateException {
608         chooseFirstProvider();
609         if (initialized == false) {
610             throw new IllegalStateException("MAC not initialized");
611         }
612 
613         if (input != null) {
614             if ((offset < 0) || (len > (input.length - offset)) || (len < 0))
615                 throw new IllegalArgumentException("Bad arguments");
616             spi.engineUpdate(input, offset, len);
617         }
618     }
619 
620     /**
621      * Processes <code>input.remaining()</code> bytes in the ByteBuffer
622      * <code>input</code>, starting at <code>input.position()</code>.
623      * Upon return, the buffer's position will be equal to its limit;
624      * its limit will not have changed.
625      *
626      * @param input the ByteBuffer
627      *
628      * @exception IllegalStateException if this <code>Mac</code> has not been
629      * initialized.
630      * @since 1.5
631      */
update(ByteBuffer input)632     public final void update(ByteBuffer input) {
633         chooseFirstProvider();
634         if (initialized == false) {
635             throw new IllegalStateException("MAC not initialized");
636         }
637         if (input == null) {
638             throw new IllegalArgumentException("Buffer must not be null");
639         }
640         spi.engineUpdate(input);
641     }
642 
643     /**
644      * Finishes the MAC operation.
645      *
646      * <p>A call to this method resets this <code>Mac</code> object to the
647      * state it was in when previously initialized via a call to
648      * <code>init(Key)</code> or
649      * <code>init(Key, AlgorithmParameterSpec)</code>.
650      * That is, the object is reset and available to generate another MAC from
651      * the same key, if desired, via new calls to <code>update</code> and
652      * <code>doFinal</code>.
653      * (In order to reuse this <code>Mac</code> object with a different key,
654      * it must be reinitialized via a call to <code>init(Key)</code> or
655      * <code>init(Key, AlgorithmParameterSpec)</code>.
656      *
657      * @return the MAC result.
658      *
659      * @exception IllegalStateException if this <code>Mac</code> has not been
660      * initialized.
661      */
doFinal()662     public final byte[] doFinal() throws IllegalStateException {
663         chooseFirstProvider();
664         if (initialized == false) {
665             throw new IllegalStateException("MAC not initialized");
666         }
667         byte[] mac = spi.engineDoFinal();
668         spi.engineReset();
669         return mac;
670     }
671 
672     /**
673      * Finishes the MAC operation.
674      *
675      * <p>A call to this method resets this <code>Mac</code> object to the
676      * state it was in when previously initialized via a call to
677      * <code>init(Key)</code> or
678      * <code>init(Key, AlgorithmParameterSpec)</code>.
679      * That is, the object is reset and available to generate another MAC from
680      * the same key, if desired, via new calls to <code>update</code> and
681      * <code>doFinal</code>.
682      * (In order to reuse this <code>Mac</code> object with a different key,
683      * it must be reinitialized via a call to <code>init(Key)</code> or
684      * <code>init(Key, AlgorithmParameterSpec)</code>.
685      *
686      * <p>The MAC result is stored in <code>output</code>, starting at
687      * <code>outOffset</code> inclusive.
688      *
689      * @param output the buffer where the MAC result is stored
690      * @param outOffset the offset in <code>output</code> where the MAC is
691      * stored
692      *
693      * @exception ShortBufferException if the given output buffer is too small
694      * to hold the result
695      * @exception IllegalStateException if this <code>Mac</code> has not been
696      * initialized.
697      */
doFinal(byte[] output, int outOffset)698     public final void doFinal(byte[] output, int outOffset)
699         throws ShortBufferException, IllegalStateException
700     {
701         chooseFirstProvider();
702         if (initialized == false) {
703             throw new IllegalStateException("MAC not initialized");
704         }
705         int macLen = getMacLength();
706         if (output == null || output.length-outOffset < macLen) {
707             throw new ShortBufferException
708                 ("Cannot store MAC in output buffer");
709         }
710         byte[] mac = doFinal();
711         System.arraycopy(mac, 0, output, outOffset, macLen);
712         return;
713     }
714 
715     /**
716      * Processes the given array of bytes and finishes the MAC operation.
717      *
718      * <p>A call to this method resets this <code>Mac</code> object to the
719      * state it was in when previously initialized via a call to
720      * <code>init(Key)</code> or
721      * <code>init(Key, AlgorithmParameterSpec)</code>.
722      * That is, the object is reset and available to generate another MAC from
723      * the same key, if desired, via new calls to <code>update</code> and
724      * <code>doFinal</code>.
725      * (In order to reuse this <code>Mac</code> object with a different key,
726      * it must be reinitialized via a call to <code>init(Key)</code> or
727      * <code>init(Key, AlgorithmParameterSpec)</code>.
728      *
729      * @param input data in bytes
730      * @return the MAC result.
731      *
732      * @exception IllegalStateException if this <code>Mac</code> has not been
733      * initialized.
734      */
doFinal(byte[] input)735     public final byte[] doFinal(byte[] input) throws IllegalStateException
736     {
737         chooseFirstProvider();
738         if (initialized == false) {
739             throw new IllegalStateException("MAC not initialized");
740         }
741         update(input);
742         return doFinal();
743     }
744 
745     /**
746      * Resets this <code>Mac</code> object.
747      *
748      * <p>A call to this method resets this <code>Mac</code> object to the
749      * state it was in when previously initialized via a call to
750      * <code>init(Key)</code> or
751      * <code>init(Key, AlgorithmParameterSpec)</code>.
752      * That is, the object is reset and available to generate another MAC from
753      * the same key, if desired, via new calls to <code>update</code> and
754      * <code>doFinal</code>.
755      * (In order to reuse this <code>Mac</code> object with a different key,
756      * it must be reinitialized via a call to <code>init(Key)</code> or
757      * <code>init(Key, AlgorithmParameterSpec)</code>.
758      */
reset()759     public final void reset() {
760         chooseFirstProvider();
761         spi.engineReset();
762     }
763 
764     /**
765      * Returns a clone if the provider implementation is cloneable.
766      *
767      * @return a clone if the provider implementation is cloneable.
768      *
769      * @exception CloneNotSupportedException if this is called on a
770      * delegate that does not support <code>Cloneable</code>.
771      */
clone()772     public final Object clone() throws CloneNotSupportedException {
773         chooseFirstProvider();
774         Mac that = (Mac)super.clone();
775         that.spi = (MacSpi)this.spi.clone();
776         return that;
777     }
778 
779     // BEGIN Android-added: Allow access to the current SPI for testing purposes.
780     /**
781      * Returns the {@code MacSpi} backing this {@code Mac} or {@code null} if no {@code MacSpi} is
782      * backing this {@code Mac}.
783      *
784      * @hide
785      */
getCurrentSpi()786     public MacSpi getCurrentSpi() {
787         return spi;
788     }
789     // END Android-added: Allow access to the current SPI for testing purposes.
790 }
791