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