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. 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 re-use
052 * HmacUtils hm1 = new HmacUtils("HmacAlgoName", key); // use a valid name here!
053 * String hexPom = hm1.hmacHex(new File("pom.xml"));
054 * String hexNot = hm1.hmacHex(new File("NOTICE.txt"));
055 * </pre>
056 *
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 The key for the keyed digest (must not be null).
070     * @return A Mac instance initialized with the given key.
071     * @throws IllegalArgumentException when 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 {@code 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 when 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 {@code 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 when 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 {@code 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 when 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 {@code 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 when 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 {@code 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 when 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 {@code 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 when 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 when 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     *                      <p>
215     *                      The InputStream must not be null and will not be closed.
216     *                      </p>
217     * @return HmacMD5 MAC for the given key and value.
218     * @throws IOException              If an I/O error occurs.
219     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
220     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmac(InputStream)}.
221     */
222    @Deprecated
223    public static byte[] hmacMd5(final byte[] key, final InputStream valueToDigest) throws IOException {
224        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
225    }
226
227    /**
228     * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
229     *
230     * @param key           The key for the keyed digest (must not be null).
231     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
232     * @return HmacMD5 MAC for the given key and value.
233     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
234     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, String).hmac(String)}.
235     */
236    @Deprecated
237    public static byte[] hmacMd5(final String key, final String valueToDigest) {
238        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
239    }
240
241    /**
242     * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
243     *
244     * @param key           The key for the keyed digest (must not be null).
245     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
246     * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase).
247     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
248     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmacHex(byte[])}.
249     */
250    @Deprecated
251    public static String hmacMd5Hex(final byte[] key, final byte[] valueToDigest) {
252        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
253    }
254
255    /**
256     * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
257     *
258     * @param key           The key for the keyed digest (must not be null).
259     * @param valueToDigest The value (data) which should to digest
260     *                      <p>
261     *                      The InputStream must not be null and will not be closed.
262     *                      </p>
263     * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase).
264     * @throws IOException              If an I/O error occurs.
265     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
266     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmacHex(InputStream)}.
267     */
268    @Deprecated
269    public static String hmacMd5Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
270        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
271    }
272
273    /**
274     * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
275     *
276     * @param key           The key for the keyed digest (must not be null).
277     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
278     * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase).
279     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
280     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, String).hmacHex(String)}.
281     */
282    @Deprecated
283    public static String hmacMd5Hex(final String key, final String valueToDigest) {
284        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
285    }
286
287    /**
288     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
289     *
290     * @param key           The key for the keyed digest (must not be null).
291     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
292     * @return HmacSHA1 MAC for the given key and value.
293     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
294     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmac(byte[])}.
295     */
296    @Deprecated
297    public static byte[] hmacSha1(final byte[] key, final byte[] valueToDigest) {
298        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
299    }
300
301    /**
302     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
303     *
304     * @param key           The key for the keyed digest (must not be null).
305     * @param valueToDigest The value (data) which should to digest
306     *                      <p>
307     *                      The InputStream must not be null and will not be closed.
308     *                      </p>
309     * @return HmacSHA1 MAC for the given key and value.
310     * @throws IOException              If an I/O error occurs.
311     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
312     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmac(InputStream)}.
313     */
314    @Deprecated
315    public static byte[] hmacSha1(final byte[] key, final InputStream valueToDigest) throws IOException {
316        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
317    }
318
319    /**
320     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
321     *
322     * @param key           The key for the keyed digest (must not be null).
323     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
324     * @return HmacSHA1 MAC for the given key and value.
325     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
326     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, String).hmac(String)}.
327     */
328    @Deprecated
329    public static byte[] hmacSha1(final String key, final String valueToDigest) {
330        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
331    }
332
333    /**
334     * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
335     *
336     * @param key           The key for the keyed digest (must not be null).
337     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
338     * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase).
339     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
340     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmacHex(byte[])}
341     */
342    @Deprecated
343    public static String hmacSha1Hex(final byte[] key, final byte[] valueToDigest) {
344        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
345    }
346
347    /**
348     * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
349     *
350     * @param key           The key for the keyed digest (must not be null).
351     * @param valueToDigest The value (data) which should to digest.
352     *                      <p>
353     *                      The InputStream must not be null and will not be closed.
354     *                      </p>
355     * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase).
356     * @throws IOException              If an I/O error occurs.
357     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
358     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmacHex(InputStream)}.
359     */
360    @Deprecated
361    public static String hmacSha1Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
362        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
363    }
364
365    /**
366     * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
367     *
368     * @param key           The key for the keyed digest (must not be null).
369     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
370     * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase).
371     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
372     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, String).hmacHex(String)}.
373     */
374    @Deprecated
375    public static String hmacSha1Hex(final String key, final String valueToDigest) {
376        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
377    }
378
379    /**
380     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
381     *
382     * @param key           The key for the keyed digest (must not be null).
383     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
384     * @return HmacSHA256 MAC for the given key and value.
385     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
386     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmac(byte[])}.
387     */
388    @Deprecated
389    public static byte[] hmacSha256(final byte[] key, final byte[] valueToDigest) {
390        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
391    }
392
393    /**
394     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
395     *
396     * @param key           The key for the keyed digest (must not be null).
397     * @param valueToDigest The value (data) which should to digest.
398     *                      <p>
399     *                      The InputStream must not be null and will not be closed.
400     *                      </p>
401     * @return HmacSHA256 MAC for the given key and value.
402     * @throws IOException              If an I/O error occurs.
403     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
404     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmac(InputStream)}.
405     */
406    @Deprecated
407    public static byte[] hmacSha256(final byte[] key, final InputStream valueToDigest) throws IOException {
408        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
409    }
410
411    /**
412     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
413     *
414     * @param key           The key for the keyed digest (must not be null).
415     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
416     * @return HmacSHA256 MAC for the given key and value.
417     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
418     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmac(String)}.
419     */
420    @Deprecated
421    public static byte[] hmacSha256(final String key, final String valueToDigest) {
422        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
423    }
424
425    /**
426     * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
427     *
428     * @param key           The key for the keyed digest (must not be null).
429     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
430     * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
431     * @throws IllegalArgumentException 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_256, byte[]).hmacHex(byte[])}.
433     */
434    @Deprecated
435    public static String hmacSha256Hex(final byte[] key, final byte[] valueToDigest) {
436        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
437    }
438
439    /**
440     * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
441     *
442     * @param key           The key for the keyed digest (must not be null).
443     * @param valueToDigest The value (data) which should to digest.
444     *                      <p>
445     *                      The InputStream must not be null and will not be closed.
446     *                      </p>
447     * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
448     * @throws IOException              If an I/O error occurs.
449     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
450     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmacHex(InputStream)}.
451     */
452    @Deprecated
453    public static String hmacSha256Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
454        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
455    }
456
457    /**
458     * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
459     *
460     * @param key           The key for the keyed digest (must not be null).
461     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
462     * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
463     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
464     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmacHex(String)}.
465     */
466    @Deprecated
467    public static String hmacSha256Hex(final String key, final String valueToDigest) {
468        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
469    }
470
471    /**
472     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
473     *
474     * @param key           The key for the keyed digest (must not be null).
475     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
476     * @return HmacSHA384 MAC for the given key and value.
477     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
478     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(byte[])}.
479     */
480    @Deprecated
481    public static byte[] hmacSha384(final byte[] key, final byte[] valueToDigest) {
482        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
483    }
484
485    /**
486     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
487     *
488     * @param key           The key for the keyed digest (must not be null).
489     * @param valueToDigest The value (data) which should to digest.
490     *                      <p>
491     *                      The InputStream must not be null and will not be closed.
492     *                      </p>
493     * @return HmacSHA384 MAC for the given key and value.
494     * @throws IOException              If an I/O error occurs.
495     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
496     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(InputStream)}.
497     */
498    @Deprecated
499    public static byte[] hmacSha384(final byte[] key, final InputStream valueToDigest) throws IOException {
500        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
501    }
502
503    /**
504     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
505     *
506     * @param key           The key for the keyed digest (must not be null).
507     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
508     * @return HmacSHA384 MAC for the given key and value.
509     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
510     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmac(String)}.
511     */
512    @Deprecated
513    public static byte[] hmacSha384(final String key, final String valueToDigest) {
514        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
515    }
516    // hmacSha384
517
518    /**
519     * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
520     *
521     * @param key           The key for the keyed digest (must not be null).
522     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
523     * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
524     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
525     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(byte[])}.
526     */
527    @Deprecated
528    public static String hmacSha384Hex(final byte[] key, final byte[] valueToDigest) {
529        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
530    }
531
532    /**
533     * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
534     *
535     * @param key           The key for the keyed digest (must not be null).
536     * @param valueToDigest The value (data) which should to digest.
537     *                      <p>
538     *                      The InputStream must not be null and will not be closed.
539     *                      </p>
540     * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
541     * @throws IOException              If an I/O error occurs.
542     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
543     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(InputStream)}.
544     */
545    @Deprecated
546    public static String hmacSha384Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
547        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
548    }
549
550    /**
551     * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
552     *
553     * @param key           The key for the keyed digest (must not be null).
554     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
555     * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
556     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
557     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmacHex(String)}.
558     */
559    @Deprecated
560    public static String hmacSha384Hex(final String key, final String valueToDigest) {
561        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
562    }
563
564    /**
565     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
566     *
567     * @param key           The key for the keyed digest (must not be null).
568     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
569     * @return HmacSHA512 MAC for the given key and value.
570     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
571     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(byte[])}.
572     */
573    @Deprecated
574    public static byte[] hmacSha512(final byte[] key, final byte[] valueToDigest) {
575        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
576    }
577
578    /**
579     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
580     *
581     * @param key           The key for the keyed digest (must not be null).
582     * @param valueToDigest The value (data) which should to digest.
583     *                      <p>
584     *                      The InputStream must not be null and will not be closed.
585     *                      </p>
586     * @return HmacSHA512 MAC for the given key and value.
587     * @throws IOException              If an I/O error occurs.
588     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
589     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(InputStream)}.
590     */
591    @Deprecated
592    public static byte[] hmacSha512(final byte[] key, final InputStream valueToDigest) throws IOException {
593        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
594    }
595
596    /**
597     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
598     *
599     * @param key           The key for the keyed digest (must not be null).
600     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
601     * @return HmacSHA512 MAC for the given key and value.
602     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
603     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmac(String)}.
604     */
605    @Deprecated
606    public static byte[] hmacSha512(final String key, final String valueToDigest) {
607        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
608    }
609    // hmacSha512
610
611    /**
612     * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
613     *
614     * @param key           The key for the keyed digest (must not be null).
615     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
616     * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
617     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
618     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(byte[])}.
619     */
620    @Deprecated
621    public static String hmacSha512Hex(final byte[] key, final byte[] valueToDigest) {
622        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
623    }
624
625    /**
626     * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
627     *
628     * @param key           The key for the keyed digest (must not be null).
629     * @param valueToDigest The value (data) which should to digest.
630     *                      <p>
631     *                      The InputStream must not be null and will not be closed.
632     *                      </p>
633     * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
634     * @throws IOException              If an I/O error occurs.
635     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
636     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(InputStream)}.
637     */
638    @Deprecated
639    public static String hmacSha512Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
640        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
641    }
642
643    /**
644     * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
645     *
646     * @param key           The key for the keyed digest (must not be null).
647     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
648     * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
649     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
650     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmacHex(String)}.
651     */
652    @Deprecated
653    public static String hmacSha512Hex(final String key, final String valueToDigest) {
654        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
655    }
656
657    /**
658     * Tests whether this algorithm is available
659     *
660     * @param hmacAlgorithms the HmacAlgorithms to check.
661     * @return whether this algorithm is available.
662     * @since 1.11
663     */
664    public static boolean isAvailable(final HmacAlgorithms hmacAlgorithms) {
665        return isAvailable(hmacAlgorithms.getName());
666    }
667
668    /**
669     * Tests whether this algorithm is available
670     *
671     * @param name the name to check.
672     * @return whether this algorithm is available.
673     * @since 1.11
674     */
675    public static boolean isAvailable(final String name) {
676        try {
677            Mac.getInstance(name);
678            return true;
679        } catch (final NoSuchAlgorithmException e) {
680            return false;
681        }
682    }
683
684    /**
685     * Resets and then updates the given {@link Mac} with the value.
686     *
687     * @param mac           the initialized {@link Mac} to update.
688     * @param valueToDigest the value to update the {@link Mac} with (maybe null or empty).
689     * @return the updated {@link Mac}.
690     * @throws IllegalStateException if the Mac was not initialized.
691     */
692    public static Mac updateHmac(final Mac mac, final byte[] valueToDigest) {
693        mac.reset();
694        mac.update(valueToDigest);
695        return mac;
696    }
697
698    /**
699     * Resets and then updates the given {@link Mac} with the value.
700     *
701     * @param mac           the initialized {@link Mac} to update.
702     * @param valueToDigest the value to update the {@link Mac} with.
703     *                      <p>
704     *                      The InputStream must not be null and will not be closed.
705     *                      </p>
706     * @return the updated {@link Mac}.
707     * @throws IOException           If an I/O error occurs.
708     * @throws IllegalStateException If the Mac was not initialized.
709     */
710    public static Mac updateHmac(final Mac mac, final InputStream valueToDigest) throws IOException {
711        mac.reset();
712        final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
713        int read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
714        while (read > -1) {
715            mac.update(buffer, 0, read);
716            read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
717        }
718        return mac;
719    }
720
721    /**
722     * Resets and then updates the given {@link Mac} with the value.
723     *
724     * @param mac           the initialized {@link Mac} to update.
725     * @param valueToDigest the value to update the {@link Mac} with (maybe null or empty).
726     * @return the updated {@link Mac}.
727     * @throws IllegalStateException if the Mac was not initialized.
728     */
729    public static Mac updateHmac(final Mac mac, final String valueToDigest) {
730        mac.reset();
731        mac.update(StringUtils.getBytesUtf8(valueToDigest));
732        return mac;
733    }
734
735    private final Mac mac;
736
737    /**
738     * Preserves binary compatibility only. As for previous versions does not provide useful behavior.
739     *
740     * @deprecated Since 1.11; only useful to preserve binary compatibility.
741     */
742    @Deprecated
743    public HmacUtils() {
744        this(null);
745    }
746
747    /**
748     * Creates an instance using the provided algorithm type.
749     *
750     * @param algorithm to use.
751     * @param key       the key to use.
752     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
753     * @since 1.11
754     */
755    public HmacUtils(final HmacAlgorithms algorithm, final byte[] key) {
756        this(algorithm.getName(), key);
757    }
758
759    /**
760     * Creates an instance using the provided algorithm type.
761     *
762     * @param algorithm to use.
763     * @param key       the key to use.
764     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
765     * @since 1.11
766     */
767    public HmacUtils(final HmacAlgorithms algorithm, final String key) {
768        this(algorithm.getName(), StringUtils.getBytesUtf8(key));
769    }
770
771    private HmacUtils(final Mac mac) {
772        this.mac = mac;
773    }
774
775    /**
776     * Creates an instance using the provided algorithm type.
777     *
778     * @param algorithm to use.
779     * @param key       the key to use.
780     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
781     * @since 1.11
782     */
783    public HmacUtils(final String algorithm, final byte[] key) {
784        this(getInitializedMac(algorithm, key));
785    }
786
787    /**
788     * Creates an instance using the provided algorithm type.
789     *
790     * @param algorithm to use.
791     * @param key       the key to use.
792     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
793     * @since 1.11
794     */
795    public HmacUtils(final String algorithm, final String key) {
796        this(algorithm, StringUtils.getBytesUtf8(key));
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 byte[] valueToDigest) {
807        return mac.doFinal(valueToDigest);
808    }
809
810    /**
811     * Returns the digest for the input data.
812     *
813     * @param valueToDigest the input to use.
814     * @return the digest as a byte[].
815     * @since 1.11
816     */
817    public byte[] hmac(final ByteBuffer valueToDigest) {
818        mac.update(valueToDigest);
819        return mac.doFinal();
820    }
821
822    /**
823     * Returns the digest for the file.
824     *
825     * @param valueToDigest the file to use.
826     * @return the digest.
827     * @throws IOException If an I/O error occurs.
828     * @since 1.11
829     */
830    public byte[] hmac(final File valueToDigest) throws IOException {
831        return hmac(valueToDigest.toPath());
832    }
833
834    /**
835     * Returns the digest for the stream.
836     *
837     * @param valueToDigest the data to use.
838     *                      <p>
839     *                      The InputStream must not be null and will not be closed.
840     *                      </p>
841     * @return the digest.
842     * @throws IOException If an I/O error occurs.
843     * @since 1.11
844     */
845    public byte[] hmac(final InputStream valueToDigest) throws IOException {
846        final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
847        int read;
848        while ((read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH)) > -1) {
849            mac.update(buffer, 0, read);
850        }
851        return mac.doFinal();
852    }
853
854    /**
855     * Returns the digest for the file.
856     *
857     * @param valueToDigest the path to use.
858     * @return the digest.
859     * @throws IOException If an I/O error occurs.
860     * @since 1.19.0
861     */
862    public byte[] hmac(final Path valueToDigest) throws IOException {
863        try (BufferedInputStream stream = new BufferedInputStream(Files.newInputStream(valueToDigest))) {
864            return hmac(stream);
865        }
866    }
867
868    /**
869     * Returns the digest for the input data.
870     *
871     * @param valueToDigest the input to use, treated as UTF-8.
872     * @return the digest as a byte[].
873     * @since 1.11
874     */
875    public byte[] hmac(final String valueToDigest) {
876        return mac.doFinal(StringUtils.getBytesUtf8(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 byte[] valueToDigest) {
887        return Hex.encodeHexString(hmac(valueToDigest));
888    }
889
890    /**
891     * Returns the digest for the input data.
892     *
893     * @param valueToDigest the input to use.
894     * @return the digest as a hexadecimal String.
895     * @since 1.11
896     */
897    public String hmacHex(final ByteBuffer valueToDigest) {
898        return Hex.encodeHexString(hmac(valueToDigest));
899    }
900
901    /**
902     * Returns the digest for the file.
903     *
904     * @param valueToDigest the file to use.
905     * @return the digest as a hexadecimal String.
906     * @throws IOException If an I/O error occurs.
907     * @since 1.11
908     */
909    public String hmacHex(final File valueToDigest) throws IOException {
910        return Hex.encodeHexString(hmac(valueToDigest));
911    }
912
913    /**
914     * Returns the digest for the stream.
915     *
916     * @param valueToDigest the data to use.
917     *                      <p>
918     *                      The InputStream must not be null and will not be closed.
919     *                      </p>
920     * @return the digest as a hexadecimal String.
921     * @throws IOException If an I/O error occurs.
922     * @since 1.11
923     */
924    public String hmacHex(final InputStream valueToDigest) throws IOException {
925        return Hex.encodeHexString(hmac(valueToDigest));
926    }
927
928    /**
929     * Returns the digest for the path.
930     *
931     * @param valueToDigest the path to use.
932     * @return the digest as a hexadecimal String.
933     * @throws IOException If an I/O error occurs.
934     * @since 1.19.0
935     */
936    public String hmacHex(final Path valueToDigest) throws IOException {
937        return Hex.encodeHexString(hmac(valueToDigest));
938    }
939
940    /**
941     * Returns the digest for the input data.
942     *
943     * @param valueToDigest the input to use, treated as UTF-8.
944     * @return the digest as a hexadecimal String.
945     * @since 1.11
946     */
947    public String hmacHex(final String valueToDigest) {
948        return Hex.encodeHexString(hmac(valueToDigest));
949    }
950}