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