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