001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.codec.digest;
019
020import java.io.BufferedInputStream;
021import java.io.File;
022import java.io.FileInputStream;
023import java.io.IOException;
024import java.io.InputStream;
025import java.nio.ByteBuffer;
026import java.security.InvalidKeyException;
027import java.security.Key;
028import java.security.NoSuchAlgorithmException;
029
030import javax.crypto.Mac;
031import javax.crypto.spec.SecretKeySpec;
032
033import org.apache.commons.codec.binary.Hex;
034import org.apache.commons.codec.binary.StringUtils;
035
036/**
037 * Simplifies common {@link javax.crypto.Mac} tasks. This class is immutable and thread-safe.
038 * However the Mac may not be.
039 * <p>
040 * <strong>Note: Not all JCE implementations support all algorithms. If not supported, an IllegalArgumentException is
041 * thrown.</strong>
042 * </p>
043 * <p>
044 * Sample usage:
045 * </p>
046 * <pre>
047 * import static HmacAlgorithms.*;
048 * byte[] key = {1,2,3,4}; // don't use this actual key!
049 * String valueToDigest = "The quick brown fox jumps over the lazy dog";
050 * byte[] hmac = new HmacUtils(HMAC_SHA_224, key).hmac(valueToDigest);
051 * // Mac re-use
052 * HmacUtils hm1 = new HmacUtils("HmacAlgoName", key); // use a valid name here!
053 * String hexPom = hm1.hmacHex(new File("pom.xml"));
054 * String hexNot = hm1.hmacHex(new File("NOTICE.txt"));
055 * </pre>
056 * @since 1.10
057 */
058public final class HmacUtils {
059
060    private static final int STREAM_BUFFER_LENGTH = 1024;
061
062    /**
063     * Returns an initialized {@code Mac} for the HmacMD5 algorithm.
064     * <p>
065     * Every implementation of the Java platform is required to support this standard Mac algorithm.
066     * </p>
067     *
068     * @param key
069     *            The key for the keyed digest (must not be null)
070     * @return A Mac instance initialized with the given key.
071     * @see Mac#getInstance(String)
072     * @see Mac#init(Key)
073     * @throws IllegalArgumentException
074     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
075     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_MD5, byte[])}
076     */
077    @Deprecated
078    public static Mac getHmacMd5(final byte[] key) {
079        return getInitializedMac(HmacAlgorithms.HMAC_MD5, key);
080    }
081
082    /**
083     * Returns an initialized {@code Mac} for the HmacSHA1 algorithm.
084     * <p>
085     * Every implementation of the Java platform is required to support this standard Mac algorithm.
086     * </p>
087     *
088     * @param key
089     *            The key for the keyed digest (must not be null)
090     * @return A Mac instance initialized with the given key.
091     * @see Mac#getInstance(String)
092     * @see Mac#init(Key)
093     * @throws IllegalArgumentException
094     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
095     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_1, byte[])}
096     */
097    @Deprecated
098    public static Mac getHmacSha1(final byte[] key) {
099        return getInitializedMac(HmacAlgorithms.HMAC_SHA_1, key);
100    }
101
102    /**
103     * Returns an initialized {@code Mac} for the HmacSHA256 algorithm.
104     * <p>
105     * Every implementation of the Java platform is required to support this standard Mac algorithm.
106     * </p>
107     *
108     * @param key
109     *            The key for the keyed digest (must not be null)
110     * @return A Mac instance initialized with the given key.
111     * @see Mac#getInstance(String)
112     * @see Mac#init(Key)
113     * @throws IllegalArgumentException
114     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
115     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_256, byte[])}
116     */
117    @Deprecated
118    public static Mac getHmacSha256(final byte[] key) {
119        return getInitializedMac(HmacAlgorithms.HMAC_SHA_256, key);
120    }
121
122    /**
123     * Returns an initialized {@code Mac} for the HmacSHA384 algorithm.
124     * <p>
125     * Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
126     * </p>
127     *
128     * @param key
129     *            The key for the keyed digest (must not be null)
130     * @return A Mac instance initialized with the given key.
131     * @see Mac#getInstance(String)
132     * @see Mac#init(Key)
133     * @throws IllegalArgumentException
134     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
135     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_384, byte[])}
136     */
137    @Deprecated
138    public static Mac getHmacSha384(final byte[] key) {
139        return getInitializedMac(HmacAlgorithms.HMAC_SHA_384, key);
140    }
141
142    /**
143     * Returns an initialized {@code Mac} for the HmacSHA512 algorithm.
144     * <p>
145     * Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
146     * </p>
147     *
148     * @param key
149     *            The key for the keyed digest (must not be null)
150     * @return A Mac instance initialized with the given key.
151     * @see Mac#getInstance(String)
152     * @see Mac#init(Key)
153     * @throws IllegalArgumentException
154     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
155     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_512, byte[])}
156     */
157    @Deprecated
158    public static Mac getHmacSha512(final byte[] key) {
159        return getInitializedMac(HmacAlgorithms.HMAC_SHA_512, key);
160    }
161
162    /**
163     * Returns an initialized {@code Mac} for the given {@code algorithm}.
164     *
165     * @param algorithm
166     *            the name of the algorithm requested. See
167     *            <a href= "https://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA"
168     *            >Appendix A in the Java Cryptography Architecture Reference Guide</a> for information about standard
169     *            algorithm names.
170     * @param key
171     *            The key for the keyed digest (must not be null)
172     * @return A Mac instance initialized with the given key.
173     * @see Mac#getInstance(String)
174     * @see Mac#init(Key)
175     * @throws IllegalArgumentException
176     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
177     */
178    public static Mac getInitializedMac(final HmacAlgorithms algorithm, final byte[] key) {
179        return getInitializedMac(algorithm.getName(), key);
180    }
181
182    /**
183     * Returns an initialized {@code Mac} for the given {@code algorithm}.
184     *
185     * @param algorithm
186     *            the name of the algorithm requested. See
187     *            <a href= "https://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA"
188     *            >Appendix A in the Java Cryptography Architecture Reference Guide</a> for information about standard
189     *            algorithm names.
190     * @param key
191     *            The key for the keyed digest (must not be null)
192     * @return A Mac instance initialized with the given key.
193     * @see Mac#getInstance(String)
194     * @see Mac#init(Key)
195     * @throws IllegalArgumentException
196     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
197     */
198    public static Mac getInitializedMac(final String algorithm, final byte[] key) {
199        if (key == null) {
200            throw new IllegalArgumentException("Null key");
201        }
202        try {
203            final SecretKeySpec keySpec = new SecretKeySpec(key, algorithm);
204            final Mac mac = Mac.getInstance(algorithm);
205            mac.init(keySpec);
206            return mac;
207        } catch (final NoSuchAlgorithmException | InvalidKeyException e) {
208            throw new IllegalArgumentException(e);
209        }
210    }
211
212    /**
213     * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
214     *
215     * @param key
216     *            The key for the keyed digest (must not be null)
217     * @param valueToDigest
218     *            The value (data) which should to digest (maybe empty or null)
219     * @return HmacMD5 MAC for the given key and value
220     * @throws IllegalArgumentException
221     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
222     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmac(byte[])}
223     */
224    @Deprecated
225    public static byte[] hmacMd5(final byte[] key, final byte[] valueToDigest) {
226        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
227    }
228
229    /**
230     * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
231     *
232     * @param key
233     *            The key for the keyed digest (must not be null)
234     * @param valueToDigest
235     *            The value (data) which should to digest
236     *            <p>
237     *            The InputStream must not be null and will not be closed
238     *            </p>
239     * @return HmacMD5 MAC for the given key and value
240     * @throws IOException
241     *             If an I/O error occurs.
242     * @throws IllegalArgumentException
243     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
244     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmac(InputStream)}
245     */
246    @Deprecated
247    public static byte[] hmacMd5(final byte[] key, final InputStream valueToDigest) throws IOException {
248        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
249    }
250
251    /**
252     * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
253     *
254     * @param key
255     *            The key for the keyed digest (must not be null)
256     * @param valueToDigest
257     *            The value (data) which should to digest (maybe empty or null)
258     * @return HmacMD5 MAC for the given key and value
259     * @throws IllegalArgumentException
260     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
261     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, String).hmac(String)}
262     */
263    @Deprecated
264    public static byte[] hmacMd5(final String key, final String valueToDigest) {
265        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
266    }
267
268    /**
269     * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
270     *
271     * @param key
272     *            The key for the keyed digest (must not be null)
273     * @param valueToDigest
274     *            The value (data) which should to digest (maybe empty or null)
275     * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase)
276     * @throws IllegalArgumentException
277     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
278     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmacHex(byte[])}
279     */
280    @Deprecated
281    public static String hmacMd5Hex(final byte[] key, final byte[] valueToDigest) {
282        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
283    }
284
285    /**
286     * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
287     *
288     * @param key
289     *            The key for the keyed digest (must not be null)
290     * @param valueToDigest
291     *            The value (data) which should to digest
292     *            <p>
293     *            The InputStream must not be null and will not be closed
294     *            </p>
295     * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase)
296     * @throws IOException
297     *             If an I/O error occurs.
298     * @throws IllegalArgumentException
299     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
300     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmacHex(InputStream)}
301     */
302    @Deprecated
303    public static String hmacMd5Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
304        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
305    }
306
307    /**
308     * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
309     *
310     * @param key
311     *            The key for the keyed digest (must not be null)
312     * @param valueToDigest
313     *            The value (data) which should to digest (maybe empty or null)
314     * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase)
315     * @throws IllegalArgumentException
316     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
317     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, String).hmacHex(String)}
318     */
319    @Deprecated
320    public static String hmacMd5Hex(final String key, final String valueToDigest) {
321        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
322    }
323
324    /**
325     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
326     *
327     * @param key
328     *            The key for the keyed digest (must not be null)
329     * @param valueToDigest
330     *            The value (data) which should to digest (maybe empty or null)
331     * @return HmacSHA1 MAC for the given key and value
332     * @throws IllegalArgumentException
333     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
334     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmac(byte[])}
335     */
336    @Deprecated
337    public static byte[] hmacSha1(final byte[] key, final byte[] valueToDigest) {
338        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
339    }
340
341    /**
342     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
343     *
344     * @param key
345     *            The key for the keyed digest (must not be null)
346     * @param valueToDigest
347     *            The value (data) which should to digest
348     *            <p>
349     *            The InputStream must not be null and will not be closed
350     *            </p>
351     * @return HmacSHA1 MAC for the given key and value
352     * @throws IOException
353     *             If an I/O error occurs.
354     * @throws IllegalArgumentException
355     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
356     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmac(InputStream)}
357     */
358    @Deprecated
359    public static byte[] hmacSha1(final byte[] key, final InputStream valueToDigest) throws IOException {
360        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
361    }
362
363    /**
364     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
365     *
366     * @param key
367     *            The key for the keyed digest (must not be null)
368     * @param valueToDigest
369     *            The value (data) which should to digest (maybe empty or null)
370     * @return HmacSHA1 MAC for the given key and value
371     * @throws IllegalArgumentException
372     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
373     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, String).hmac(String)}
374     */
375    @Deprecated
376    public static byte[] hmacSha1(final String key, final String valueToDigest) {
377        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
378    }
379
380    // hmacSha1
381
382    /**
383     * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
384     *
385     * @param key
386     *            The key for the keyed digest (must not be null)
387     * @param valueToDigest
388     *            The value (data) which should to digest (maybe empty or null)
389     * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase)
390     * @throws IllegalArgumentException
391     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
392     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmacHex(byte[])}
393     */
394    @Deprecated
395    public static String hmacSha1Hex(final byte[] key, final byte[] valueToDigest) {
396        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
397    }
398
399    /**
400     * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
401     *
402     * @param key
403     *            The key for the keyed digest (must not be null)
404     * @param valueToDigest
405     *            The value (data) which should to digest
406     *            <p>
407     *            The InputStream must not be null and will not be closed
408     *            </p>
409     * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase)
410     * @throws IOException
411     *             If an I/O error occurs.
412     * @throws IllegalArgumentException
413     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
414     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmacHex(InputStream)}
415     */
416    @Deprecated
417    public static String hmacSha1Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
418        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
419    }
420
421    /**
422     * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
423     *
424     * @param key
425     *            The key for the keyed digest (must not be null)
426     * @param valueToDigest
427     *            The value (data) which should to digest (maybe empty or null)
428     * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase)
429     * @throws IllegalArgumentException
430     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
431     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, String).hmacHex(String)}
432     */
433    @Deprecated
434    public static String hmacSha1Hex(final String key, final String valueToDigest) {
435        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
436    }
437
438    /**
439     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
440     *
441     * @param key
442     *            The key for the keyed digest (must not be null)
443     * @param valueToDigest
444     *            The value (data) which should to digest (maybe empty or null)
445     * @return HmacSHA256 MAC for the given key and value
446     * @throws IllegalArgumentException
447     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
448     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmac(byte[])}
449     */
450    @Deprecated
451    public static byte[] hmacSha256(final byte[] key, final byte[] valueToDigest) {
452        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
453    }
454
455    /**
456     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
457     *
458     * @param key
459     *            The key for the keyed digest (must not be null)
460     * @param valueToDigest
461     *            The value (data) which should to digest
462     *            <p>
463     *            The InputStream must not be null and will not be closed
464     *            </p>
465     * @return HmacSHA256 MAC for the given key and value
466     * @throws IOException
467     *             If an I/O error occurs.
468     * @throws IllegalArgumentException
469     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
470     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmac(InputStream)}
471     */
472    @Deprecated
473    public static byte[] hmacSha256(final byte[] key, final InputStream valueToDigest) throws IOException {
474        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
475    }
476
477    /**
478     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
479     *
480     * @param key
481     *            The key for the keyed digest (must not be null)
482     * @param valueToDigest
483     *            The value (data) which should to digest (maybe empty or null)
484     * @return HmacSHA256 MAC for the given key and value
485     * @throws IllegalArgumentException
486     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
487     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmac(String)}
488     */
489    @Deprecated
490    public static byte[] hmacSha256(final String key, final String valueToDigest) {
491        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
492    }
493
494    /**
495     * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
496     *
497     * @param key
498     *            The key for the keyed digest (must not be null)
499     * @param valueToDigest
500     *            The value (data) which should to digest (maybe empty or null)
501     * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase)
502     * @throws IllegalArgumentException
503     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
504     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmacHex(byte[])}
505     */
506    @Deprecated
507    public static String hmacSha256Hex(final byte[] key, final byte[] valueToDigest) {
508        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
509    }
510
511    /**
512     * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
513     *
514     * @param key
515     *            The key for the keyed digest (must not be null)
516     * @param valueToDigest
517     *            The value (data) which should to digest
518     *            <p>
519     *            The InputStream must not be null and will not be closed
520     *            </p>
521     * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase)
522     * @throws IOException
523     *             If an I/O error occurs.
524     * @throws IllegalArgumentException
525     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
526     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmacHex(InputStream)}
527     */
528    @Deprecated
529    public static String hmacSha256Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
530        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
531    }
532
533    /**
534     * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
535     *
536     * @param key
537     *            The key for the keyed digest (must not be null)
538     * @param valueToDigest
539     *            The value (data) which should to digest (maybe empty or null)
540     * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase)
541     * @throws IllegalArgumentException
542     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
543     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmacHex(String)}
544     */
545    @Deprecated
546    public static String hmacSha256Hex(final String key, final String valueToDigest) {
547        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
548    }
549
550    /**
551     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
552     *
553     * @param key
554     *            The key for the keyed digest (must not be null)
555     * @param valueToDigest
556     *            The value (data) which should to digest (maybe empty or null)
557     * @return HmacSHA384 MAC for the given key and value
558     * @throws IllegalArgumentException
559     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
560     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(byte[])}
561     */
562    @Deprecated
563    public static byte[] hmacSha384(final byte[] key, final byte[] valueToDigest) {
564        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
565    }
566
567    /**
568     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
569     *
570     * @param key
571     *            The key for the keyed digest (must not be null)
572     * @param valueToDigest
573     *            The value (data) which should to digest
574     *            <p>
575     *            The InputStream must not be null and will not be closed
576     *            </p>
577     * @return HmacSHA384 MAC for the given key and value
578     * @throws IOException
579     *             If an I/O error occurs.
580     * @throws IllegalArgumentException
581     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
582     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(InputStream)}
583     */
584    @Deprecated
585    public static byte[] hmacSha384(final byte[] key, final InputStream valueToDigest) throws IOException {
586        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
587    }
588
589    /**
590     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
591     *
592     * @param key
593     *            The key for the keyed digest (must not be null)
594     * @param valueToDigest
595     *            The value (data) which should to digest (maybe empty or null)
596     * @return HmacSHA384 MAC for the given key and value
597     * @throws IllegalArgumentException
598     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
599     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmac(String)}
600     */
601    @Deprecated
602    public static byte[] hmacSha384(final String key, final String valueToDigest) {
603        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
604    }
605
606    // hmacSha384
607
608    /**
609     * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
610     *
611     * @param key
612     *            The key for the keyed digest (must not be null)
613     * @param valueToDigest
614     *            The value (data) which should to digest (maybe empty or null)
615     * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase)
616     * @throws IllegalArgumentException
617     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
618     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(byte[])}
619     */
620    @Deprecated
621    public static String hmacSha384Hex(final byte[] key, final byte[] valueToDigest) {
622        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
623    }
624
625    /**
626     * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
627     *
628     * @param key
629     *            The key for the keyed digest (must not be null)
630     * @param valueToDigest
631     *            The value (data) which should to digest
632     *            <p>
633     *            The InputStream must not be null and will not be closed
634     *            </p>
635     * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase)
636     * @throws IOException
637     *             If an I/O error occurs.
638     * @throws IllegalArgumentException
639     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
640     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(InputStream)}
641     */
642    @Deprecated
643    public static String hmacSha384Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
644        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
645    }
646
647    /**
648     * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
649     *
650     * @param key
651     *            The key for the keyed digest (must not be null)
652     * @param valueToDigest
653     *            The value (data) which should to digest (maybe empty or null)
654     * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase)
655     * @throws IllegalArgumentException
656     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
657     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmacHex(String)}
658     */
659    @Deprecated
660    public static String hmacSha384Hex(final String key, final String valueToDigest) {
661        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
662    }
663
664    /**
665     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
666     *
667     * @param key
668     *            The key for the keyed digest (must not be null)
669     * @param valueToDigest
670     *            The value (data) which should to digest (maybe empty or null)
671     * @return HmacSHA512 MAC for the given key and value
672     * @throws IllegalArgumentException
673     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
674     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(byte[])}
675     */
676    @Deprecated
677    public static byte[] hmacSha512(final byte[] key, final byte[] valueToDigest) {
678        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
679    }
680
681    /**
682     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
683     *
684     * @param key
685     *            The key for the keyed digest (must not be null)
686     * @param valueToDigest
687     *            The value (data) which should to digest
688     *            <p>
689     *            The InputStream must not be null and will not be closed
690     *            </p>
691     * @return HmacSHA512 MAC for the given key and value
692     * @throws IOException
693     *             If an I/O error occurs.
694     * @throws IllegalArgumentException
695     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
696     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(InputStream)}
697     */
698    @Deprecated
699    public static byte[] hmacSha512(final byte[] key, final InputStream valueToDigest) throws IOException {
700        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
701    }
702
703    /**
704     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
705     *
706     * @param key
707     *            The key for the keyed digest (must not be null)
708     * @param valueToDigest
709     *            The value (data) which should to digest (maybe empty or null)
710     * @return HmacSHA512 MAC for the given key and value
711     * @throws IllegalArgumentException
712     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
713     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmac(String)}
714     */
715    @Deprecated
716    public static byte[] hmacSha512(final String key, final String valueToDigest) {
717        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
718    }
719
720    // hmacSha512
721
722    /**
723     * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
724     *
725     * @param key
726     *            The key for the keyed digest (must not be null)
727     * @param valueToDigest
728     *            The value (data) which should to digest (maybe empty or null)
729     * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase)
730     * @throws IllegalArgumentException
731     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
732     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(byte[])}
733     */
734    @Deprecated
735    public static String hmacSha512Hex(final byte[] key, final byte[] valueToDigest) {
736        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
737    }
738
739    /**
740     * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
741     *
742     * @param key
743     *            The key for the keyed digest (must not be null)
744     * @param valueToDigest
745     *            The value (data) which should to digest
746     *            <p>
747     *            The InputStream must not be null and will not be closed
748     *            </p>
749     * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase)
750     * @throws IOException
751     *             If an I/O error occurs.
752     * @throws IllegalArgumentException
753     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
754     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(InputStream)}
755     */
756    @Deprecated
757    public static String hmacSha512Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
758        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
759    }
760
761    /**
762     * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
763     *
764     * @param key
765     *            The key for the keyed digest (must not be null)
766     * @param valueToDigest
767     *            The value (data) which should to digest (maybe empty or null)
768     * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase)
769     * @throws IllegalArgumentException
770     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
771     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmacHex(String)}
772     */
773    @Deprecated
774    public static String hmacSha512Hex(final String key, final String valueToDigest) {
775        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
776    }
777
778    /**
779     * Returns whether this algorithm is available
780     *
781     * @param name the name to check
782     * @return whether this algorithm is available
783     * @since 1.11
784     */
785    public static boolean isAvailable(final HmacAlgorithms name) {
786        try {
787            Mac.getInstance(name.getName());
788            return true;
789        } catch (final NoSuchAlgorithmException e) {
790            return false;
791        }
792    }
793
794    /**
795     * Returns whether this algorithm is available
796     *
797     * @param name the name to check
798     * @return whether this algorithm is available
799     * @since 1.11
800     */
801    public static boolean isAvailable(final String name) {
802        try {
803            Mac.getInstance(name);
804            return true;
805        } catch (final NoSuchAlgorithmException e) {
806            return false;
807        }
808    }
809
810    /**
811     * Resets and then updates the given {@link Mac} with the value.
812     *
813     * @param mac
814     *            the initialized {@link Mac} to update
815     * @param valueToDigest
816     *            the value to update the {@link Mac} with (maybe null or empty)
817     * @return the updated {@link Mac}
818     * @throws IllegalStateException
819     *             if the Mac was not initialized
820     */
821    public static Mac updateHmac(final Mac mac, final byte[] valueToDigest) {
822        mac.reset();
823        mac.update(valueToDigest);
824        return mac;
825    }
826
827    /**
828     * Resets and then updates the given {@link Mac} with the value.
829     *
830     * @param mac
831     *            the initialized {@link Mac} to update
832     * @param valueToDigest
833     *            the value to update the {@link Mac} with
834     *            <p>
835     *            The InputStream must not be null and will not be closed
836     *            </p>
837     * @return the updated {@link Mac}
838     * @throws IOException
839     *             If an I/O error occurs.
840     * @throws IllegalStateException
841     *             If the Mac was not initialized
842     */
843    public static Mac updateHmac(final Mac mac, final InputStream valueToDigest) throws IOException {
844        mac.reset();
845        final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
846        int read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
847
848        while (read > -1) {
849            mac.update(buffer, 0, read);
850            read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
851        }
852
853        return mac;
854    }
855
856    /**
857     * Resets and then updates the given {@link Mac} with the value.
858     *
859     * @param mac
860     *            the initialized {@link Mac} to update
861     * @param valueToDigest
862     *            the value to update the {@link Mac} with (maybe null or empty)
863     * @return the updated {@link Mac}
864     * @throws IllegalStateException
865     *             if the Mac was not initialized
866     */
867    public static Mac updateHmac(final Mac mac, final String valueToDigest) {
868        mac.reset();
869        mac.update(StringUtils.getBytesUtf8(valueToDigest));
870        return mac;
871    }
872
873    private final Mac mac;
874
875    /**
876     * Preserves binary compatibility only.
877     * As for previous versions does not provide useful behavior
878     * @deprecated since 1.11; only useful to preserve binary compatibility
879     */
880    @Deprecated
881    public HmacUtils() {
882        this(null);
883    }
884
885    /**
886     * Creates an instance using the provided algorithm type.
887     *
888     * @param algorithm to use.
889     * @param key the key to use
890     * @throws IllegalArgumentException
891     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
892     * @since 1.11
893     */
894    public HmacUtils(final HmacAlgorithms algorithm, final byte[] key) {
895        this(algorithm.getName(), key);
896    }
897
898    /**
899     * Creates an instance using the provided algorithm type.
900     *
901     * @param algorithm to use
902     * @param  key the key to use
903     * @throws IllegalArgumentException
904     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
905     * @since 1.11
906     */
907    public HmacUtils(final HmacAlgorithms algorithm, final String key) {
908        this(algorithm.getName(), StringUtils.getBytesUtf8(key));
909    }
910
911    private HmacUtils(final Mac mac) {
912        this.mac = mac;
913    }
914
915    /**
916     * Creates an instance using the provided algorithm type.
917     *
918     * @param algorithm to use
919     * @param  key the key to use
920     * @throws IllegalArgumentException
921     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
922     * @since 1.11
923     */
924    public HmacUtils(final String algorithm, final byte[] key) {
925        this(getInitializedMac(algorithm, key));
926    }
927
928    /**
929     * Creates an instance using the provided algorithm type.
930     *
931     * @param algorithm to use
932     * @param  key the key to use
933     * @throws IllegalArgumentException
934     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
935     * @since 1.11
936     */
937    public HmacUtils(final String algorithm, final String key) {
938        this(algorithm, StringUtils.getBytesUtf8(key));
939    }
940
941    /**
942     * Returns the digest for the input data.
943     *
944     * @param valueToDigest the input to use
945     * @return the digest as a byte[]
946     * @since 1.11
947     */
948    public byte[] hmac(final byte[] valueToDigest) {
949        return mac.doFinal(valueToDigest);
950    }
951
952    /**
953     * Returns the digest for the input data.
954     *
955     * @param valueToDigest the input to use
956     * @return the digest as a byte[]
957     * @since 1.11
958     */
959    public byte[] hmac(final ByteBuffer valueToDigest) {
960        mac.update(valueToDigest);
961        return mac.doFinal();
962    }
963
964    /**
965     * Returns the digest for the file.
966     *
967     * @param valueToDigest the file to use
968     * @return the digest
969     * @throws IOException
970     *             If an I/O error occurs.
971     * @since 1.11
972     */
973    public byte[] hmac(final File valueToDigest) throws IOException {
974        try (final BufferedInputStream stream = new BufferedInputStream(new FileInputStream(valueToDigest))) {
975            return hmac(stream);
976        }
977    }
978
979    /**
980     * Returns the digest for the stream.
981     *
982     * @param valueToDigest
983     *            the data to use
984     *            <p>
985     *            The InputStream must not be null and will not be closed
986     *            </p>
987     * @return the digest
988     * @throws IOException
989     *             If an I/O error occurs.
990     * @since 1.11
991     */
992    public byte[] hmac(final InputStream valueToDigest) throws IOException {
993        final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
994        int read;
995
996        while ((read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH)) > -1) {
997            mac.update(buffer, 0, read);
998        }
999        return mac.doFinal();
1000    }
1001
1002    /**
1003     * Returns the digest for the input data.
1004     *
1005     * @param valueToDigest the input to use, treated as UTF-8
1006     * @return the digest as a byte[]
1007     * @since 1.11
1008     */
1009    public byte[] hmac(final String valueToDigest) {
1010        return mac.doFinal(StringUtils.getBytesUtf8(valueToDigest));
1011    }
1012
1013    /**
1014     * Returns the digest for the input data.
1015     *
1016     * @param valueToDigest the input to use
1017     * @return the digest as a hexadecimal String
1018     * @since 1.11
1019     */
1020    public String hmacHex(final byte[] valueToDigest) {
1021        return Hex.encodeHexString(hmac(valueToDigest));
1022    }
1023
1024    /**
1025     * Returns the digest for the input data.
1026     *
1027     * @param valueToDigest the input to use
1028     * @return the digest as a hexadecimal String
1029     * @since 1.11
1030     */
1031    public String hmacHex(final ByteBuffer valueToDigest) {
1032        return Hex.encodeHexString(hmac(valueToDigest));
1033    }
1034
1035    /**
1036     * Returns the digest for the file.
1037     *
1038     * @param valueToDigest the file to use
1039     * @return the digest as a hexadecimal String
1040     * @throws IOException
1041     *             If an I/O error occurs.
1042     * @since 1.11
1043     */
1044    public String hmacHex(final File valueToDigest) throws IOException {
1045        return Hex.encodeHexString(hmac(valueToDigest));
1046    }
1047
1048    /**
1049     * Returns the digest for the stream.
1050     *
1051     * @param valueToDigest
1052     *            the data to use
1053     *            <p>
1054     *            The InputStream must not be null and will not be closed
1055     *            </p>
1056     * @return the digest as a hexadecimal String
1057     * @throws IOException
1058     *             If an I/O error occurs.
1059     * @since 1.11
1060     */
1061    public String hmacHex(final InputStream valueToDigest) throws IOException {
1062        return Hex.encodeHexString(hmac(valueToDigest));
1063    }
1064
1065    /**
1066     * Returns the digest for the input data.
1067     *
1068     * @param valueToDigest the input to use, treated as UTF-8
1069     * @return the digest as a hexadecimal String
1070     * @since 1.11
1071     */
1072    public String hmacHex(final String valueToDigest) {
1073        return Hex.encodeHexString(hmac(valueToDigest));
1074    }
1075
1076}