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
27package javax.crypto;
28
29import java.util.*;
30
31import java.security.*;
32import java.security.Provider.Service;
33import java.security.spec.AlgorithmParameterSpec;
34
35import java.nio.ByteBuffer;
36
37import sun.security.jca.*;
38import 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}openjdk-redirect.html?v=8&path=/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
154public 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     */
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.
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     */
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}openjdk-redirect.html?v=8&path=/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     */
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}openjdk-redirect.html?v=8&path=/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     */
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}openjdk-redirect.html?v=8&path=/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     */
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     */
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
786    public MacSpi getCurrentSpi() {
787        return spi;
788    }
789    // END Android-added: Allow access to the current SPI for testing purposes.
790}
791