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     * Gets 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     * Gets 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     * Gets 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     * Gets 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     * Gets 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     * Gets 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     * Gets 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              Thrown 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              Thrown 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              Thrown 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              Thrown 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     *                      The InputStream must not be null and will not be closed.
434     * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
435     * @throws IOException              Thrown if an I/O error occurs.
436     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
437     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmacHex(InputStream)}.
438     */
439    @Deprecated
440    public static String hmacSha256Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
441        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
442    }
443
444    /**
445     * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
446     *
447     * @param key           The key for the keyed digest (must not be null).
448     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
449     * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
450     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
451     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmacHex(String)}.
452     */
453    @Deprecated
454    public static String hmacSha256Hex(final String key, final String valueToDigest) {
455        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
456    }
457
458    /**
459     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
460     *
461     * @param key           The key for the keyed digest (must not be null).
462     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
463     * @return HmacSHA384 MAC for the given key and value.
464     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
465     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(byte[])}.
466     */
467    @Deprecated
468    public static byte[] hmacSha384(final byte[] key, final byte[] valueToDigest) {
469        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
470    }
471
472    /**
473     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
474     *
475     * @param key           The key for the keyed digest (must not be null).
476     * @param valueToDigest The value (data) which should to digest.
477     *                      The InputStream must not be null and will not be closed.
478     * @return HmacSHA384 MAC for the given key and value.
479     * @throws IOException              Thrown if an I/O error occurs.
480     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
481     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(InputStream)}.
482     */
483    @Deprecated
484    public static byte[] hmacSha384(final byte[] key, final InputStream valueToDigest) throws IOException {
485        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
486    }
487
488    /**
489     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
490     *
491     * @param key           The key for the keyed digest (must not be null).
492     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
493     * @return HmacSHA384 MAC for the given key and value.
494     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
495     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmac(String)}.
496     */
497    @Deprecated
498    public static byte[] hmacSha384(final String key, final String valueToDigest) {
499        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
500    }
501    // hmacSha384
502
503    /**
504     * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) 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 as hexadecimal string (lowercase).
509     * @throws IllegalArgumentException Thrown if 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, byte[]).hmacHex(byte[])}.
511     */
512    @Deprecated
513    public static String hmacSha384Hex(final byte[] key, final byte[] valueToDigest) {
514        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
515    }
516
517    /**
518     * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
519     *
520     * @param key           The key for the keyed digest (must not be null).
521     * @param valueToDigest The value (data) which should to digest.
522     *                      The InputStream must not be null and will not be closed.
523     * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
524     * @throws IOException              Thrown if an I/O error occurs.
525     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
526     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(InputStream)}.
527     */
528    @Deprecated
529    public static String hmacSha384Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
530        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
531    }
532
533    /**
534     * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
535     *
536     * @param key           The key for the keyed digest (must not be null).
537     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
538     * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
539     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
540     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmacHex(String)}.
541     */
542    @Deprecated
543    public static String hmacSha384Hex(final String key, final String valueToDigest) {
544        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
545    }
546
547    /**
548     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
549     *
550     * @param key           The key for the keyed digest (must not be null).
551     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
552     * @return HmacSHA512 MAC for the given key and value.
553     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
554     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(byte[])}.
555     */
556    @Deprecated
557    public static byte[] hmacSha512(final byte[] key, final byte[] valueToDigest) {
558        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
559    }
560
561    /**
562     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
563     *
564     * @param key           The key for the keyed digest (must not be null).
565     * @param valueToDigest The value (data) which should to digest.
566     *                      The InputStream must not be null and will not be closed.
567     * @return HmacSHA512 MAC for the given key and value.
568     * @throws IOException              Thrown if an I/O error occurs.
569     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
570     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(InputStream)}.
571     */
572    @Deprecated
573    public static byte[] hmacSha512(final byte[] key, final InputStream valueToDigest) throws IOException {
574        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
575    }
576
577    /**
578     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
579     *
580     * @param key           The key for the keyed digest (must not be null).
581     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
582     * @return HmacSHA512 MAC for the given key and value.
583     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
584     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmac(String)}.
585     */
586    @Deprecated
587    public static byte[] hmacSha512(final String key, final String valueToDigest) {
588        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
589    }
590    // hmacSha512
591
592    /**
593     * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
594     *
595     * @param key           The key for the keyed digest (must not be null).
596     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
597     * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
598     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
599     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(byte[])}.
600     */
601    @Deprecated
602    public static String hmacSha512Hex(final byte[] key, final byte[] valueToDigest) {
603        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
604    }
605
606    /**
607     * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
608     *
609     * @param key           The key for the keyed digest (must not be null).
610     * @param valueToDigest The value (data) which should to digest.
611     *                      The InputStream must not be null and will not be closed.
612     * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
613     * @throws IOException              Thrown if an I/O error occurs.
614     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
615     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(InputStream)}.
616     */
617    @Deprecated
618    public static String hmacSha512Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
619        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
620    }
621
622    /**
623     * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
624     *
625     * @param key           The key for the keyed digest (must not be null).
626     * @param valueToDigest The value (data) which should to digest (maybe empty or null).
627     * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
628     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
629     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmacHex(String)}.
630     */
631    @Deprecated
632    public static String hmacSha512Hex(final String key, final String valueToDigest) {
633        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
634    }
635
636    /**
637     * Tests whether this algorithm is available.
638     *
639     * @param hmacAlgorithms The HmacAlgorithms to check.
640     * @return whether this algorithm is available.
641     * @since 1.11
642     */
643    public static boolean isAvailable(final HmacAlgorithms hmacAlgorithms) {
644        return isAvailable(hmacAlgorithms.getName());
645    }
646
647    /**
648     * Tests whether this algorithm is available.
649     *
650     * @param name The name to check.
651     * @return whether this algorithm is available.
652     * @since 1.11
653     */
654    public static boolean isAvailable(final String name) {
655        try {
656            Mac.getInstance(name);
657            return true;
658        } catch (final NoSuchAlgorithmException e) {
659            return false;
660        }
661    }
662
663    /**
664     * Resets and then updates the given {@link Mac} with the value.
665     *
666     * @param mac           The initialized {@link Mac} to update.
667     * @param valueToDigest The value to update the {@link Mac} with (maybe null or empty).
668     * @return The updated {@link Mac}.
669     * @throws IllegalStateException Thrown if the Mac was not initialized.
670     */
671    public static Mac updateHmac(final Mac mac, final byte[] valueToDigest) {
672        mac.reset();
673        mac.update(valueToDigest);
674        return mac;
675    }
676
677    /**
678     * Resets and then updates the given {@link Mac} with the value.
679     *
680     * @param mac           The initialized {@link Mac} to update.
681     * @param valueToDigest The value to update the {@link Mac} with.
682     *                      The InputStream must not be null and will not be closed.
683     * @return The updated {@link Mac}.
684     * @throws IOException           Thrown if an I/O error occurs.
685     * @throws IllegalStateException Thrown if the Mac was not initialized.
686     */
687    public static Mac updateHmac(final Mac mac, final InputStream valueToDigest) throws IOException {
688        mac.reset();
689        final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
690        int read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
691        while (read > -1) {
692            mac.update(buffer, 0, read);
693            read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
694        }
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 (maybe null or empty).
703     * @return The updated {@link Mac}.
704     * @throws IllegalStateException Thrown if the Mac was not initialized.
705     */
706    public static Mac updateHmac(final Mac mac, final String valueToDigest) {
707        mac.reset();
708        mac.update(StringUtils.getBytesUtf8(valueToDigest));
709        return mac;
710    }
711
712    private final Mac mac;
713
714    /**
715     * Preserves binary compatibility only. As for previous versions does not provide useful behavior.
716     *
717     * @deprecated Since 1.11; only useful to preserve binary compatibility.
718     */
719    @Deprecated
720    public HmacUtils() {
721        this(null);
722    }
723
724    /**
725     * Creates an instance using the provided algorithm type.
726     *
727     * @param algorithm to use.
728     * @param key       The key to use.
729     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
730     * @since 1.11
731     */
732    public HmacUtils(final HmacAlgorithms algorithm, final byte[] key) {
733        this(algorithm.getName(), key);
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 String key) {
745        this(algorithm.getName(), StringUtils.getBytesUtf8(key));
746    }
747
748    private HmacUtils(final Mac mac) {
749        this.mac = mac;
750    }
751
752    /**
753     * Creates an instance using the provided algorithm type.
754     *
755     * @param algorithm to use.
756     * @param key       The key to use.
757     * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
758     * @since 1.11
759     */
760    public HmacUtils(final String algorithm, final byte[] key) {
761        this(getInitializedMac(algorithm, key));
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 String key) {
773        this(algorithm, StringUtils.getBytesUtf8(key));
774    }
775
776    /**
777     * Returns the digest for the input data.
778     *
779     * @param valueToDigest The input to use.
780     * @return The digest as a byte[].
781     * @since 1.11
782     */
783    public byte[] hmac(final byte[] valueToDigest) {
784        return mac.doFinal(valueToDigest);
785    }
786
787    /**
788     * Returns the digest for the input data.
789     *
790     * @param valueToDigest The input to use.
791     * @return The digest as a byte[].
792     * @since 1.11
793     */
794    public byte[] hmac(final ByteBuffer valueToDigest) {
795        mac.update(valueToDigest);
796        return mac.doFinal();
797    }
798
799    /**
800     * Returns the digest for the file.
801     *
802     * @param valueToDigest The file to use.
803     * @return The digest.
804     * @throws IOException Thrown if an I/O error occurs.
805     * @since 1.11
806     */
807    public byte[] hmac(final File valueToDigest) throws IOException {
808        return hmac(valueToDigest.toPath());
809    }
810
811    /**
812     * Returns the digest for the stream.
813     *
814     * @param valueToDigest The data to use.
815     *                      The InputStream must not be null and will not be closed.
816     * @return The digest.
817     * @throws IOException Thrown if an I/O error occurs.
818     * @since 1.11
819     */
820    public byte[] hmac(final InputStream valueToDigest) throws IOException {
821        final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
822        int read;
823        while ((read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH)) > -1) {
824            mac.update(buffer, 0, read);
825        }
826        return mac.doFinal();
827    }
828
829    /**
830     * Returns the digest for the file.
831     *
832     * @param valueToDigest The path to use.
833     * @return The digest.
834     * @throws IOException Thrown if an I/O error occurs.
835     * @since 1.19.0
836     */
837    public byte[] hmac(final Path valueToDigest) throws IOException {
838        try (BufferedInputStream stream = new BufferedInputStream(Files.newInputStream(valueToDigest))) {
839            return hmac(stream);
840        }
841    }
842
843    /**
844     * Returns the digest for the input data.
845     *
846     * @param valueToDigest The input to use, treated as UTF-8.
847     * @return The digest as a byte[].
848     * @since 1.11
849     */
850    public byte[] hmac(final String valueToDigest) {
851        return mac.doFinal(StringUtils.getBytesUtf8(valueToDigest));
852    }
853
854    /**
855     * Returns the digest for the input data.
856     *
857     * @param valueToDigest The input to use.
858     * @return The digest as a hexadecimal String.
859     * @since 1.11
860     */
861    public String hmacHex(final byte[] valueToDigest) {
862        return Hex.encodeHexString(hmac(valueToDigest));
863    }
864
865    /**
866     * Returns the digest for the input data.
867     *
868     * @param valueToDigest The input to use.
869     * @return The digest as a hexadecimal String.
870     * @since 1.11
871     */
872    public String hmacHex(final ByteBuffer valueToDigest) {
873        return Hex.encodeHexString(hmac(valueToDigest));
874    }
875
876    /**
877     * Returns the digest for the file.
878     *
879     * @param valueToDigest The file to use.
880     * @return The digest as a hexadecimal String.
881     * @throws IOException Thrown if an I/O error occurs.
882     * @since 1.11
883     */
884    public String hmacHex(final File valueToDigest) throws IOException {
885        return Hex.encodeHexString(hmac(valueToDigest));
886    }
887
888    /**
889     * Returns the digest for the stream.
890     *
891     * @param valueToDigest The data to use.
892     *                      The InputStream must not be null and will not be closed.
893     * @return The digest as a hexadecimal String.
894     * @throws IOException Thrown if an I/O error occurs.
895     * @since 1.11
896     */
897    public String hmacHex(final InputStream valueToDigest) throws IOException {
898        return Hex.encodeHexString(hmac(valueToDigest));
899    }
900
901    /**
902     * Returns the digest for the path.
903     *
904     * @param valueToDigest The path to use.
905     * @return The digest as a hexadecimal String.
906     * @throws IOException Thrown if an I/O error occurs.
907     * @since 1.19.0
908     */
909    public String hmacHex(final Path valueToDigest) throws IOException {
910        return Hex.encodeHexString(hmac(valueToDigest));
911    }
912
913    /**
914     * Returns the digest for the input data.
915     *
916     * @param valueToDigest The input to use, treated as UTF-8.
917     * @return The digest as a hexadecimal String.
918     * @since 1.11
919     */
920    public String hmacHex(final String valueToDigest) {
921        return Hex.encodeHexString(hmac(valueToDigest));
922    }
923}