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